Compare commits
917 Commits
mitreid-co
...
master
Author | SHA1 | Date |
---|---|---|
![]() |
d074573de0 | |
![]() |
5e87fa7650 | |
![]() |
7e85d2575e | |
![]() |
05fd73e643 | |
![]() |
2c41e6a267 | |
![]() |
8a58d12600 | |
![]() |
f5df762153 | |
![]() |
a0bd2c70ac | |
![]() |
6906f616e2 | |
![]() |
7eba3c12fe | |
![]() |
0d4ef2cb4f | |
![]() |
cc6bd4b590 | |
![]() |
621e86e62d | |
![]() |
73459f0348 | |
![]() |
5aa8b2a0a7 | |
![]() |
ae7debba2f | |
![]() |
ad64aef0c5 | |
![]() |
703c341308 | |
![]() |
8430b42ab3 | |
![]() |
4979f9f50e | |
![]() |
a2e8cb1a67 | |
![]() |
676451c73d | |
![]() |
04f439ec58 | |
![]() |
aa2dc78148 | |
![]() |
f56918982a | |
![]() |
69afba59cc | |
![]() |
802e40ebc9 | |
![]() |
ea6960e66a | |
![]() |
9d6f42b141 | |
![]() |
dd922b4cf7 | |
![]() |
938d7e00c2 | |
![]() |
a596cc1fd4 | |
![]() |
7ad29ae9c6 | |
![]() |
e3cfb80c33 | |
![]() |
fd938e11e9 | |
![]() |
dae674af67 | |
![]() |
67c87d56a6 | |
![]() |
4a818c7b4b | |
![]() |
fe000d91cb | |
![]() |
011bf8adb8 | |
![]() |
0ee4ee2f58 | |
![]() |
0b531a0fd3 | |
![]() |
e6a8e0c17d | |
![]() |
a070f61edf | |
![]() |
51b580aa18 | |
![]() |
3f277047e3 | |
![]() |
417a6b7c74 | |
![]() |
bf8149605a | |
![]() |
64fbee7935 | |
![]() |
bca388d740 | |
![]() |
e2d94f422a | |
![]() |
a5a16f27c7 | |
![]() |
4dd907ea16 | |
![]() |
d119559d4d | |
![]() |
b804f22bc8 | |
![]() |
f72e6b3e08 | |
![]() |
1feb0958bd | |
![]() |
6497af40e8 | |
![]() |
7dc309c5af | |
![]() |
7f956a5854 | |
![]() |
37fba622b9 | |
![]() |
c38b9d7a42 | |
![]() |
36ec1b82e6 | |
![]() |
fcb119ff6a | |
![]() |
8fb9adefc1 | |
![]() |
0ce55d079a | |
![]() |
f7da25fbe8 | |
![]() |
1c7b9d5b44 | |
![]() |
a1a45aa36a | |
![]() |
01eb1401a3 | |
![]() |
e6130872a9 | |
![]() |
ca3642b6c3 | |
![]() |
85246d2d3e | |
![]() |
ce9bf3507f | |
![]() |
9bff58085d | |
![]() |
514dcc3851 | |
![]() |
8b4e461748 | |
![]() |
ef01d3032e | |
![]() |
bba18fd118 | |
![]() |
28ad78e9f3 | |
![]() |
059e140164 | |
![]() |
0b1f9000db | |
![]() |
705ac9879c | |
![]() |
4dc31cdfbd | |
![]() |
661c242a9f | |
![]() |
0859a5d122 | |
![]() |
c11e47a75b | |
![]() |
2f31ceddf8 | |
![]() |
7e6864ff38 | |
![]() |
a316306f33 | |
![]() |
7b06d91700 | |
![]() |
8301f35e17 | |
![]() |
f17a44e9b4 | |
![]() |
90c3c396ee | |
![]() |
713e872b8a | |
![]() |
9baacc0eaf | |
![]() |
2aa12fc0e3 | |
![]() |
0c46e7cb7a | |
![]() |
e6679b6e4b | |
![]() |
0efa77b580 | |
![]() |
b9b7bf53c3 | |
![]() |
0aedfc8e22 | |
![]() |
0d564d9714 | |
![]() |
11f3cccab9 | |
![]() |
702a775881 | |
![]() |
45ea899de8 | |
![]() |
d317cf5024 | |
![]() |
cc0622edd0 | |
![]() |
52829d4adb | |
![]() |
903168a949 | |
![]() |
6216659cd6 | |
![]() |
9d1a50d17e | |
![]() |
2aecedfb3d | |
![]() |
f43ff53683 | |
![]() |
bf49cd193d | |
![]() |
835a326627 | |
![]() |
1d7fba5d6e | |
![]() |
2ea5f8fd28 | |
![]() |
050662dd5c | |
![]() |
7767c7a831 | |
![]() |
7a225e56c4 | |
![]() |
78b9b6ced4 | |
![]() |
bd72b4138d | |
![]() |
32ce21b5cd | |
![]() |
b6cf8fe22b | |
![]() |
dd0f69ba6d | |
![]() |
80358566a5 | |
![]() |
4da1e619a0 | |
![]() |
eb1ec0979d | |
![]() |
9b2177a422 | |
![]() |
fd8f628a4f | |
![]() |
c377e411e3 | |
![]() |
2a75535dce | |
![]() |
a926a8f0ab | |
![]() |
256b79ae51 | |
![]() |
626b18d5ca | |
![]() |
02928b048f | |
![]() |
e57ea488b3 | |
![]() |
22a4addfc0 | |
![]() |
8406a89fd1 | |
![]() |
f0c8b1b235 | |
![]() |
f54d44cd9d | |
![]() |
f915196c2e | |
![]() |
cbf5bf742b | |
![]() |
153776ecb5 | |
![]() |
d83fbc6c67 | |
![]() |
44b24af466 | |
![]() |
04dd67d073 | |
![]() |
548dad4e29 | |
![]() |
9cb5377ce8 | |
![]() |
a5b4115169 | |
![]() |
3326eee934 | |
![]() |
c42fe57367 | |
![]() |
72fd3c2b99 | |
![]() |
837cce786a | |
![]() |
3e5e7a0f0b | |
![]() |
0d84db49af | |
![]() |
1cb5b6c6ff | |
![]() |
e1ae8f3d8d | |
![]() |
f056eb9387 | |
![]() |
98a4d56cdd | |
![]() |
00ecd3dd22 | |
![]() |
141f4da7f1 | |
![]() |
650429a2de | |
![]() |
40b4dfa5fe | |
![]() |
26c34c70de | |
![]() |
9592c784d1 | |
![]() |
f2173907ac | |
![]() |
503d6f5725 | |
![]() |
5af98e1106 | |
![]() |
00c4ea9199 | |
![]() |
c79b6da9d9 | |
![]() |
606dd2633b | |
![]() |
907f94e0ce | |
![]() |
b176d4d77e | |
![]() |
8178af87f0 | |
![]() |
3acb71763a | |
![]() |
52d2298f99 | |
![]() |
777b7a2112 | |
![]() |
76c7bef0d6 | |
![]() |
01b798151d | |
![]() |
db50a88fe5 | |
![]() |
d92cc4d488 | |
![]() |
b17a7f43ae | |
![]() |
524794fe2e | |
![]() |
bdaf7cba23 | |
![]() |
46046b574a | |
![]() |
099211593c | |
![]() |
ffc5782810 | |
![]() |
0c09a17f59 | |
![]() |
93deef952f | |
![]() |
99d1b0cfec | |
![]() |
0c821fcb51 | |
![]() |
5993c879a6 | |
![]() |
0dd7eef428 | |
![]() |
d862ba9fd8 | |
![]() |
9b715f9632 | |
![]() |
0d162b1423 | |
![]() |
71bb8d6439 | |
![]() |
fc91043807 | |
![]() |
d5e8dd31a8 | |
![]() |
0e703ef9f9 | |
![]() |
275c1b7e1c | |
![]() |
bea3af2470 | |
![]() |
63bd8d18fb | |
![]() |
91da3935f5 | |
![]() |
91ed758ed1 | |
![]() |
4f4c8de1c8 | |
![]() |
375a5f2e47 | |
![]() |
22fa3605ef | |
![]() |
55b1b00b73 | |
![]() |
d875d52be7 | |
![]() |
7725fcfa2b | |
![]() |
c3d0c18af5 | |
![]() |
f45a6ef56a | |
![]() |
476ec872ff | |
![]() |
bb6bb81dbc | |
![]() |
52da5e769a | |
![]() |
d361f01999 | |
![]() |
b2fab9642e | |
![]() |
4ac3916db3 | |
![]() |
8333d035b4 | |
![]() |
fa122e7ad6 | |
![]() |
4b3284ffd2 | |
![]() |
83a9fef14d | |
![]() |
dea6044e77 | |
![]() |
1b7612a26d | |
![]() |
cbe6b9e1df | |
![]() |
6f5ca3fd2f | |
![]() |
337513a559 | |
![]() |
74d34ab744 | |
![]() |
d0056ae882 | |
![]() |
74f3e2d0c0 | |
![]() |
af7c1f7d45 | |
![]() |
82c313f036 | |
![]() |
ba0d0aab0b | |
![]() |
ac0cafe7b3 | |
![]() |
5dcda2812e | |
![]() |
2cc90ba5f2 | |
![]() |
83d7627ed0 | |
![]() |
d1d05e506e | |
![]() |
57208ac35d | |
![]() |
d89257380f | |
![]() |
f9e4d75a4a | |
![]() |
42ccb8b39e | |
![]() |
bd9932d56f | |
![]() |
8c021ad403 | |
![]() |
8e016a8d30 | |
![]() |
a5a12b2f1f | |
![]() |
fa63993896 | |
![]() |
17be89fe98 | |
![]() |
6e8a728c68 | |
![]() |
1366db3b48 | |
![]() |
838fcb6789 | |
![]() |
241bc0f649 | |
![]() |
055b5cc4da | |
![]() |
cdf5147706 | |
![]() |
40863f4696 | |
![]() |
bba0b2fcd2 | |
![]() |
ed7536837b | |
![]() |
e073df614f | |
![]() |
d79bbaf430 | |
![]() |
8749e1124e | |
![]() |
44313c4e10 | |
![]() |
93be6b59b8 | |
![]() |
efc1c3c8bd | |
![]() |
ee537c404b | |
![]() |
a951a22bf8 | |
![]() |
b8cc0a82b3 | |
![]() |
805b6d1a7a | |
![]() |
928ed980fd | |
![]() |
66667b95bc | |
![]() |
0153ff9cb8 | |
![]() |
55b54c53b3 | |
![]() |
4884b167f2 | |
![]() |
7177854416 | |
![]() |
39bae3a160 | |
![]() |
01892b6f47 | |
![]() |
ca6e867df6 | |
![]() |
ecb4a9ed53 | |
![]() |
6fb26856a7 | |
![]() |
c96be134da | |
![]() |
a8adcb1f6b | |
![]() |
8e71107f9b | |
![]() |
8f81278332 | |
![]() |
fa4722cdd8 | |
![]() |
e08b7f89fc | |
![]() |
f21c374e8a | |
![]() |
832f5c0199 | |
![]() |
2d495bd0bd | |
![]() |
c31f42c3f3 | |
![]() |
326ce4cb6f | |
![]() |
58724aa6dc | |
![]() |
29c9ee2c46 | |
![]() |
37bead1404 | |
![]() |
2d2cf57125 | |
![]() |
37b9acda66 | |
![]() |
89316cbab1 | |
![]() |
9691f02772 | |
![]() |
49a8848648 | |
![]() |
60faf96e00 | |
![]() |
26d507d635 | |
![]() |
d75bba218d | |
![]() |
52061ff05a | |
![]() |
3a0fd9141f | |
![]() |
699e9bff39 | |
![]() |
38710bd3d2 | |
![]() |
74ea42851b | |
![]() |
028265faa6 | |
![]() |
5bccb602d8 | |
![]() |
fa4ed7ea06 | |
![]() |
51e3513307 | |
![]() |
84ff2f5fb9 | |
![]() |
fd452bf379 | |
![]() |
d0d6ae2ad8 | |
![]() |
7f5b70e9e1 | |
![]() |
0781592357 | |
![]() |
cf70a20069 | |
![]() |
cebf0fb8b2 | |
![]() |
fc38a9f65d | |
![]() |
65e5476c66 | |
![]() |
659646ba9a | |
![]() |
183a599126 | |
![]() |
f27df01ccc | |
![]() |
61433cc23a | |
![]() |
193d3f8ec6 | |
![]() |
002767ec8a | |
![]() |
8168acf04b | |
![]() |
26483b22a9 | |
![]() |
c386f0d7c1 | |
![]() |
82a1e49e79 | |
![]() |
e6684fb7a8 | |
![]() |
3d14b0d128 | |
![]() |
7badfe1d17 | |
![]() |
b691cd198a | |
![]() |
d74ba2cd04 | |
![]() |
d1033b693f | |
![]() |
43509b7dfb | |
![]() |
099ae41607 | |
![]() |
e828f3f18d | |
![]() |
01ca5ef8e2 | |
![]() |
8294dbedd5 | |
![]() |
b3486c31a0 | |
![]() |
d338352cc8 | |
![]() |
aa878cc3cf | |
![]() |
105d5d9e3d | |
![]() |
698feb49cd | |
![]() |
e1800b5fd6 | |
![]() |
616220e048 | |
![]() |
7f464c496b | |
![]() |
be9d8948ef | |
![]() |
d120e8fb20 | |
![]() |
1596b6b9e7 | |
![]() |
ea77bf2a19 | |
![]() |
9ffe877766 | |
![]() |
1ed3e2c47a | |
![]() |
fcfc620d51 | |
![]() |
c59f722cc2 | |
![]() |
2496dc114c | |
![]() |
e255fc1a10 | |
![]() |
70751a3d4a | |
![]() |
7b34a666d9 | |
![]() |
a80953a2d4 | |
![]() |
dce80d488b | |
![]() |
f27673a5f5 | |
![]() |
4f9ea0b474 | |
![]() |
6d2b73a7ef | |
![]() |
4c1e6866ce | |
![]() |
a3d01727f9 | |
![]() |
abff7421c1 | |
![]() |
5f24685f17 | |
![]() |
f04face41e | |
![]() |
2deec98b58 | |
![]() |
d96b2dc130 | |
![]() |
6129cfa61a | |
![]() |
96f4d5e8a8 | |
![]() |
a5701f4ea3 | |
![]() |
8cc89e4e85 | |
![]() |
c9358f348a | |
![]() |
e1e892377f | |
![]() |
542afca459 | |
![]() |
9599642f3a | |
![]() |
149e93e970 | |
![]() |
ebb4f2c3d4 | |
![]() |
c67611e975 | |
![]() |
d337e14de3 | |
![]() |
b89fa7028d | |
![]() |
d280ca40a4 | |
![]() |
98e1d26134 | |
![]() |
301802abd3 | |
![]() |
90e4cb97ff | |
![]() |
8b7fc5de68 | |
![]() |
9117e7fe31 | |
![]() |
0269c24263 | |
![]() |
7871ee0f26 | |
![]() |
58543ac9c4 | |
![]() |
b5c298e0ca | |
![]() |
8b362f23f3 | |
![]() |
e384a6257b | |
![]() |
4063f7f94f | |
![]() |
3c222b0d79 | |
![]() |
43e9fbc29c | |
![]() |
ca23521c3b | |
![]() |
e1af979995 | |
![]() |
74f5a248c7 | |
![]() |
acb3d03052 | |
![]() |
48bc26901a | |
![]() |
d3f8ff2855 | |
![]() |
f43c94314c | |
![]() |
c4726b09f0 | |
![]() |
9822748209 | |
![]() |
719a714735 | |
![]() |
31ea96ce27 | |
![]() |
31374c0f7b | |
![]() |
9fe98e0132 | |
![]() |
8d0355a513 | |
![]() |
54d8d890e5 | |
![]() |
22c05ec51b | |
![]() |
e6b64cd9cd | |
![]() |
cd46994fb3 | |
![]() |
489450b1c2 | |
![]() |
edda0218e1 | |
![]() |
8a4fb5f839 | |
![]() |
15c2b57730 | |
![]() |
8317c759f1 | |
![]() |
0740443768 | |
![]() |
658b5e1456 | |
![]() |
99fbda3d13 | |
![]() |
71c52d1a39 | |
![]() |
a4e75ed733 | |
![]() |
58a47d0e46 | |
![]() |
e18fa60054 | |
![]() |
0714ed514e | |
![]() |
62f6b7c45b | |
![]() |
064f36ef6c | |
![]() |
f6c20ad314 | |
![]() |
d1c069ad1e | |
![]() |
7345a03aaa | |
![]() |
bcd8a96b5d | |
![]() |
a3360e9561 | |
![]() |
4a382f2b1c | |
![]() |
8c822c0f54 | |
![]() |
2d6be48732 | |
![]() |
3c297ba18f | |
![]() |
6921ca9a42 | |
![]() |
e96eda0990 | |
![]() |
662b0cd098 | |
![]() |
44dce71888 | |
![]() |
42b93be492 | |
![]() |
a42920355c | |
![]() |
0360d35c3b | |
![]() |
de72311c95 | |
![]() |
2db607ec28 | |
![]() |
ee9413b882 | |
![]() |
aa96b1f1ed | |
![]() |
8086cc9153 | |
![]() |
d4e3639236 | |
![]() |
214097584a | |
![]() |
c5a65e9cec | |
![]() |
f3a777a2c8 | |
![]() |
3d760cad8b | |
![]() |
03b301b43b | |
![]() |
53922374df | |
![]() |
a9f531bffe | |
![]() |
8b8db24179 | |
![]() |
72bb09550c | |
![]() |
1259b8cd68 | |
![]() |
f0d628bf27 | |
![]() |
d7af4b2cf9 | |
![]() |
6703db234d | |
![]() |
bfd70efcc3 | |
![]() |
a8a6e7bf31 | |
![]() |
7909e3e9ce | |
![]() |
af798705b4 | |
![]() |
b0935086c2 | |
![]() |
de9f69e461 | |
![]() |
2cfaa1c1d7 | |
![]() |
b8a5486995 | |
![]() |
667c766273 | |
![]() |
cd47d32e2d | |
![]() |
13239c1754 | |
![]() |
c4aaa29ffc | |
![]() |
d9efeb3b67 | |
![]() |
50cbeb3e4c | |
![]() |
2f4d9ce54b | |
![]() |
8359ac2813 | |
![]() |
d2a393f7f9 | |
![]() |
b18bea6b9f | |
![]() |
7df3597757 | |
![]() |
b4520c170e | |
![]() |
f4a1b27e2e | |
![]() |
9ae92b983a | |
![]() |
c166cbe49c | |
![]() |
f7a082d4b8 | |
![]() |
fdf8c4d620 | |
![]() |
445099fc74 | |
![]() |
84b595ea6f | |
![]() |
bf295b4c67 | |
![]() |
a7c0a45e5d | |
![]() |
a259841eaf | |
![]() |
698fe55b85 | |
![]() |
286d433da6 | |
![]() |
9e74e40453 | |
![]() |
13f5e4f8a6 | |
![]() |
6dc2b2cb5e | |
![]() |
54fbf0d0ac | |
![]() |
2d5e53c0f2 | |
![]() |
d1e8529a7b | |
![]() |
f7b5228109 | |
![]() |
23e1e87368 | |
![]() |
0aabb7226d | |
![]() |
4655650a68 | |
![]() |
118237ab05 | |
![]() |
dfc8df42f5 | |
![]() |
54e3b7e8d3 | |
![]() |
49c8804a1c | |
![]() |
d09b003bc3 | |
![]() |
79317d5b70 | |
![]() |
8b81b36e22 | |
![]() |
e43600494a | |
![]() |
642942b5cf | |
![]() |
032d41e5ed | |
![]() |
30162f6baa | |
![]() |
8d3a8471aa | |
![]() |
9662f3e8b3 | |
![]() |
285504cba1 | |
![]() |
742ceea182 | |
![]() |
d583499a07 | |
![]() |
effe955953 | |
![]() |
caf85b990d | |
![]() |
d32118d017 | |
![]() |
9ba1a78d09 | |
![]() |
c974267cde | |
![]() |
cbf6316050 | |
![]() |
fe6d2f8a6e | |
![]() |
d5a08d4996 | |
![]() |
d9e03b769b | |
![]() |
3d1aee77b4 | |
![]() |
441b19f0c5 | |
![]() |
84167396da | |
![]() |
a7905c9f82 | |
![]() |
93a91c8f84 | |
![]() |
bedda2959d | |
![]() |
5e3d08ef4d | |
![]() |
98e414b6df | |
![]() |
6533875dee | |
![]() |
2f4956f3dd | |
![]() |
cb8abca0f6 | |
![]() |
cf1cb34a5f | |
![]() |
e9aeb8318e | |
![]() |
6be2b4f65e | |
![]() |
0d6775dfa8 | |
![]() |
eb1ea4c0b8 | |
![]() |
04dc037f9e | |
![]() |
aeed2fa003 | |
![]() |
5b02e18f7c | |
![]() |
31d5e3ad0e | |
![]() |
da72ce02ad | |
![]() |
e52fff58f5 | |
![]() |
7f44132abc | |
![]() |
a44335198e | |
![]() |
bf2449b693 | |
![]() |
80c172971a | |
![]() |
52b1bda8d8 | |
![]() |
24a464e142 | |
![]() |
cdf6107b25 | |
![]() |
dece458c67 | |
![]() |
f077579b29 | |
![]() |
1b4dba70f0 | |
![]() |
a2edb31753 | |
![]() |
582c52ebf5 | |
![]() |
7188a06488 | |
![]() |
c63651626f | |
![]() |
43a432eb9a | |
![]() |
ed7799b54a | |
![]() |
e0cdeb3571 | |
![]() |
fc64dcc9b9 | |
![]() |
f4f08d9449 | |
![]() |
1f083c7acb | |
![]() |
0ea06f01b8 | |
![]() |
53d4f15923 | |
![]() |
7951ff5086 | |
![]() |
b811594ad4 | |
![]() |
8d5c7d6226 | |
![]() |
afad3a720b | |
![]() |
e155cdc282 | |
![]() |
396ed472a9 | |
![]() |
9c6f12087d | |
![]() |
06f7dc984d | |
![]() |
d6dfa89533 | |
![]() |
7273b0a5b7 | |
![]() |
eb49d9624c | |
![]() |
98cd5ba27d | |
![]() |
b2912b944a | |
![]() |
08413302eb | |
![]() |
f48049be4d | |
![]() |
dc10779abb | |
![]() |
a38a0b6f75 | |
![]() |
2a4cceff5a | |
![]() |
6e095e3266 | |
![]() |
1ad1813239 | |
![]() |
687517d7f4 | |
![]() |
d015d17fad | |
![]() |
348ff7ee17 | |
![]() |
5aa5cc1a10 | |
![]() |
e89d8cd985 | |
![]() |
394785b9c4 | |
![]() |
7af19dbd61 | |
![]() |
06ae8545ae | |
![]() |
332cb22a99 | |
![]() |
3e931c68b4 | |
![]() |
ba0c679e60 | |
![]() |
5698393d31 | |
![]() |
bde03411f1 | |
![]() |
006a4d1ec6 | |
![]() |
6f149cba69 | |
![]() |
30e894a64a | |
![]() |
866186f611 | |
![]() |
aee2544fbf | |
![]() |
6daeeefb33 | |
![]() |
9f913244a0 | |
![]() |
7df31f1e87 | |
![]() |
e1769d1545 | |
![]() |
1be9da52c6 | |
![]() |
f123366069 | |
![]() |
b635a2bc88 | |
![]() |
ff958e20b6 | |
![]() |
098519da5e | |
![]() |
2993b76dad | |
![]() |
1393251da9 | |
![]() |
2aadb09f49 | |
![]() |
a57c336e11 | |
![]() |
c234f78dbd | |
![]() |
5873b336f2 | |
![]() |
8352145d82 | |
![]() |
ba51df0c37 | |
![]() |
4f12fab56b | |
![]() |
7e9ee525a8 | |
![]() |
f39e2e9412 | |
![]() |
9b0e504cea | |
![]() |
2abcd96bbe | |
![]() |
285ad71874 | |
![]() |
4d1b08f89d | |
![]() |
80605becf1 | |
![]() |
ed8887864c | |
![]() |
75e0cdd550 | |
![]() |
e1fb8272cc | |
![]() |
54bec32b7e | |
![]() |
daee9266c5 | |
![]() |
ad9b49733f | |
![]() |
15b97b1dcb | |
![]() |
61a596dc15 | |
![]() |
86e95d9e6e | |
![]() |
e56161e223 | |
![]() |
1735dbca11 | |
![]() |
617d485478 | |
![]() |
c777ebfac9 | |
![]() |
1ba14f7682 | |
![]() |
76b7324d88 | |
![]() |
c3bf359629 | |
![]() |
8c8f912880 | |
![]() |
99c57141cb | |
![]() |
ee522100b9 | |
![]() |
5d35f2c1a6 | |
![]() |
65d7b00f4d | |
![]() |
627bcaee43 | |
![]() |
e5e4c15058 | |
![]() |
2a6a17486a | |
![]() |
621399545e | |
![]() |
764df71758 | |
![]() |
1da5c2cd84 | |
![]() |
c7f6811961 | |
![]() |
48b857eb85 | |
![]() |
c09b63c69f | |
![]() |
849a2b3271 | |
![]() |
020b410ffe | |
![]() |
db2574ab53 | |
![]() |
f266d3b151 | |
![]() |
35f2a03b4e | |
![]() |
e59e988809 | |
![]() |
5ff9cd1bbb | |
![]() |
eed8fb0b28 | |
![]() |
c41488b103 | |
![]() |
5be7d64c7d | |
![]() |
0d96b6a28a | |
![]() |
0dc7cb05e7 | |
![]() |
351ce3995a | |
![]() |
c8cf2abbd9 | |
![]() |
45754d3b75 | |
![]() |
d570497b16 | |
![]() |
692e8418d6 | |
![]() |
8caaf3ae20 | |
![]() |
a29f524186 | |
![]() |
7a1480bb07 | |
![]() |
40fc70894e | |
![]() |
4d88e04e59 | |
![]() |
4878e88d4f | |
![]() |
8d22ad03e2 | |
![]() |
89114dcf74 | |
![]() |
ad228e8953 | |
![]() |
3b6412219b | |
![]() |
0b480bac10 | |
![]() |
3076da1ed8 | |
![]() |
efeead52b6 | |
![]() |
99bf19e21b | |
![]() |
e7bf75e9a4 | |
![]() |
90a7304b4e | |
![]() |
8992841ffa | |
![]() |
071ea579a3 | |
![]() |
b670f44138 | |
![]() |
19879c20c2 | |
![]() |
6a41e98474 | |
![]() |
5f116d522d | |
![]() |
2d53f317b0 | |
![]() |
e963c3c1ec | |
![]() |
9a19207f86 | |
![]() |
720b73939f | |
![]() |
97ae456099 | |
![]() |
9ccaa98e2a | |
![]() |
cf07f75682 | |
![]() |
6885713eed | |
![]() |
f4813fccee | |
![]() |
4ae981f484 | |
![]() |
593fac83cf | |
![]() |
1caf5ef8bc | |
![]() |
b376bc6059 | |
![]() |
ecfb72bc50 | |
![]() |
522edda074 | |
![]() |
cef6cf17b6 | |
![]() |
05f03f7c90 | |
![]() |
f7998899cf | |
![]() |
994ce6c743 | |
![]() |
335d05bb5c | |
![]() |
685960358c | |
![]() |
e2349984b8 | |
![]() |
d56aec5652 | |
![]() |
d88cc2ec8e | |
![]() |
d91da77a31 | |
![]() |
cdd49d9d54 | |
![]() |
40b390de6d | |
![]() |
da9c8bdee5 | |
![]() |
cc02f8fbe8 | |
![]() |
b7612520c4 | |
![]() |
bedc101637 | |
![]() |
95c7ba3cc2 | |
![]() |
70779a69ea | |
![]() |
10f7612595 | |
![]() |
587d4b2db6 | |
![]() |
377d8cb884 | |
![]() |
a9544059cf | |
![]() |
77c06e9557 | |
![]() |
3708b531df | |
![]() |
ef3a696972 | |
![]() |
63dd7c0b25 | |
![]() |
d25602fbe7 | |
![]() |
7861300d72 | |
![]() |
10b7eb60c8 | |
![]() |
a80bb19faf | |
![]() |
3fbd17ffe3 | |
![]() |
c5d1f4de9d | |
![]() |
d774cfeb6d | |
![]() |
0b4e584533 | |
![]() |
7dbfa37887 | |
![]() |
22e9dd703b | |
![]() |
1801225528 | |
![]() |
bd38e43f5a | |
![]() |
c50392d77e | |
![]() |
a602d4c231 | |
![]() |
6f35c2273d | |
![]() |
19181446aa | |
![]() |
8b38d6a797 | |
![]() |
2982f8e199 | |
![]() |
2cad53f5a5 | |
![]() |
dcf8e1988c | |
![]() |
0e9214ccea | |
![]() |
c97cd1bd10 | |
![]() |
d42ad7a9ab | |
![]() |
97cf6854ed | |
![]() |
76b10736ef | |
![]() |
eaf2ac3160 | |
![]() |
f6a26be722 | |
![]() |
89004b3b43 | |
![]() |
3c72097f3d | |
![]() |
a5ce2f66a2 | |
![]() |
3f9f33f9a4 | |
![]() |
d308f58e71 | |
![]() |
d082394bc8 | |
![]() |
91ac730129 | |
![]() |
7d24490f30 | |
![]() |
4626584b06 | |
![]() |
62b6406581 | |
![]() |
43b6472a7a | |
![]() |
ea1052388c | |
![]() |
550b7d4e41 | |
![]() |
73a4533906 | |
![]() |
fdc9a65ec1 | |
![]() |
004c439711 | |
![]() |
44b8e565ae | |
![]() |
d0b3e19279 | |
![]() |
b2d2a95a47 | |
![]() |
5a7e70a18e | |
![]() |
8f64e0c454 | |
![]() |
5e2522491d | |
![]() |
ef3c13ef24 | |
![]() |
86e4f4afe1 | |
![]() |
323a860210 | |
![]() |
bed754dde6 | |
![]() |
4dde4fa054 | |
![]() |
502150c196 | |
![]() |
4f7e3ed4e3 | |
![]() |
c36e0dbf9c | |
![]() |
3533dcdee9 | |
![]() |
55bc8713ef | |
![]() |
644344a6e4 | |
![]() |
f991ca0093 | |
![]() |
a33a3c13c6 | |
![]() |
6fccef3f69 | |
![]() |
2dcedca7ac | |
![]() |
a61759bf74 | |
![]() |
222b7bae91 | |
![]() |
166c53cd6a | |
![]() |
6c88d7c54b | |
![]() |
e8015051d2 | |
![]() |
c6c09b9c6c | |
![]() |
ada1b0d24e | |
![]() |
ba97fcb88a | |
![]() |
a1228d19b5 | |
![]() |
bbeaeb06e3 | |
![]() |
9aa45f8efb | |
![]() |
3a067f1875 | |
![]() |
0e50b2f250 | |
![]() |
e9d764e53e | |
![]() |
3e7ade9a67 | |
![]() |
1a2ca25359 | |
![]() |
55fb6667a0 | |
![]() |
76b25e13c1 | |
![]() |
e371ad345f | |
![]() |
56344fa12b | |
![]() |
0e776762c2 | |
![]() |
69c19d35fa | |
![]() |
b4f3039c5a | |
![]() |
51b10dbe96 | |
![]() |
89f46fa872 | |
![]() |
d9d9903c55 | |
![]() |
d7f8a846c3 | |
![]() |
b14dfa6458 | |
![]() |
775b77b367 | |
![]() |
4e4d9337b6 | |
![]() |
c600787f1c | |
![]() |
d87bdb2120 | |
![]() |
34afe21e8a | |
![]() |
b50facd4c2 | |
![]() |
e6d10b67a4 | |
![]() |
bc9942e929 | |
![]() |
841e4b4d68 | |
![]() |
9e1bd8d8c1 | |
![]() |
f0e2fc6700 | |
![]() |
3f5e2acfeb | |
![]() |
a59fe0604e | |
![]() |
9dfac35912 | |
![]() |
bf00c1f5e0 | |
![]() |
659880b4dc | |
![]() |
d557b1e2c2 | |
![]() |
ff436a6738 | |
![]() |
aecd222c5a | |
![]() |
d18d325c0c | |
![]() |
ff28e1a383 | |
![]() |
188818dc0d | |
![]() |
e814c3abd4 | |
![]() |
793740cf08 | |
![]() |
db052f11ca | |
![]() |
55a906ae40 | |
![]() |
2d6deeb6f3 | |
![]() |
f12d37f84e | |
![]() |
78ebcd030d | |
![]() |
134909a82f | |
![]() |
1e71749c23 | |
![]() |
0b8dbc4f68 | |
![]() |
13cee6bf06 | |
![]() |
98ace5c9fb | |
![]() |
1fbdd240f1 | |
![]() |
a8377513a6 | |
![]() |
0320bae15c | |
![]() |
dcf66fadc4 | |
![]() |
ad841a03df | |
![]() |
8495617aed | |
![]() |
16f15cc3c8 | |
![]() |
6333b1e4b1 | |
![]() |
d5551e9692 | |
![]() |
03f2d8f8a0 | |
![]() |
ec8f708472 | |
![]() |
3e3613f471 | |
![]() |
acc4cf16bd | |
![]() |
cf2837f678 | |
![]() |
0461e51ddc | |
![]() |
e1015e1194 | |
![]() |
c683131f12 | |
![]() |
a704277652 | |
![]() |
fd472e3bb4 | |
![]() |
9e88a62479 | |
![]() |
cf198cccc2 | |
![]() |
6d80a00d65 | |
![]() |
81634e6165 | |
![]() |
bf56fc34bb | |
![]() |
e09c9af306 | |
![]() |
d6cc626241 | |
![]() |
1a79949d51 | |
![]() |
54c95c39d2 | |
![]() |
094bb6108e | |
![]() |
7e35ed0100 | |
![]() |
fc93f1b36c | |
![]() |
3cb76f1810 | |
![]() |
dee78c130c | |
![]() |
ed0b476bb7 | |
![]() |
c3c8df3dd1 | |
![]() |
e0b84069d4 | |
![]() |
6f2f807b0b |
|
@ -0,0 +1,14 @@
|
|||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# 4 space - Tab indentation
|
||||
[*.{java,xml,js,html}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
|
@ -1,4 +1,3 @@
|
|||
local-values.conf
|
||||
target
|
||||
*~
|
||||
bin
|
||||
|
@ -10,3 +9,4 @@ bin
|
|||
.classpath
|
||||
/target
|
||||
.springBeans
|
||||
nb-configuration.xml
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -1 +1,11 @@
|
|||
language: java
|
||||
jdk:
|
||||
- oraclejdk11
|
||||
sudo: false
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
Unreleased:
|
||||
|
||||
*1.3.3*:
|
||||
- Authorization codes are now longer
|
||||
- Client/RS can parse the "sub" and "user_id" claims in introspection response
|
||||
- Database-direct queries for fetching tokens by user (optimization)
|
||||
- Device flow supports verification_uri_complete (must be turned on)
|
||||
- Long scopes display properly and are still checkable
|
||||
- Language system remebers when it can't find a file and stops throwing so many errors
|
||||
- Index added for refresh tokens
|
||||
- Updated to Spring Security 4.2.11
|
||||
- Updated Spring to 4.3.22
|
||||
- Change approve pages to use issuer instead of page context
|
||||
- Updated oracle database scripts
|
||||
|
||||
*1.3.2*:
|
||||
- Added changelog
|
||||
- Set default redirect URI resolver strict matching to true
|
||||
- Fixed XSS vulnerability on redirect URI display on approval page
|
||||
- Removed MITRE from copyright
|
||||
- Disallow unsigned JWTs on client authentication
|
||||
- Upgraded Nimbus revision
|
||||
- Added French translation
|
||||
- Added hooks for custom JWT claims
|
||||
- Removed "Not Yet Implemented" tag from post-logout redirect URI
|
||||
|
||||
*1.3.1*:
|
||||
- Added End Session endpoint
|
||||
- Fixed discovery endpoint
|
||||
- Downgrade MySQL connector dependency version from developer preview to GA release
|
||||
|
||||
*1.3.0*:
|
||||
- Added device flow support
|
||||
- Added PKCE support
|
||||
- Modularized UI to allow better overlay and extensions
|
||||
- Modularized data import/export API
|
||||
- Added software statements to dynamic client registration
|
||||
- Added assertion processing framework
|
||||
- Removed ID tokens from storage
|
||||
- Removed structured scopes
|
||||
|
||||
*1.2.6*:
|
||||
- Added strict HEART compliance mode
|
|
@ -1,8 +1,9 @@
|
|||
Copyright 2014 The MITRE Corporation
|
||||
and the MIT Kerberos and Internet Trust Consortium
|
||||
Copyright 2018 The MIT Internet Trust Consortium
|
||||
|
||||
Portions copyright 2011-2013 The MITRE Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
you may not use this project except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
|
12
README.md
12
README.md
|
@ -1,9 +1,11 @@
|
|||
# MITREid Connect
|
||||
---
|
||||
|
||||
[](https://maven-badges.herokuapp.com/maven-central/org.mitre/openid-connect-parent) [](https://travis-ci.org/mitreid-connect/OpenID-Connect-Java-Spring-Server)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/org.mitre/openid-connect-parent) [](https://travis-ci.org/mitreid-connect/OpenID-Connect-Java-Spring-Server) [](https://codecov.io/github/mitreid-connect/OpenID-Connect-Java-Spring-Server)
|
||||
|
||||
This project contains an OpenID Connect reference implementation in Java on the Spring platform, including a functioning [server library](openid-connect-server), [deployable server package](openid-connect-server-webapp), [client (RP) library](openid-connect-client), and general [utility libraries](openid-connect-common). The server can be used as an OpenID Connect Identity Provider as well as a general-purpose OAuth 2.0 Authorization Server.
|
||||
This project contains a certified OpenID Connect reference implementation in Java on the Spring platform, including a functioning [server library](openid-connect-server), [deployable server package](openid-connect-server-webapp), [client (RP) library](openid-connect-client), and general [utility libraries](openid-connect-common). The server can be used as an OpenID Connect Identity Provider as well as a general-purpose OAuth 2.0 Authorization Server.
|
||||
|
||||
[](https://openid.net/certification/)
|
||||
|
||||
More information about the project can be found:
|
||||
|
||||
|
@ -23,9 +25,7 @@ The authors and key contributors of the project include:
|
|||
* [Steve Moore](https://github.com/srmoore)
|
||||
* [Mike Derryberry](https://github.com/mtderryberry)
|
||||
* [William Kim](https://github.com/wikkim)
|
||||
* [Mark Janssen](https://github.com/praseodym)
|
||||
|
||||
|
||||
|
||||
|
||||
Copyright ©2014, [The MITRE Corporation](http://www.mitre.org/)
|
||||
and the [MIT Kerberos and Internet Trust Consortium](http://kit.mit.edu/). Licensed under the Apache 2.0 license, for details see `LICENSE.txt`.
|
||||
Licensed under the Apache 2.0 license, for details see `LICENSE.txt`.
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# MITREid Connect
|
||||
---
|
||||
|
||||
[](https://maven-badges.herokuapp.com/maven-central/org.mitre/openid-connect-parent) [](https://travis-ci.org/mitreid-connect/OpenID-Connect-Java-Spring-Server)
|
||||
|
||||
此项目提供了一个业经认证的、用Java语言构筑于Spring平台之上的OpenID Connect参考实现,包括 [服务器端的实现库](openid-connect-server), [可部署的服务器包](openid-connect-server-webapp), [客户端 (RP) 的库](openid-connect-client), 以及 [工具类库](openid-connect-common)。该服务器可以用做OpenID Connect身份提供者,也可以用做一般意义上的OAuth 2.0授权服务器。
|
||||
|
||||
[](https://openid.net/certification/)
|
||||
|
||||
有关项目的更多信息参见:
|
||||
|
||||
* [项目在GitHub上的主页 (及相关项目)](https://github.com/mitreid-connect/)
|
||||
* [完整的文档](https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/wiki)
|
||||
* [Maven文档及Java API](http://mitreid-connect.github.com/)
|
||||
* [问题(Issue)追踪系统 (用于报告bug及提交支持请求)](https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues)
|
||||
* 项目的邮件列表: `mitreid-connect@mit.edu`, 及其 [在线存档](https://mailman.mit.edu/mailman/listinfo/mitreid-connect).
|
||||
|
||||
|
||||
项目的作者及主要贡献者有:
|
||||
|
||||
* [Justin Richer](https://github.com/jricher/)
|
||||
* [Amanda Anganes](https://github.com/aanganes/)
|
||||
* [Michael Jett](https://github.com/jumbojett/)
|
||||
* [Michael Walsh](https://github.com/nemonik/)
|
||||
* [Steve Moore](https://github.com/srmoore)
|
||||
* [Mike Derryberry](https://github.com/mtderryberry)
|
||||
* [William Kim](https://github.com/wikkim)
|
||||
* [Mark Janssen](https://github.com/praseodym)
|
||||
|
||||
|
||||
项目的中文译者:
|
||||
|
||||
* [刘晓曦](https://github.com/liouxiao/)
|
||||
|
||||
|
||||
|
||||
|
||||
版权所有 ©2018 [MIT因特网信任联盟](http://www.mit-trust.org/). 采用Apache 2.0许可证, 详见 `LICENSE.txt`.
|
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2014 The MITRE Corporation
|
||||
and the MIT Kerberos and Internet Trust Consortium
|
||||
Copyright 2018 The MIT Internet Trust Consortium
|
||||
|
||||
Portions copyright 2011-2013 The MITRE Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Overview ##
|
||||
|
||||
This project contains an OpenID Connect Client implemented as a Spring Security AuthenticationFilter. The client facilitates a user's authentication into the secured application to an OpenID Connect Java Spring Server following the OpenID Connect Standard protocol.
|
||||
This project contains an OpenID Connect Client implemented as a Spring Security AuthenticationFilter. The client facilitates a user's authentication into the secured application to an OpenID Connect Server following the OpenID Connect standard protocol.
|
||||
|
||||
## Configuring ##
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2014 The MITRE Corporation
|
||||
and the MIT Kerberos and Internet Trust Consortium
|
||||
Copyright 2018 The MIT Internet Trust Consortium
|
||||
|
||||
Portions copyright 2011-2013 The MITRE Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -20,7 +22,7 @@
|
|||
<parent>
|
||||
<artifactId>openid-connect-parent</artifactId>
|
||||
<groupId>org.mitre</groupId>
|
||||
<version>1.1.9</version>
|
||||
<version>1.3.5-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>openid-connect-client</artifactId>
|
||||
|
@ -30,7 +32,6 @@
|
|||
<dependency>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-common</artifactId>
|
||||
<version>1.1.9</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<packaging>jar</packaging>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,13 +14,14 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.introspectingfilter;
|
||||
|
||||
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -27,7 +29,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
|
||||
import org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService;
|
||||
import org.mitre.oauth2.introspectingfilter.service.impl.SimpleIntrospectionAuthorityGranter;
|
||||
|
@ -67,22 +69,49 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
private IntrospectionConfigurationService introspectionConfigurationService;
|
||||
private IntrospectionAuthorityGranter introspectionAuthorityGranter = new SimpleIntrospectionAuthorityGranter();
|
||||
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private int defaultExpireTime = 300000; // 5 minutes in milliseconds
|
||||
private boolean forceCacheExpireTime = false; // force removal of cached tokens based on default expire time
|
||||
private boolean cacheNonExpiringTokens = false;
|
||||
private boolean cacheTokens = true;
|
||||
|
||||
private HttpComponentsClientHttpRequestFactory factory;
|
||||
|
||||
public IntrospectingTokenService() {
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public IntrospectingTokenService(HttpClient httpClient) {
|
||||
this.factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
}
|
||||
|
||||
// Inner class to store in the hash map
|
||||
private class TokenCacheObject {
|
||||
OAuth2AccessToken token;
|
||||
OAuth2Authentication auth;
|
||||
Date cacheExpire;
|
||||
|
||||
private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
|
||||
this.token = token;
|
||||
this.auth = auth;
|
||||
|
||||
// we don't need to check the cacheTokens values, because this won't actually be added to the cache if cacheTokens is false
|
||||
// if the token isn't null we use the token expire time
|
||||
// if forceCacheExpireTime is also true, we also make sure that the token expire time is shorter than the default expire time
|
||||
if ((this.token.getExpiration() != null) && (!forceCacheExpireTime || (forceCacheExpireTime && (this.token.getExpiration().getTime() - System.currentTimeMillis() <= defaultExpireTime)))) {
|
||||
this.cacheExpire = this.token.getExpiration();
|
||||
} else { // if the token doesn't have an expire time, or if the using forceCacheExpireTime the token expire time is longer than the default, then use the default expire time
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.add(Calendar.MILLISECOND, defaultExpireTime);
|
||||
this.cacheExpire = cal.getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, TokenCacheObject> authCache = new HashMap<String, TokenCacheObject>();
|
||||
private static Logger logger = LoggerFactory.getLogger(IntrospectingTokenService.class);
|
||||
private Map<String, TokenCacheObject> authCache = new HashMap<>();
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(IntrospectingTokenService.class);
|
||||
|
||||
/**
|
||||
* @return the introspectionConfigurationService
|
||||
|
@ -112,12 +141,84 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
return introspectionAuthorityGranter;
|
||||
}
|
||||
|
||||
// Check if there is a token and authentication in the cache
|
||||
// and check if it is not expired.
|
||||
/**
|
||||
* get the default cache expire time in milliseconds
|
||||
* @return
|
||||
*/
|
||||
public int getDefaultExpireTime() {
|
||||
return defaultExpireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the default cache expire time in milliseconds
|
||||
* @param defaultExpireTime
|
||||
*/
|
||||
public void setDefaultExpireTime(int defaultExpireTime) {
|
||||
this.defaultExpireTime = defaultExpireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* check if forcing a cache expire time maximum value
|
||||
* @return the forceCacheExpireTime setting
|
||||
*/
|
||||
public boolean isForceCacheExpireTime() {
|
||||
return forceCacheExpireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* set forcing a cache expire time maximum value
|
||||
* @param forceCacheExpireTime
|
||||
*/
|
||||
public void setForceCacheExpireTime(boolean forceCacheExpireTime) {
|
||||
this.forceCacheExpireTime = forceCacheExpireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are non-expiring tokens cached using the default cache time
|
||||
* @return state of cacheNonExpiringTokens
|
||||
*/
|
||||
public boolean isCacheNonExpiringTokens() {
|
||||
return cacheNonExpiringTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* should non-expiring tokens be cached using the default cache timeout
|
||||
* @param cacheNonExpiringTokens
|
||||
*/
|
||||
public void setCacheNonExpiringTokens(boolean cacheNonExpiringTokens) {
|
||||
this.cacheNonExpiringTokens = cacheNonExpiringTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the service caching tokens, or is it hitting the introspection end point every time
|
||||
* @return true is caching tokens locally, false hits the introspection end point every time
|
||||
*/
|
||||
public boolean isCacheTokens() {
|
||||
return cacheTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure if the client should cache tokens locally or not
|
||||
* @param cacheTokens
|
||||
*/
|
||||
public void setCacheTokens(boolean cacheTokens) {
|
||||
this.cacheTokens = cacheTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the introspection end point response for a token has been cached locally
|
||||
* This call will return the token if it has been cached and is still valid according to
|
||||
* the cache expire time on the TokenCacheObject. If a cached value has been found but is
|
||||
* expired, either by default expire times or the token's own expire time, then the token is
|
||||
* removed from the cache and null is returned.
|
||||
* @param key is the token to check
|
||||
* @return the cached TokenCacheObject or null
|
||||
*/
|
||||
private TokenCacheObject checkCache(String key) {
|
||||
if (authCache.containsKey(key)) {
|
||||
if (cacheTokens && authCache.containsKey(key)) {
|
||||
TokenCacheObject tco = authCache.get(key);
|
||||
if (tco.token.getExpiration().after(new Date())) {
|
||||
|
||||
if (tco != null && tco.cacheExpire != null && tco.cacheExpire.after(new Date())) {
|
||||
return tco;
|
||||
} else {
|
||||
// if the token is expired, don't keep things around.
|
||||
|
@ -129,19 +230,27 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
|
||||
private OAuth2Request createStoredRequest(final JsonObject token) {
|
||||
String clientId = token.get("client_id").getAsString();
|
||||
Set<String> scopes = new HashSet<String>();
|
||||
Set<String> scopes = new HashSet<>();
|
||||
if (token.has("scope")) {
|
||||
scopes.addAll(OAuth2Utils.parseParameterList(token.get("scope").getAsString()));
|
||||
}
|
||||
Map<String, String> parameters = new HashMap<String, String>();
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
parameters.put("client_id", clientId);
|
||||
parameters.put("scope", OAuth2Utils.formatParameterList(scopes));
|
||||
OAuth2Request storedRequest = new OAuth2Request(parameters, clientId, null, true, scopes, null, null, null, null);
|
||||
return storedRequest;
|
||||
}
|
||||
|
||||
private Authentication createAuthentication(JsonObject token) {
|
||||
return new PreAuthenticatedAuthenticationToken(token.get("sub").getAsString(), token, introspectionAuthorityGranter.getAuthorities(token));
|
||||
private Authentication createUserAuthentication(JsonObject token) {
|
||||
JsonElement userId = token.get("user_id");
|
||||
if(userId == null) {
|
||||
userId = token.get("sub");
|
||||
if (userId == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return new PreAuthenticatedAuthenticationToken(userId.getAsString(), token, introspectionAuthorityGranter.getAuthorities(token));
|
||||
}
|
||||
|
||||
private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString) {
|
||||
|
@ -149,10 +258,14 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
return accessToken;
|
||||
}
|
||||
|
||||
// Validate a token string against the introspection endpoint,
|
||||
// then parse it and store it in the local cache. Return true on
|
||||
// sucess, false otherwise.
|
||||
private boolean parseToken(String accessToken) {
|
||||
/**
|
||||
* Validate a token string against the introspection endpoint,
|
||||
* then parse it and store it in the local cache if caching is enabled.
|
||||
*
|
||||
* @param accessToken Token to pass to the introspection endpoint
|
||||
* @return TokenCacheObject containing authentication and token if the token was valid, otherwise null
|
||||
*/
|
||||
private TokenCacheObject parseToken(String accessToken) {
|
||||
|
||||
// find out which URL to ask
|
||||
String introspectionUrl;
|
||||
|
@ -162,14 +275,14 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
client = introspectionConfigurationService.getClientConfiguration(accessToken);
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.error("Unable to load introspection URL or client configuration", e);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
// Use the SpringFramework RestTemplate to send the request to the
|
||||
// endpoint
|
||||
String validatedToken = null;
|
||||
|
||||
RestTemplate restTemplate;
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
|
||||
final String clientId = client.getClientId();
|
||||
final String clientSecret = client.getClientSecret();
|
||||
|
@ -199,12 +312,13 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
validatedToken = restTemplate.postForObject(introspectionUrl, form, String.class);
|
||||
} catch (RestClientException rce) {
|
||||
logger.error("validateToken", rce);
|
||||
return null;
|
||||
}
|
||||
if (validatedToken != null) {
|
||||
// parse the json
|
||||
JsonElement jsonRoot = new JsonParser().parse(validatedToken);
|
||||
if (!jsonRoot.isJsonObject()) {
|
||||
return false; // didn't get a proper JSON object
|
||||
return null; // didn't get a proper JSON object
|
||||
}
|
||||
|
||||
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
|
||||
|
@ -212,29 +326,31 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
if (tokenResponse.get("error") != null) {
|
||||
// report an error?
|
||||
logger.error("Got an error back: " + tokenResponse.get("error") + ", " + tokenResponse.get("error_description"));
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!tokenResponse.get("active").getAsBoolean()) {
|
||||
// non-valid token
|
||||
logger.info("Server returned non-active token");
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
// create an OAuth2Authentication
|
||||
OAuth2Authentication auth = new OAuth2Authentication(createStoredRequest(tokenResponse), createAuthentication(tokenResponse));
|
||||
OAuth2Authentication auth = new OAuth2Authentication(createStoredRequest(tokenResponse), createUserAuthentication(tokenResponse));
|
||||
// create an OAuth2AccessToken
|
||||
OAuth2AccessToken token = createAccessToken(tokenResponse, accessToken);
|
||||
|
||||
if (token.getExpiration().after(new Date())) {
|
||||
if (token.getExpiration() == null || token.getExpiration().after(new Date())) {
|
||||
// Store them in the cache
|
||||
authCache.put(accessToken, new TokenCacheObject(token, auth));
|
||||
|
||||
return true;
|
||||
TokenCacheObject tco = new TokenCacheObject(token, auth);
|
||||
if (cacheTokens && (cacheNonExpiringTokens || token.getExpiration() != null)) {
|
||||
authCache.put(accessToken, tco);
|
||||
}
|
||||
return tco;
|
||||
}
|
||||
}
|
||||
|
||||
// If we never put a token and an authentication in the cache...
|
||||
return false;
|
||||
// when the token is invalid for whatever reason
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,16 +362,12 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
if (cacheAuth != null) {
|
||||
return cacheAuth.auth;
|
||||
} else {
|
||||
if (parseToken(accessToken)) {
|
||||
cacheAuth = authCache.get(accessToken);
|
||||
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
||||
cacheAuth = parseToken(accessToken);
|
||||
if (cacheAuth != null) {
|
||||
return cacheAuth.auth;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,16 +380,12 @@ public class IntrospectingTokenService implements ResourceServerTokenServices {
|
|||
if (cacheAuth != null) {
|
||||
return cacheAuth.token;
|
||||
} else {
|
||||
if (parseToken(accessToken)) {
|
||||
cacheAuth = authCache.get(accessToken);
|
||||
if (cacheAuth != null && (cacheAuth.token.getExpiration().after(new Date()))) {
|
||||
cacheAuth = parseToken(accessToken);
|
||||
if (cacheAuth != null) {
|
||||
return cacheAuth.token;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,19 +14,14 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.introspectingfilter;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
@ -37,26 +33,21 @@ import com.google.gson.JsonObject;
|
|||
|
||||
public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
|
||||
|
||||
private JsonObject token;
|
||||
private JsonObject introspectionResponse;
|
||||
private String tokenString;
|
||||
private Set<String> scopes = new HashSet<String>();
|
||||
private Set<String> scopes = new HashSet<>();
|
||||
private Date expireDate;
|
||||
|
||||
|
||||
public OAuth2AccessTokenImpl(JsonObject token, String tokenString) {
|
||||
this.token = token;
|
||||
public OAuth2AccessTokenImpl(JsonObject introspectionResponse, String tokenString) {
|
||||
this.setIntrospectionResponse(introspectionResponse);
|
||||
this.tokenString = tokenString;
|
||||
if (token.get("scope") != null) {
|
||||
scopes = Sets.newHashSet(Splitter.on(" ").split(token.get("scope").getAsString()));
|
||||
if (introspectionResponse.get("scope") != null) {
|
||||
scopes = Sets.newHashSet(Splitter.on(" ").split(introspectionResponse.get("scope").getAsString()));
|
||||
}
|
||||
|
||||
DateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
if (token.get("exp") != null) {
|
||||
try {
|
||||
expireDate = dateFormater.parse(token.get("exp").getAsString());
|
||||
} catch (ParseException ex) {
|
||||
Logger.getLogger(IntrospectingTokenService.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (introspectionResponse.get("exp") != null) {
|
||||
expireDate = new Date(introspectionResponse.get("exp").getAsLong() * 1000L);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,4 +98,20 @@ public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
|
|||
return tokenString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the token
|
||||
*/
|
||||
public JsonObject getIntrospectionResponse() {
|
||||
return introspectionResponse;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param token the token to set
|
||||
*/
|
||||
public void setIntrospectionResponse(JsonObject token) {
|
||||
this.introspectionResponse = token;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.introspectingfilter.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.oauth2.common.util.OAuth2Utils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class ScopeBasedIntrospectionAuthoritiesGranter implements IntrospectionAuthorityGranter {
|
||||
|
||||
private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_API");
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.introspectingfilter.IntrospectionAuthorityGranter#getAuthorities(net.minidev.json.JSONObject)
|
||||
*/
|
||||
@Override
|
||||
public List<GrantedAuthority> getAuthorities(JsonObject introspectionResponse) {
|
||||
List<GrantedAuthority> auth = new ArrayList<>(getAuthorities());
|
||||
|
||||
if (introspectionResponse.has("scope") && introspectionResponse.get("scope").isJsonPrimitive()) {
|
||||
String scopeString = introspectionResponse.get("scope").getAsString();
|
||||
Set<String> scopes = OAuth2Utils.parseParameterList(scopeString);
|
||||
for (String scope : scopes) {
|
||||
auth.add(new SimpleGrantedAuthority("OAUTH_SCOPE_" + scope));
|
||||
}
|
||||
}
|
||||
|
||||
return auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the authorities
|
||||
*/
|
||||
public List<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorities the authorities to set
|
||||
*/
|
||||
public void setAuthorities(List<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
public class AuthorizationEndpointException extends AuthenticationServiceException {
|
||||
|
||||
private static final long serialVersionUID = 6953119789654778380L;
|
||||
|
||||
private String error;
|
||||
|
||||
private String errorDescription;
|
||||
|
||||
private String errorURI;
|
||||
|
||||
public AuthorizationEndpointException(String error, String errorDescription, String errorURI) {
|
||||
super("Error from Authorization Endpoint: " + error + " " + errorDescription + " " + errorURI);
|
||||
this.error = error;
|
||||
this.errorDescription = errorDescription;
|
||||
this.errorURI = errorURI;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getErrorDescription() {
|
||||
return errorDescription;
|
||||
}
|
||||
|
||||
public String getErrorURI() {
|
||||
return errorURI;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AuthorizationEndpointException [error=" + error + ", errorDescription=" + errorDescription + ", errorURI=" + errorURI + "]";
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,20 +14,25 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -37,31 +43,36 @@ import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper
|
|||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class NamedAdminAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||
public class NamedAdminAuthoritiesMapper implements OIDCAuthoritiesMapper {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(NamedAdminAuthoritiesMapper.class);
|
||||
|
||||
private static final SimpleGrantedAuthority ROLE_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
|
||||
private static final SimpleGrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
|
||||
|
||||
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<SubjectIssuerGrantedAuthority>();
|
||||
|
||||
private GrantedAuthoritiesMapper chain = new NullAuthoritiesMapper();
|
||||
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(JWT idToken, UserInfo userInfo) {
|
||||
|
||||
Set<GrantedAuthority> out = new HashSet<GrantedAuthority>();
|
||||
out.addAll(authorities);
|
||||
Set<GrantedAuthority> out = new HashSet<>();
|
||||
try {
|
||||
JWTClaimsSet claims = idToken.getJWTClaimsSet();
|
||||
|
||||
SubjectIssuerGrantedAuthority authority = new SubjectIssuerGrantedAuthority(claims.getSubject(), claims.getIssuer());
|
||||
out.add(authority);
|
||||
|
||||
for (GrantedAuthority authority : authorities) {
|
||||
if (admins.contains(authority)) {
|
||||
out.add(ROLE_ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
// everybody's a user by default
|
||||
out.add(ROLE_USER);
|
||||
|
||||
return chain.mapAuthorities(out);
|
||||
} catch (ParseException e) {
|
||||
logger.error("Unable to parse ID Token inside of authorities mapper (huh?)");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,18 +89,4 @@ public class NamedAdminAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
|||
this.admins = admins;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the chain
|
||||
*/
|
||||
public GrantedAuthoritiesMapper getChain() {
|
||||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chain the chain to set
|
||||
*/
|
||||
public void setChain(GrantedAuthoritiesMapper chain) {
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.PRIVATE_KEY;
|
||||
|
@ -23,10 +24,14 @@ import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_JWT;
|
|||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -34,10 +39,12 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||
import org.mitre.jwt.signer.service.impl.SymmetricCacheService;
|
||||
import org.mitre.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService;
|
||||
import org.mitre.oauth2.model.PKCEAlgorithm;
|
||||
import org.mitre.oauth2.model.RegisteredClient;
|
||||
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
|
||||
import org.mitre.openid.connect.client.service.AuthRequestOptionsService;
|
||||
|
@ -47,7 +54,7 @@ import org.mitre.openid.connect.client.service.IssuerService;
|
|||
import org.mitre.openid.connect.client.service.ServerConfigurationService;
|
||||
import org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.ClientHttpRequest;
|
||||
|
@ -59,10 +66,12 @@ import org.springframework.security.web.authentication.AbstractAuthenticationPro
|
|||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
@ -71,11 +80,11 @@ import com.nimbusds.jose.Algorithm;
|
|||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.util.Base64;
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.jwt.PlainJWT;
|
||||
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
|
@ -87,31 +96,45 @@ import com.nimbusds.jwt.SignedJWT;
|
|||
public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
protected final static String REDIRECT_URI_SESION_VARIABLE = "redirect_uri";
|
||||
protected final static String CODE_VERIFIER_SESSION_VARIABLE = "code_verifier";
|
||||
protected final static String STATE_SESSION_VARIABLE = "state";
|
||||
protected final static String NONCE_SESSION_VARIABLE = "nonce";
|
||||
protected final static String ISSUER_SESSION_VARIABLE = "issuer";
|
||||
protected static final String TARGET_SESSION_VARIABLE = "target";
|
||||
protected final static String TARGET_SESSION_VARIABLE = "target";
|
||||
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
|
||||
|
||||
protected final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
||||
public final static String FILTER_PROCESSES_URL = "/openid_connect_login";
|
||||
|
||||
// Allow for time sync issues by having a window of X seconds.
|
||||
private int timeSkewAllowance = 300;
|
||||
|
||||
@Autowired
|
||||
// fetches and caches public keys for servers
|
||||
@Autowired(required=false)
|
||||
private JWKSetCacheService validationServices;
|
||||
|
||||
// creates JWT signer/validators for symmetric keys
|
||||
@Autowired(required=false)
|
||||
private SymmetricCacheService symmetricCacheService;
|
||||
private SymmetricKeyJWTValidatorCacheService symmetricCacheService;
|
||||
|
||||
// signer based on keypair for this client (for outgoing auth requests)
|
||||
@Autowired(required=false)
|
||||
private JWTSigningAndValidationService authenticationSignerService;
|
||||
|
||||
@Autowired(required=false)
|
||||
private JwtSigningAndValidationService authenticationSignerService;
|
||||
private HttpClient httpClient;
|
||||
|
||||
// modular services to build out client filter
|
||||
private ServerConfigurationService servers;
|
||||
private ClientConfigurationService clients;
|
||||
/*
|
||||
* Modular services to build out client filter.
|
||||
*/
|
||||
// looks at the request and determines which issuer to use for lookup on the server
|
||||
private IssuerService issuerService;
|
||||
// holds server information (auth URI, token URI, etc.), indexed by issuer
|
||||
private ServerConfigurationService servers;
|
||||
// holds client information (client ID, redirect URI, etc.), indexed by issuer of the server
|
||||
private ClientConfigurationService clients;
|
||||
// provides extra options to inject into the outbound request
|
||||
private AuthRequestOptionsService authOptions = new StaticAuthRequestOptionsService(); // initialize with an empty set of options
|
||||
// builds the actual request URI based on input from all other services
|
||||
private AuthRequestUrlBuilder authRequestBuilder;
|
||||
|
||||
// private helpers to handle target link URLs
|
||||
|
@ -123,7 +146,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
/**
|
||||
* OpenIdConnectAuthenticationFilter constructor
|
||||
*/
|
||||
protected OIDCAuthenticationFilter() {
|
||||
public OIDCAuthenticationFilter() {
|
||||
super(FILTER_PROCESSES_URL);
|
||||
targetSuccessHandler.passthrough = super.getSuccessHandler();
|
||||
super.setAuthenticationSuccessHandler(targetSuccessHandler);
|
||||
|
@ -140,7 +163,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
}
|
||||
|
||||
if (symmetricCacheService == null) {
|
||||
symmetricCacheService = new SymmetricCacheService();
|
||||
symmetricCacheService = new SymmetricKeyJWTValidatorCacheService();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -216,8 +239,6 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
throw new AuthenticationServiceException("No issuer found: " + issuer);
|
||||
}
|
||||
|
||||
session.setAttribute(ISSUER_SESSION_VARIABLE, issuer);
|
||||
|
||||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||
if (serverConfig == null) {
|
||||
logger.error("No server configuration found for issuer: " + issuer);
|
||||
|
@ -225,6 +246,8 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
}
|
||||
|
||||
|
||||
session.setAttribute(ISSUER_SESSION_VARIABLE, serverConfig.getIssuer());
|
||||
|
||||
RegisteredClient clientConfig = clients.getClientConfiguration(serverConfig);
|
||||
if (clientConfig == null) {
|
||||
logger.error("No client configuration found for issuer: " + issuer);
|
||||
|
@ -234,7 +257,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
String redirectUri = null;
|
||||
if (clientConfig.getRegisteredRedirectUri() != null && clientConfig.getRegisteredRedirectUri().size() == 1) {
|
||||
// if there's a redirect uri configured (and only one), use that
|
||||
redirectUri = clientConfig.getRegisteredRedirectUri().toArray(new String[] {})[0];
|
||||
redirectUri = Iterables.getOnlyElement(clientConfig.getRegisteredRedirectUri());
|
||||
} else {
|
||||
// otherwise our redirect URI is this current URL, with no query parameters
|
||||
redirectUri = request.getRequestURL().toString();
|
||||
|
@ -249,7 +272,27 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
Map<String, String> options = authOptions.getOptions(serverConfig, clientConfig, request);
|
||||
|
||||
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
|
||||
// if we're using PKCE, handle the challenge here
|
||||
if (clientConfig.getCodeChallengeMethod() != null) {
|
||||
String codeVerifier = createCodeVerifier(session);
|
||||
options.put("code_challenge_method", clientConfig.getCodeChallengeMethod().getName());
|
||||
if (clientConfig.getCodeChallengeMethod().equals(PKCEAlgorithm.plain)) {
|
||||
options.put("code_challenge", codeVerifier);
|
||||
} else if (clientConfig.getCodeChallengeMethod().equals(PKCEAlgorithm.S256)) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
String hash = Base64URL.encode(digest.digest(codeVerifier.getBytes(StandardCharsets.US_ASCII))).toString();
|
||||
options.put("code_challenge", hash);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, issResp.getLoginHint());
|
||||
|
||||
logger.debug("Auth Request: " + authRequest);
|
||||
|
||||
|
@ -272,11 +315,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
// check for state, if it doesn't match we bail early
|
||||
String storedState = getStoredState(session);
|
||||
if (!Strings.isNullOrEmpty(storedState)) {
|
||||
String state = request.getParameter("state");
|
||||
if (!storedState.equals(state)) {
|
||||
throw new AuthenticationServiceException("State parameter mismatch on return. Expected " + storedState + " got " + state);
|
||||
}
|
||||
String requestState = request.getParameter("state");
|
||||
if (storedState == null || !storedState.equals(requestState)) {
|
||||
throw new AuthenticationServiceException("State parameter mismatch on return. Expected " + storedState + " got " + requestState);
|
||||
}
|
||||
|
||||
// look up the issuer that we set out to talk to
|
||||
|
@ -286,9 +327,15 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
|
||||
final RegisteredClient clientConfig = clients.getClientConfiguration(serverConfig);
|
||||
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("grant_type", "authorization_code");
|
||||
form.add("code", authorizationCode);
|
||||
form.setAll(authOptions.getTokenOptions(serverConfig, clientConfig, request));
|
||||
|
||||
String codeVerifier = getStoredCodeVerifier(session);
|
||||
if (codeVerifier != null) {
|
||||
form.add("code_verifier", codeVerifier);
|
||||
}
|
||||
|
||||
String redirectUri = getStoredSessionString(session, REDIRECT_URI_SESION_VARIABLE);
|
||||
if (redirectUri != null) {
|
||||
|
@ -296,9 +343,15 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
}
|
||||
|
||||
// Handle Token Endpoint interaction
|
||||
HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
|
||||
httpClient.getParams().setParameter("http.socket.timeout", new Integer(httpSocketTimeout));
|
||||
if(httpClient == null) {
|
||||
httpClient = HttpClientBuilder.create()
|
||||
.useSystemProperties()
|
||||
.setDefaultRequestConfig(RequestConfig.custom()
|
||||
.setSocketTimeout(httpSocketTimeout)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
|
||||
|
@ -312,9 +365,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
|
||||
ClientHttpRequest httpRequest = super.createRequest(url, method);
|
||||
httpRequest.getHeaders().add("Authorization",
|
||||
String.format("Basic %s", Base64.encode(String.format("%s:%s", clientConfig.getClientId(), clientConfig.getClientSecret())) ));
|
||||
|
||||
|
||||
String.format("Basic %s", Base64.encode(String.format("%s:%s",
|
||||
UriUtils.encodePathSegment(clientConfig.getClientId(), "UTF-8"),
|
||||
UriUtils.encodePathSegment(clientConfig.getClientSecret(), "UTF-8")))));
|
||||
|
||||
return httpRequest;
|
||||
}
|
||||
|
@ -327,13 +380,13 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
// do a symmetric secret signed JWT for auth
|
||||
|
||||
|
||||
JwtSigningAndValidationService signer = null;
|
||||
JWTSigningAndValidationService signer = null;
|
||||
JWSAlgorithm alg = clientConfig.getTokenEndpointAuthSigningAlg();
|
||||
|
||||
if (SECRET_JWT.equals(clientConfig.getTokenEndpointAuthMethod()) &&
|
||||
(alg.equals(JWSAlgorithm.HS256)
|
||||
|| alg.equals(JWSAlgorithm.HS384)
|
||||
|| alg.equals(JWSAlgorithm.HS512))) {
|
||||
(JWSAlgorithm.HS256.equals(alg)
|
||||
|| JWSAlgorithm.HS384.equals(alg)
|
||||
|| JWSAlgorithm.HS512.equals(alg))) {
|
||||
|
||||
// generate one based on client secret
|
||||
signer = symmetricCacheService.getSymmetricValidtor(clientConfig.getClient());
|
||||
|
@ -342,27 +395,35 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
// needs to be wired in to the bean
|
||||
signer = authenticationSignerService;
|
||||
|
||||
if (alg == null) {
|
||||
alg = authenticationSignerService.getDefaultSigningAlgorithm();
|
||||
}
|
||||
}
|
||||
|
||||
if (signer == null) {
|
||||
throw new AuthenticationServiceException("Couldn't find required signer service for use with private key auth.");
|
||||
}
|
||||
|
||||
JWTClaimsSet claimsSet = new JWTClaimsSet();
|
||||
JWTClaimsSet.Builder claimsSet = new JWTClaimsSet.Builder();
|
||||
|
||||
claimsSet.setIssuer(clientConfig.getClientId());
|
||||
claimsSet.setSubject(clientConfig.getClientId());
|
||||
claimsSet.setAudience(Lists.newArrayList(serverConfig.getTokenEndpointUri()));
|
||||
claimsSet.issuer(clientConfig.getClientId());
|
||||
claimsSet.subject(clientConfig.getClientId());
|
||||
claimsSet.audience(Lists.newArrayList(serverConfig.getTokenEndpointUri()));
|
||||
claimsSet.jwtID(UUID.randomUUID().toString());
|
||||
|
||||
// TODO: make this configurable
|
||||
Date exp = new Date(System.currentTimeMillis() + (60 * 1000)); // auth good for 60 seconds
|
||||
claimsSet.setExpirationTime(exp);
|
||||
claimsSet.expirationTime(exp);
|
||||
|
||||
Date now = new Date(System.currentTimeMillis());
|
||||
claimsSet.setIssueTime(now);
|
||||
claimsSet.setNotBeforeTime(now);
|
||||
claimsSet.issueTime(now);
|
||||
claimsSet.notBeforeTime(now);
|
||||
|
||||
SignedJWT jwt = new SignedJWT(new JWSHeader(alg), claimsSet);
|
||||
JWSHeader header = new JWSHeader(alg, null, null, null, null, null, null, null, null, null,
|
||||
signer.getDefaultSignerKeyId(),
|
||||
null, null);
|
||||
SignedJWT jwt = new SignedJWT(header, claimsSet.build());
|
||||
|
||||
signer.signJwt(jwt, alg);
|
||||
|
||||
|
@ -383,15 +444,13 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
|
||||
try {
|
||||
jsonString = restTemplate.postForObject(serverConfig.getTokenEndpointUri(), form, String.class);
|
||||
} catch (HttpClientErrorException httpClientErrorException) {
|
||||
} catch (RestClientException e) {
|
||||
|
||||
// Handle error
|
||||
|
||||
logger.error("Token Endpoint error response: "
|
||||
+ httpClientErrorException.getStatusText() + " : "
|
||||
+ httpClientErrorException.getMessage());
|
||||
logger.error("Token Endpoint error response: " + e.getMessage());
|
||||
|
||||
throw new AuthenticationServiceException("Unable to obtain Access Token: " + httpClientErrorException.getMessage());
|
||||
throw new AuthenticationServiceException("Unable to obtain Access Token: " + e.getMessage());
|
||||
}
|
||||
|
||||
logger.debug("from TokenEndpoint jsonString = " + jsonString);
|
||||
|
@ -444,10 +503,10 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
JWT idToken = JWTParser.parse(idTokenValue);
|
||||
|
||||
// validate our ID Token over a number of tests
|
||||
ReadOnlyJWTClaimsSet idClaims = idToken.getJWTClaimsSet();
|
||||
JWTClaimsSet idClaims = idToken.getJWTClaimsSet();
|
||||
|
||||
// check the signature
|
||||
JwtSigningAndValidationService jwtValidator = null;
|
||||
JWTSigningAndValidationService jwtValidator = null;
|
||||
|
||||
Algorithm tokenAlg = idToken.getHeader().getAlgorithm();
|
||||
|
||||
|
@ -465,7 +524,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
throw new AuthenticationServiceException("Unsigned ID tokens can only be used if explicitly configured in client.");
|
||||
}
|
||||
|
||||
if (tokenAlg != null && !tokenAlg.equals(JWSAlgorithm.NONE)) {
|
||||
if (tokenAlg != null && !tokenAlg.equals(Algorithm.NONE)) {
|
||||
throw new AuthenticationServiceException("Unsigned token received, expected signature with " + tokenAlg);
|
||||
}
|
||||
} else if (idToken instanceof SignedJWT) {
|
||||
|
@ -556,13 +615,11 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
|
||||
}
|
||||
|
||||
// pull the subject (user id) out as a claim on the id_token
|
||||
// construct an PendingOIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
||||
|
||||
String userId = idClaims.getSubject();
|
||||
|
||||
// construct an OIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
||||
|
||||
OIDCAuthenticationToken token = new OIDCAuthenticationToken(userId, idClaims.getIssuer(), serverConfig, idTokenValue, accessTokenValue, refreshTokenValue);
|
||||
PendingOIDCAuthenticationToken token = new PendingOIDCAuthenticationToken(idClaims.getSubject(), idClaims.getIssuer(),
|
||||
serverConfig,
|
||||
idToken, accessTokenValue, refreshTokenValue);
|
||||
|
||||
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
||||
|
||||
|
@ -593,7 +650,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
String errorDescription = request.getParameter("error_description");
|
||||
String errorURI = request.getParameter("error_uri");
|
||||
|
||||
throw new AuthenticationServiceException("Error from Authorization Endpoint: " + error + " " + errorDescription + " " + errorURI);
|
||||
throw new AuthorizationEndpointException(error, errorDescription, errorURI);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,6 +710,26 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
return getStoredSessionString(session, STATE_SESSION_VARIABLE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a random code challenge and store it in the session
|
||||
* @param session
|
||||
* @return
|
||||
*/
|
||||
protected static String createCodeVerifier(HttpSession session) {
|
||||
String challenge = new BigInteger(50, new SecureRandom()).toString(16);
|
||||
session.setAttribute(CODE_VERIFIER_SESSION_VARIABLE, challenge);
|
||||
return challenge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the stored challenge from our session
|
||||
* @param session
|
||||
* @return
|
||||
*/
|
||||
protected static String getStoredCodeVerifier(HttpSession session) {
|
||||
return getStoredSessionString(session, CODE_VERIFIER_SESSION_VARIABLE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
|
||||
|
@ -685,7 +762,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
if (!Strings.isNullOrEmpty(target)) {
|
||||
session.removeAttribute(TARGET_SESSION_VARIABLE);
|
||||
|
||||
if (deepLinkFilter != null) {
|
||||
target = deepLinkFilter.filter(target);
|
||||
}
|
||||
|
||||
response.sendRedirect(target);
|
||||
} else {
|
||||
|
@ -795,11 +874,11 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
|||
this.authOptions = authOptions;
|
||||
}
|
||||
|
||||
public SymmetricCacheService getSymmetricCacheService() {
|
||||
public SymmetricKeyJWTValidatorCacheService getSymmetricCacheService() {
|
||||
return symmetricCacheService;
|
||||
}
|
||||
|
||||
public void setSymmetricCacheService(SymmetricCacheService symmetricCacheService) {
|
||||
public void setSymmetricCacheService(SymmetricKeyJWTValidatorCacheService symmetricCacheService) {
|
||||
this.symmetricCacheService = symmetricCacheService;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,31 +14,36 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author nemonik
|
||||
* @author nemonik, Justin Richer
|
||||
*
|
||||
*/
|
||||
public class OIDCAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(OIDCAuthenticationProvider.class);
|
||||
|
||||
private UserInfoFetcher userInfoFetcher = new UserInfoFetcher();
|
||||
|
||||
private GrantedAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
|
||||
private OIDCAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
|
@ -46,43 +52,65 @@ public class OIDCAuthenticationProvider implements AuthenticationProvider {
|
|||
* authenticate(org.springframework.security.core.Authentication)
|
||||
*/
|
||||
@Override
|
||||
public Authentication authenticate(final Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
|
||||
|
||||
if (!supports(authentication.getClass())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (authentication instanceof OIDCAuthenticationToken) {
|
||||
if (authentication instanceof PendingOIDCAuthenticationToken) {
|
||||
|
||||
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
||||
PendingOIDCAuthenticationToken token = (PendingOIDCAuthenticationToken) authentication;
|
||||
|
||||
Collection<SubjectIssuerGrantedAuthority> authorities = Lists.newArrayList(new SubjectIssuerGrantedAuthority(token.getSub(), token.getIssuer()));
|
||||
// get the ID Token value out
|
||||
JWT idToken = token.getIdToken();
|
||||
|
||||
// load the user info if we can
|
||||
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
||||
|
||||
if (userInfo == null) {
|
||||
// TODO: user Info not found -- error?
|
||||
// user info not found -- could be an error, could be fine
|
||||
} else {
|
||||
// if we found userinfo, double check it
|
||||
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
|
||||
// the userinfo came back and the user_id fields don't match what was in the id_token
|
||||
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + token.getSub() + " / " + userInfo.getSub());
|
||||
}
|
||||
}
|
||||
|
||||
return new OIDCAuthenticationToken(token.getSub(),
|
||||
token.getIssuer(),
|
||||
userInfo, authoritiesMapper.mapAuthorities(authorities),
|
||||
token.getIdTokenValue(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
||||
return createAuthenticationToken(token, authoritiesMapper.mapAuthorities(idToken, userInfo), userInfo);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this function to return a different kind of Authentication, processes the authorities differently,
|
||||
* or do post-processing based on the UserInfo object.
|
||||
*
|
||||
* @param token
|
||||
* @param authorities
|
||||
* @param userInfo
|
||||
* @return
|
||||
*/
|
||||
protected Authentication createAuthenticationToken(PendingOIDCAuthenticationToken token, Collection<? extends GrantedAuthority> authorities, UserInfo userInfo) {
|
||||
return new OIDCAuthenticationToken(token.getSub(),
|
||||
token.getIssuer(),
|
||||
userInfo, authorities,
|
||||
token.getIdToken(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userInfoFetcher
|
||||
*/
|
||||
public void setUserInfoFetcher(UserInfoFetcher userInfoFetcher) {
|
||||
this.userInfoFetcher = userInfoFetcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authoritiesMapper
|
||||
*/
|
||||
public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
|
||||
public void setAuthoritiesMapper(OIDCAuthoritiesMapper authoritiesMapper) {
|
||||
this.authoritiesMapper = authoritiesMapper;
|
||||
}
|
||||
|
||||
|
@ -95,6 +123,6 @@ public class OIDCAuthenticationProvider implements AuthenticationProvider {
|
|||
*/
|
||||
@Override
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return OIDCAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
return PendingOIDCAuthenticationToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface OIDCAuthoritiesMapper {
|
||||
|
||||
/**
|
||||
* @param idToken the ID Token (parsed as a JWT, cannot be @null)
|
||||
* @param userInfo userInfo of the current user (could be @null)
|
||||
* @return the set of authorities to map to this user
|
||||
*/
|
||||
Collection<? extends GrantedAuthority> mapAuthorities(JWT idToken, UserInfo userInfo);
|
||||
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +12,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,19 +14,22 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration.UserInfoTokenMethod;
|
||||
import org.mitre.openid.connect.model.DefaultUserInfo;
|
||||
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -37,19 +41,58 @@ import org.springframework.util.MultiValueMap;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* Utility class to fetch userinfo from the userinfo endpoint, if available.
|
||||
* Utility class to fetch userinfo from the userinfo endpoint, if available. Caches the results.
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class UserInfoFetcher {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(UserInfoFetcher.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(UserInfoFetcher.class);
|
||||
|
||||
public UserInfo loadUserInfo(final OIDCAuthenticationToken token) {
|
||||
private LoadingCache<PendingOIDCAuthenticationToken, UserInfo> cache;
|
||||
|
||||
public UserInfoFetcher() {
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public UserInfoFetcher(HttpClient httpClient) {
|
||||
cache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
|
||||
.maximumSize(100)
|
||||
.build(new UserInfoLoader(httpClient));
|
||||
}
|
||||
|
||||
public UserInfo loadUserInfo(final PendingOIDCAuthenticationToken token) {
|
||||
try {
|
||||
return cache.get(token);
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Couldn't load User Info from token: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class UserInfoLoader extends CacheLoader<PendingOIDCAuthenticationToken, UserInfo> {
|
||||
private HttpComponentsClientHttpRequestFactory factory;
|
||||
|
||||
UserInfoLoader(HttpClient httpClient) {
|
||||
this.factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserInfo load(final PendingOIDCAuthenticationToken token) throws URISyntaxException {
|
||||
|
||||
ServerConfiguration serverConfiguration = token.getServerConfiguration();
|
||||
|
||||
|
@ -63,13 +106,6 @@ public class UserInfoFetcher {
|
|||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// if we got this far, try to actually get the userinfo
|
||||
HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
|
||||
String userInfoString = null;
|
||||
|
||||
if (serverConfiguration.getUserInfoTokenMethod() == null || serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.HEADER)) {
|
||||
|
@ -86,7 +122,7 @@ public class UserInfoFetcher {
|
|||
userInfoString = restTemplate.getForObject(serverConfiguration.getUserInfoUri(), String.class);
|
||||
|
||||
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.FORM)) {
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("access_token", token.getAccessTokenValue());
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(factory);
|
||||
|
@ -104,18 +140,18 @@ public class UserInfoFetcher {
|
|||
|
||||
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
|
||||
|
||||
UserInfo userInfo = DefaultUserInfo.fromJson(userInfoJson);
|
||||
UserInfo userInfo = fromJson(userInfoJson);
|
||||
|
||||
return userInfo;
|
||||
} else {
|
||||
// didn't get anything, return null
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error fetching userinfo", e);
|
||||
return null;
|
||||
// didn't get anything throw exception
|
||||
throw new IllegalArgumentException("Unable to load user info");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected UserInfo fromJson(JsonObject userInfoJson) {
|
||||
return DefaultUserInfo.fromJson(userInfoJson);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,14 +14,14 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.keypublisher;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.openid.connect.view.JwkKeyListView;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.openid.connect.view.JWKSetView;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
|
@ -37,13 +38,13 @@ import com.nimbusds.jose.jwk.JWK;
|
|||
*/
|
||||
public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
||||
|
||||
private JwtSigningAndValidationService signingAndValidationService;
|
||||
private JWTSigningAndValidationService signingAndValidationService;
|
||||
|
||||
private String jwkPublishUrl;
|
||||
|
||||
private BeanDefinitionRegistry registry;
|
||||
|
||||
private String jwkViewName = "jwkKeyList";
|
||||
private String jwkViewName = JWKSetView.VIEWNAME;
|
||||
|
||||
/**
|
||||
* If the jwkPublishUrl field is set on this bean, set up a listener on that URL to publish keys.
|
||||
|
@ -61,13 +62,13 @@ public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
|||
clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl());
|
||||
|
||||
// randomize view name to make sure it doesn't conflict with local views
|
||||
jwkViewName = "jwkKeyList-" + UUID.randomUUID().toString();
|
||||
jwkViewName = JWKSetView.VIEWNAME + "-" + UUID.randomUUID().toString();
|
||||
viewResolver.addPropertyValue("jwkViewName", jwkViewName);
|
||||
|
||||
// view bean
|
||||
BeanDefinitionBuilder jwkView = BeanDefinitionBuilder.rootBeanDefinition(JwkKeyListView.class);
|
||||
registry.registerBeanDefinition("jwkKeyList", jwkView.getBeanDefinition());
|
||||
viewResolver.addPropertyReference("jwk", "jwkKeyList");
|
||||
BeanDefinitionBuilder jwkView = BeanDefinitionBuilder.rootBeanDefinition(JWKSetView.class);
|
||||
registry.registerBeanDefinition(JWKSetView.VIEWNAME, jwkView.getBeanDefinition());
|
||||
viewResolver.addPropertyReference("jwk", JWKSetView.VIEWNAME);
|
||||
}
|
||||
|
||||
registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition());
|
||||
|
@ -114,14 +115,14 @@ public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
|
|||
/**
|
||||
* @return the signingAndValidationService
|
||||
*/
|
||||
public JwtSigningAndValidationService getSigningAndValidationService() {
|
||||
public JWTSigningAndValidationService getSigningAndValidationService() {
|
||||
return signingAndValidationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signingAndValidationService the signingAndValidationService to set
|
||||
*/
|
||||
public void setSigningAndValidationService(JwtSigningAndValidationService signingAndValidationService) {
|
||||
public void setSigningAndValidationService(JWTSigningAndValidationService signingAndValidationService) {
|
||||
this.signingAndValidationService = signingAndValidationService;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -28,7 +29,8 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
|
||||
/**
|
||||
*
|
||||
* This service provides any extra options that need to be passed to the authentication request.
|
||||
* This service provides any extra options that need to be passed to the authentication request,
|
||||
* either through the authorization endpoint (getOptions) or the token endpoint (getTokenOptions).
|
||||
* These options may depend on the server configuration, client configuration, or HTTP request.
|
||||
*
|
||||
* @author jricher
|
||||
|
@ -36,6 +38,24 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
*/
|
||||
public interface AuthRequestOptionsService {
|
||||
|
||||
/**
|
||||
* The set of options needed at the authorization endpoint.
|
||||
*
|
||||
* @param server
|
||||
* @param client
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> getOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* The set of options needed at the token endpoint.
|
||||
*
|
||||
* @param server
|
||||
* @param client
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public Map<String, String> getTokenOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -25,6 +26,8 @@ import org.mitre.oauth2.model.RegisteredClient;
|
|||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
|
||||
/**
|
||||
* Builds a URL string to the IdP's authorization endpoint.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
|
@ -36,8 +39,9 @@ public interface AuthRequestUrlBuilder {
|
|||
* @param redirectUri
|
||||
* @param nonce
|
||||
* @param state
|
||||
* @param loginHint
|
||||
* @return
|
||||
*/
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options);
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -24,7 +25,7 @@ import java.util.Set;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.oauth2.model.RegisteredClient;
|
||||
import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
|
||||
import org.mitre.openid.connect.client.service.ClientConfigurationService;
|
||||
|
@ -39,6 +40,8 @@ import org.springframework.http.MediaType;
|
|||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
@ -55,7 +58,10 @@ import com.google.gson.JsonObject;
|
|||
*/
|
||||
public class DynamicRegistrationClientConfigurationService implements ClientConfigurationService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(DynamicRegistrationClientConfigurationService.class);
|
||||
|
||||
private LoadingCache<ServerConfiguration, RegisteredClient> clients;
|
||||
|
||||
|
@ -63,29 +69,30 @@ public class DynamicRegistrationClientConfigurationService implements ClientConf
|
|||
|
||||
private RegisteredClient template;
|
||||
|
||||
private Set<String> whitelist = new HashSet<String>();
|
||||
private Set<String> blacklist = new HashSet<String>();
|
||||
private Set<String> whitelist = new HashSet<>();
|
||||
private Set<String> blacklist = new HashSet<>();
|
||||
|
||||
public DynamicRegistrationClientConfigurationService() {
|
||||
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader());
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public DynamicRegistrationClientConfigurationService(HttpClient httpClient) {
|
||||
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader(httpClient));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredClient getClientConfiguration(ServerConfiguration issuer) {
|
||||
try {
|
||||
if (!whitelist.isEmpty() && !whitelist.contains(issuer)) {
|
||||
if (!whitelist.isEmpty() && !whitelist.contains(issuer.getIssuer())) {
|
||||
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + issuer);
|
||||
}
|
||||
|
||||
if (blacklist.contains(issuer)) {
|
||||
if (blacklist.contains(issuer.getIssuer())) {
|
||||
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
|
||||
}
|
||||
|
||||
return clients.get(issuer);
|
||||
} catch (UncheckedExecutionException ue) {
|
||||
logger.warn("Unable to get client configuration", ue);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Unable to get client configuration", e);
|
||||
return null;
|
||||
}
|
||||
|
@ -166,10 +173,17 @@ public class DynamicRegistrationClientConfigurationService implements ClientConf
|
|||
*
|
||||
*/
|
||||
public class DynamicClientRegistrationLoader extends CacheLoader<ServerConfiguration, RegisteredClient> {
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory;
|
||||
private Gson gson = new Gson(); // note that this doesn't serialize nulls by default
|
||||
|
||||
public DynamicClientRegistrationLoader() {
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public DynamicClientRegistrationLoader(HttpClient httpClient) {
|
||||
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RegisteredClient load(ServerConfiguration serverConfig) throws Exception {
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
@ -186,10 +200,10 @@ public class DynamicRegistrationClientConfigurationService implements ClientConf
|
|||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<String>(serializedClient, headers);
|
||||
HttpEntity<String> entity = new HttpEntity<>(serializedClient, headers);
|
||||
|
||||
try {
|
||||
String registered = restTemplate.postForObject(serverConfig.getRegistrationEndpointUri(), entity, String.class);
|
||||
// TODO: handle HTTP errors
|
||||
|
||||
RegisteredClient client = ClientDetailsEntityJsonProcessor.parseRegistered(registered);
|
||||
|
||||
|
@ -197,6 +211,9 @@ public class DynamicRegistrationClientConfigurationService implements ClientConf
|
|||
registeredClientService.save(serverConfig.getIssuer(), client);
|
||||
|
||||
return client;
|
||||
} catch (RestClientException rce) {
|
||||
throw new InvalidClientException("Error registering client with server");
|
||||
}
|
||||
} else {
|
||||
|
||||
if (knownClient.getClientId() == null) {
|
||||
|
@ -206,14 +223,18 @@ public class DynamicRegistrationClientConfigurationService implements ClientConf
|
|||
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, knownClient.getRegistrationAccessToken()));
|
||||
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<String>(headers);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
try {
|
||||
String registered = restTemplate.exchange(knownClient.getRegistrationClientUri(), HttpMethod.GET, entity, String.class).getBody();
|
||||
// TODO: handle HTTP errors
|
||||
|
||||
RegisteredClient client = ClientDetailsEntityJsonProcessor.parseRegistered(registered);
|
||||
|
||||
return client;
|
||||
} catch (RestClientException rce) {
|
||||
throw new InvalidClientException("Error loading previously registered client information from server");
|
||||
}
|
||||
} else {
|
||||
// it's got a client ID from the store, don't bother trying to load it
|
||||
return knownClient;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,25 +14,25 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsBoolean;
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsEncryptionMethodList;
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsJweAlgorithmList;
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsJwsAlgorithmList;
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsString;
|
||||
import static org.mitre.discovery.util.JsonUtils.getAsStringList;
|
||||
import static org.mitre.util.JsonUtils.getAsBoolean;
|
||||
import static org.mitre.util.JsonUtils.getAsEncryptionMethodList;
|
||||
import static org.mitre.util.JsonUtils.getAsJweAlgorithmList;
|
||||
import static org.mitre.util.JsonUtils.getAsJwsAlgorithmList;
|
||||
import static org.mitre.util.JsonUtils.getAsString;
|
||||
import static org.mitre.util.JsonUtils.getAsStringList;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.openid.connect.client.service.ServerConfigurationService;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -57,17 +58,24 @@ import com.google.gson.JsonParser;
|
|||
*/
|
||||
public class DynamicServerConfigurationService implements ServerConfigurationService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
|
||||
|
||||
// map of issuer -> server configuration, loaded dynamically from service discovery
|
||||
private LoadingCache<String, ServerConfiguration> servers;
|
||||
|
||||
private Set<String> whitelist = new HashSet<String>();
|
||||
private Set<String> blacklist = new HashSet<String>();
|
||||
private Set<String> whitelist = new HashSet<>();
|
||||
private Set<String> blacklist = new HashSet<>();
|
||||
|
||||
public DynamicServerConfigurationService() {
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public DynamicServerConfigurationService(HttpClient httpClient) {
|
||||
// initialize the cache
|
||||
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher());
|
||||
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher(httpClient));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -111,11 +119,8 @@ public class DynamicServerConfigurationService implements ServerConfigurationSer
|
|||
}
|
||||
|
||||
return servers.get(issuer);
|
||||
} catch (UncheckedExecutionException ue) {
|
||||
logger.warn("Couldn't load configuration for " + issuer, ue);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load configuration for " + issuer, e);
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Couldn't load configuration for " + issuer + ": " + e);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -126,10 +131,13 @@ public class DynamicServerConfigurationService implements ServerConfigurationSer
|
|||
*
|
||||
*/
|
||||
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory;
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
OpenIDConnectServiceConfigurationFetcher(HttpClient httpClient) {
|
||||
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerConfiguration load(String issuer) throws Exception {
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
|
@ -154,7 +162,7 @@ public class DynamicServerConfigurationService implements ServerConfigurationSer
|
|||
}
|
||||
|
||||
if (!issuer.equals(o.get("issuer").getAsString())) {
|
||||
throw new IllegalStateException("Discovered issuers didn't match, expected " + issuer + " got " + o.get("issuer").getAsString());
|
||||
logger.info("Issuer used for discover was " + issuer + " but final issuer is " + o.get("issuer").getAsString());
|
||||
}
|
||||
|
||||
conf.setIssuer(o.get("issuer").getAsString());
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -24,7 +25,7 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||
import org.mitre.oauth2.model.RegisteredClient;
|
||||
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
|
||||
|
@ -32,6 +33,7 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWEHeader;
|
||||
|
@ -54,33 +56,38 @@ public class EncryptedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequestUrl(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, java.lang.String, java.lang.String, java.lang.String, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
|
||||
|
||||
// create our signed JWT for the request object
|
||||
JWTClaimsSet claims = new JWTClaimsSet();
|
||||
JWTClaimsSet.Builder claims = new JWTClaimsSet.Builder();
|
||||
|
||||
//set parameters to JwtClaims
|
||||
claims.setClaim("response_type", "code");
|
||||
claims.setClaim("client_id", clientConfig.getClientId());
|
||||
claims.setClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||
claims.claim("response_type", "code");
|
||||
claims.claim("client_id", clientConfig.getClientId());
|
||||
claims.claim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||
|
||||
// build our redirect URI
|
||||
claims.setClaim("redirect_uri", redirectUri);
|
||||
claims.claim("redirect_uri", redirectUri);
|
||||
|
||||
// this comes back in the id token
|
||||
claims.setClaim("nonce", nonce);
|
||||
claims.claim("nonce", nonce);
|
||||
|
||||
// this comes back in the auth request return
|
||||
claims.setClaim("state", state);
|
||||
claims.claim("state", state);
|
||||
|
||||
// Optional parameters
|
||||
for (Entry<String, String> option : options.entrySet()) {
|
||||
claims.setClaim(option.getKey(), option.getValue());
|
||||
claims.claim(option.getKey(), option.getValue());
|
||||
}
|
||||
|
||||
EncryptedJWT jwt = new EncryptedJWT(new JWEHeader(alg, enc), claims);
|
||||
// if there's a login hint, send it
|
||||
if (!Strings.isNullOrEmpty(loginHint)) {
|
||||
claims.claim("login_hint", loginHint);
|
||||
}
|
||||
|
||||
JwtEncryptionAndDecryptionService encryptor = encrypterService.getEncrypter(serverConfig.getJwksUri());
|
||||
EncryptedJWT jwt = new EncryptedJWT(new JWEHeader(alg, enc), claims.build());
|
||||
|
||||
JWTEncryptionAndDecryptionService encryptor = encrypterService.getEncrypter(serverConfig.getJwksUri());
|
||||
|
||||
encryptor.encryptJwt(jwt);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -36,6 +37,38 @@ import com.google.common.collect.Sets;
|
|||
*/
|
||||
public class HybridIssuerService implements IssuerService {
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.openid.connect.client.service.impl.ThirdPartyIssuerService#getAccountChooserUrl()
|
||||
*/
|
||||
public String getAccountChooserUrl() {
|
||||
return thirdPartyIssuerService.getAccountChooserUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accountChooserUrl
|
||||
* @see org.mitre.openid.connect.client.service.impl.ThirdPartyIssuerService#setAccountChooserUrl(java.lang.String)
|
||||
*/
|
||||
public void setAccountChooserUrl(String accountChooserUrl) {
|
||||
thirdPartyIssuerService.setAccountChooserUrl(accountChooserUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.openid.connect.client.service.impl.WebfingerIssuerService#isForceHttps()
|
||||
*/
|
||||
public boolean isForceHttps() {
|
||||
return webfingerIssuerService.isForceHttps();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forceHttps
|
||||
* @see org.mitre.openid.connect.client.service.impl.WebfingerIssuerService#setForceHttps(boolean)
|
||||
*/
|
||||
public void setForceHttps(boolean forceHttps) {
|
||||
webfingerIssuerService.setForceHttps(forceHttps);
|
||||
}
|
||||
|
||||
private ThirdPartyIssuerService thirdPartyIssuerService = new ThirdPartyIssuerService();
|
||||
private WebfingerIssuerService webfingerIssuerService = new WebfingerIssuerService();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -31,7 +32,7 @@ import org.mitre.openid.connect.client.service.RegisteredClientService;
|
|||
*/
|
||||
public class InMemoryRegisteredClientService implements RegisteredClientService {
|
||||
|
||||
private Map<String, RegisteredClient> clients = new HashMap<String, RegisteredClient>();
|
||||
private Map<String, RegisteredClient> clients = new HashMap<>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.RegisteredClientService#getByIssuer(java.lang.String)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,14 +14,13 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
@ -50,7 +50,10 @@ import com.google.gson.JsonSerializer;
|
|||
*/
|
||||
public class JsonFileRegisteredClientService implements RegisteredClientService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonFileRegisteredClientService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(JsonFileRegisteredClientService.class);
|
||||
|
||||
private Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(RegisteredClient.class, new JsonSerializer<RegisteredClient>() {
|
||||
|
@ -70,7 +73,7 @@ public class JsonFileRegisteredClientService implements RegisteredClientService
|
|||
|
||||
private File file;
|
||||
|
||||
private Map<String, RegisteredClient> clients = new HashMap<String, RegisteredClient>();
|
||||
private Map<String, RegisteredClient> clients = new HashMap<>();
|
||||
|
||||
public JsonFileRegisteredClientService(String filename) {
|
||||
this.file = new File(filename);
|
||||
|
@ -97,6 +100,7 @@ public class JsonFileRegisteredClientService implements RegisteredClientService
|
|||
/**
|
||||
* Sync the map of clients out to disk.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private void write() {
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
|
@ -110,8 +114,6 @@ public class JsonFileRegisteredClientService implements RegisteredClientService
|
|||
|
||||
out.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.error("Could not write to output file", e);
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not write to output file", e);
|
||||
}
|
||||
|
@ -120,6 +122,7 @@ public class JsonFileRegisteredClientService implements RegisteredClientService
|
|||
/**
|
||||
* Load the map in from disk.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private void load() {
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
|
@ -132,8 +135,6 @@ public class JsonFileRegisteredClientService implements RegisteredClientService
|
|||
|
||||
in.close();
|
||||
|
||||
} catch (FileNotFoundException e) {
|
||||
logger.error("Could not read from input file", e);
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not read from input file", e);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -30,6 +31,7 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -44,7 +46,7 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequest(javax.servlet.http.HttpServletRequest, org.mitre.openid.connect.config.ServerConfiguration, org.springframework.security.oauth2.provider.ClientDetails)
|
||||
*/
|
||||
@Override
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
|
||||
try {
|
||||
|
||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||
|
@ -63,6 +65,11 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
uriBuilder.addParameter(option.getKey(), option.getValue());
|
||||
}
|
||||
|
||||
// if there's a login hint, send it
|
||||
if (!Strings.isNullOrEmpty(loginHint)) {
|
||||
uriBuilder.addParameter("login_hint", loginHint);
|
||||
}
|
||||
|
||||
return uriBuilder.build().toString();
|
||||
|
||||
} catch (URISyntaxException e) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -24,13 +25,15 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.RegisteredClient;
|
||||
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
@ -41,41 +44,49 @@ import com.nimbusds.jwt.SignedJWT;
|
|||
*/
|
||||
public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||
|
||||
private JwtSigningAndValidationService signingAndValidationService;
|
||||
private JWTSigningAndValidationService signingAndValidationService;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequestUrl(org.mitre.openid.connect.config.ServerConfiguration, org.springframework.security.oauth2.provider.ClientDetails, java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
|
||||
|
||||
// create our signed JWT for the request object
|
||||
JWTClaimsSet claims = new JWTClaimsSet();
|
||||
JWTClaimsSet.Builder claims = new JWTClaimsSet.Builder();
|
||||
|
||||
//set parameters to JwtClaims
|
||||
claims.setClaim("response_type", "code");
|
||||
claims.setClaim("client_id", clientConfig.getClientId());
|
||||
claims.setClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||
claims.claim("response_type", "code");
|
||||
claims.claim("client_id", clientConfig.getClientId());
|
||||
claims.claim("scope", Joiner.on(" ").join(clientConfig.getScope()));
|
||||
|
||||
// build our redirect URI
|
||||
claims.setClaim("redirect_uri", redirectUri);
|
||||
claims.claim("redirect_uri", redirectUri);
|
||||
|
||||
// this comes back in the id token
|
||||
claims.setClaim("nonce", nonce);
|
||||
claims.claim("nonce", nonce);
|
||||
|
||||
// this comes back in the auth request return
|
||||
claims.setClaim("state", state);
|
||||
claims.claim("state", state);
|
||||
|
||||
// Optional parameters
|
||||
for (Entry<String, String> option : options.entrySet()) {
|
||||
claims.setClaim(option.getKey(), option.getValue());
|
||||
claims.claim(option.getKey(), option.getValue());
|
||||
}
|
||||
|
||||
// if there's a login hint, send it
|
||||
if (!Strings.isNullOrEmpty(loginHint)) {
|
||||
claims.claim("login_hint", loginHint);
|
||||
}
|
||||
|
||||
JWSAlgorithm alg = clientConfig.getRequestObjectSigningAlg();
|
||||
if (alg == null) {
|
||||
alg = signingAndValidationService.getDefaultSigningAlgorithm();
|
||||
}
|
||||
|
||||
SignedJWT jwt = new SignedJWT(new JWSHeader(signingAndValidationService.getDefaultSigningAlgorithm()), claims);
|
||||
SignedJWT jwt = new SignedJWT(new JWSHeader(alg), claims.build());
|
||||
|
||||
signingAndValidationService.signJwt(jwt);
|
||||
signingAndValidationService.signJwt(jwt, alg);
|
||||
|
||||
try {
|
||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||
|
@ -91,14 +102,14 @@ public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
|||
/**
|
||||
* @return the signingAndValidationService
|
||||
*/
|
||||
public JwtSigningAndValidationService getSigningAndValidationService() {
|
||||
public JWTSigningAndValidationService getSigningAndValidationService() {
|
||||
return signingAndValidationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param signingAndValidationService the signingAndValidationService to set
|
||||
*/
|
||||
public void setSigningAndValidationService(JwtSigningAndValidationService signingAndValidationService) {
|
||||
public void setSigningAndValidationService(JWTSigningAndValidationService signingAndValidationService) {
|
||||
this.signingAndValidationService = signingAndValidationService;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -37,7 +38,8 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
*/
|
||||
public class StaticAuthRequestOptionsService implements AuthRequestOptionsService {
|
||||
|
||||
private Map<String, String> options = new HashMap<String, String>();
|
||||
private Map<String, String> options = new HashMap<>();
|
||||
private Map<String, String> tokenOptions = new HashMap<>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.AuthRequestOptionsService#getOptions(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, javax.servlet.http.HttpServletRequest)
|
||||
|
@ -47,8 +49,16 @@ public class StaticAuthRequestOptionsService implements AuthRequestOptionsServic
|
|||
return options;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.AuthRequestOptionsService#getTokenOptions(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, javax.servlet.http.HttpServletRequest)
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> getTokenOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request) {
|
||||
return tokenOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the options
|
||||
* @return the options object directly
|
||||
*/
|
||||
public Map<String, String> getOptions() {
|
||||
return options;
|
||||
|
@ -61,6 +71,18 @@ public class StaticAuthRequestOptionsService implements AuthRequestOptionsServic
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the tokenOptions
|
||||
*/
|
||||
public Map<String, String> getTokenOptions() {
|
||||
return tokenOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenOptions the tokenOptions to set
|
||||
*/
|
||||
public void setTokenOptions(Map<String, String> tokenOptions) {
|
||||
this.tokenOptions = tokenOptions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -66,7 +67,7 @@ public class StaticClientConfigurationService implements ClientConfigurationServ
|
|||
}
|
||||
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() {
|
||||
if (clients == null || clients.isEmpty()) {
|
||||
throw new IllegalArgumentException("Clients map cannot be null or empty");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -60,7 +61,7 @@ public class StaticServerConfigurationService implements ServerConfigurationServ
|
|||
}
|
||||
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() {
|
||||
if (servers == null || servers.isEmpty()) {
|
||||
throw new IllegalArgumentException("Servers map cannot be null or empty.");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -60,7 +61,7 @@ public class StaticSingleIssuerService implements IssuerService {
|
|||
}
|
||||
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (Strings.isNullOrEmpty(issuer)) {
|
||||
throw new IllegalArgumentException("Issuer must not be null or empty.");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -44,8 +45,8 @@ public class ThirdPartyIssuerService implements IssuerService {
|
|||
|
||||
private String accountChooserUrl;
|
||||
|
||||
private Set<String> whitelist = new HashSet<String>();
|
||||
private Set<String> blacklist = new HashSet<String>();
|
||||
private Set<String> whitelist = new HashSet<>();
|
||||
private Set<String> blacklist = new HashSet<>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
|
||||
|
@ -127,11 +128,8 @@ public class ThirdPartyIssuerService implements IssuerService {
|
|||
this.blacklist = blacklist;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
public void afterPropertiesSet() {
|
||||
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
|
||||
throw new IllegalArgumentException("Account Chooser URL cannot be null or empty");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -27,7 +28,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.discovery.util.WebfingerURLNormalizer;
|
||||
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
|
||||
import org.mitre.openid.connect.client.service.IssuerService;
|
||||
|
@ -35,6 +36,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
|
||||
|
@ -46,6 +48,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
|
|||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
|
@ -55,13 +58,26 @@ import com.google.gson.JsonParser;
|
|||
*/
|
||||
public class WebfingerIssuerService implements IssuerService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
|
||||
|
||||
// map of user input -> issuer, loaded dynamically from webfinger discover
|
||||
private LoadingCache<UriComponents, String> issuers;
|
||||
private LoadingCache<String, LoadingResult> issuers;
|
||||
|
||||
private Set<String> whitelist = new HashSet<String>();
|
||||
private Set<String> blacklist = new HashSet<String>();
|
||||
// private data shuttle class to get back two bits of info from the cache loader
|
||||
private class LoadingResult {
|
||||
public String loginHint;
|
||||
public String issuer;
|
||||
public LoadingResult(String loginHint, String issuer) {
|
||||
this.loginHint = loginHint;
|
||||
this.issuer = issuer;
|
||||
}
|
||||
}
|
||||
|
||||
private Set<String> whitelist = new HashSet<>();
|
||||
private Set<String> blacklist = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Name of the incoming parameter to check for discovery purposes.
|
||||
|
@ -73,8 +89,17 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
*/
|
||||
private String loginPageUrl;
|
||||
|
||||
/**
|
||||
* Strict enfocement of "https"
|
||||
*/
|
||||
private boolean forceHttps = true;
|
||||
|
||||
public WebfingerIssuerService() {
|
||||
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher());
|
||||
this(HttpClientBuilder.create().useSystemProperties().build());
|
||||
}
|
||||
|
||||
public WebfingerIssuerService(HttpClient httpClient) {
|
||||
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher(httpClient));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
@ -86,21 +111,18 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
String identifier = request.getParameter(parameterName);
|
||||
if (!Strings.isNullOrEmpty(identifier)) {
|
||||
try {
|
||||
String issuer = issuers.get(WebfingerURLNormalizer.normalizeResource(identifier));
|
||||
if (!whitelist.isEmpty() && !whitelist.contains(issuer)) {
|
||||
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + issuer);
|
||||
LoadingResult lr = issuers.get(identifier);
|
||||
if (!whitelist.isEmpty() && !whitelist.contains(lr.issuer)) {
|
||||
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + lr.issuer);
|
||||
}
|
||||
|
||||
if (blacklist.contains(issuer)) {
|
||||
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
|
||||
if (blacklist.contains(lr.issuer)) {
|
||||
throw new AuthenticationServiceException("Issuer was in blacklist: " + lr.issuer);
|
||||
}
|
||||
|
||||
return new IssuerServiceResponse(issuer, null, null);
|
||||
} catch (UncheckedExecutionException ue) {
|
||||
logger.warn("Issue fetching issuer for user input: " + identifier, ue);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Issue fetching issuer for user input: " + identifier, e);
|
||||
return new IssuerServiceResponse(lr.issuer, lr.loginHint, request.getParameter("target_link_uri"));
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Issue fetching issuer for user input: " + identifier + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -167,27 +189,52 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
this.blacklist = blacklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the forceHttps
|
||||
*/
|
||||
public boolean isForceHttps() {
|
||||
return forceHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param forceHttps the forceHttps to set
|
||||
*/
|
||||
public void setForceHttps(boolean forceHttps) {
|
||||
this.forceHttps = forceHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class WebfingerIssuerFetcher extends CacheLoader<UriComponents, String> {
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private class WebfingerIssuerFetcher extends CacheLoader<String, LoadingResult> {
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory;
|
||||
private JsonParser parser = new JsonParser();
|
||||
|
||||
WebfingerIssuerFetcher(HttpClient httpClient) {
|
||||
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String load(UriComponents key) throws Exception {
|
||||
public LoadingResult load(String identifier) throws Exception {
|
||||
|
||||
UriComponents key = WebfingerURLNormalizer.normalizeResource(identifier);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
// construct the URL to go to
|
||||
|
||||
// preserving http scheme is strictly for demo system use only.
|
||||
String scheme = key.getScheme();
|
||||
|
||||
// preserving http scheme is strictly for demo system use only.
|
||||
if (!Strings.isNullOrEmpty(scheme) &&scheme.equals("http")) {
|
||||
scheme = "http://"; // add on colon and slashes.
|
||||
logger.warn("Webfinger endpoint MUST use the https URI scheme.");
|
||||
if (forceHttps) {
|
||||
throw new IllegalArgumentException("Scheme must not be 'http'");
|
||||
} else {
|
||||
logger.warn("Webfinger endpoint MUST use the https URI scheme, overriding by configuration");
|
||||
scheme = "http://"; // add on colon and slashes.
|
||||
}
|
||||
} else {
|
||||
// otherwise we don't know the scheme, assume HTTPS
|
||||
scheme = "https://";
|
||||
}
|
||||
|
||||
|
@ -199,19 +246,17 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
+ "/.well-known/webfinger"
|
||||
+ (Strings.isNullOrEmpty(key.getQuery()) ? "" : "?" + key.getQuery())
|
||||
);
|
||||
builder.addParameter("resource", key.toString());
|
||||
builder.addParameter("resource", identifier);
|
||||
builder.addParameter("rel", "http://openid.net/specs/connect/1.0/issuer");
|
||||
|
||||
try {
|
||||
|
||||
// do the fetch
|
||||
logger.info("Loading: " + builder.toString());
|
||||
String webfingerResponse = restTemplate.getForObject(builder.build(), String.class);
|
||||
|
||||
// TODO: catch and handle HTTP errors
|
||||
|
||||
JsonElement json = parser.parse(webfingerResponse);
|
||||
|
||||
// TODO: catch and handle JSON errors
|
||||
|
||||
if (json != null && json.isJsonObject()) {
|
||||
// find the issuer
|
||||
JsonArray links = json.getAsJsonObject().get("links").getAsJsonArray();
|
||||
|
@ -223,22 +268,34 @@ public class WebfingerIssuerService implements IssuerService {
|
|||
&& linkObj.get("rel").getAsString().equals("http://openid.net/specs/connect/1.0/issuer")) {
|
||||
|
||||
// we found the issuer, return it
|
||||
return linkObj.get("href").getAsString();
|
||||
String href = linkObj.get("href").getAsString();
|
||||
|
||||
if (identifier.equals(href)
|
||||
|| identifier.startsWith("http")) {
|
||||
// try to avoid sending a URL as the login hint
|
||||
return new LoadingResult(null, href);
|
||||
} else {
|
||||
// otherwise pass back whatever the user typed as a login hint
|
||||
return new LoadingResult(identifier, href);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (JsonParseException | RestClientException e) {
|
||||
logger.warn("Failure in fetching webfinger input", e.getMessage());
|
||||
}
|
||||
|
||||
// we couldn't find it
|
||||
// we couldn't find it!
|
||||
|
||||
if (key.getScheme().equals("http") || key.getScheme().equals("https")) {
|
||||
// if it looks like HTTP then punt and return the input
|
||||
logger.warn("Returning normalized input string as issuer, hoping for the best: " + key.toString());
|
||||
return key.toString();
|
||||
// if it looks like HTTP then punt: return the input, hope for the best
|
||||
logger.warn("Returning normalized input string as issuer, hoping for the best: " + identifier);
|
||||
return new LoadingResult(null, identifier);
|
||||
} else {
|
||||
// if it's not HTTP, give up
|
||||
logger.warn("Couldn't find issuer: " + key.toString());
|
||||
return null;
|
||||
logger.warn("Couldn't find issuer: " + identifier);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.introspectingfilter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class TestOAuth2AccessTokenImpl {
|
||||
|
||||
private static String tokenString = "thisisatokenstring";
|
||||
|
||||
private static Set<String> scopes = ImmutableSet.of("bar", "foo");
|
||||
private static String scopeString = "foo bar";
|
||||
|
||||
private static Date exp = new Date(123 * 1000L);
|
||||
private static Long expVal = 123L;
|
||||
|
||||
@Test
|
||||
public void testFullToken() {
|
||||
|
||||
|
||||
JsonObject tokenObj = new JsonObject();
|
||||
tokenObj.addProperty("active", true);
|
||||
tokenObj.addProperty("scope", scopeString);
|
||||
tokenObj.addProperty("exp", expVal);
|
||||
tokenObj.addProperty("sub", "subject");
|
||||
tokenObj.addProperty("client_id", "123-456-789");
|
||||
|
||||
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
|
||||
|
||||
assertThat(tok.getScope(), is(equalTo(scopes)));
|
||||
assertThat(tok.getExpiration(), is(equalTo(exp)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullExp() {
|
||||
|
||||
|
||||
JsonObject tokenObj = new JsonObject();
|
||||
tokenObj.addProperty("active", true);
|
||||
tokenObj.addProperty("scope", scopeString);
|
||||
tokenObj.addProperty("sub", "subject");
|
||||
tokenObj.addProperty("client_id", "123-456-789");
|
||||
|
||||
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
|
||||
|
||||
assertThat(tok.getScope(), is(equalTo(scopes)));
|
||||
assertThat(tok.getExpiration(), is(equalTo(null)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullScopes() {
|
||||
|
||||
|
||||
JsonObject tokenObj = new JsonObject();
|
||||
tokenObj.addProperty("active", true);
|
||||
tokenObj.addProperty("exp", expVal);
|
||||
tokenObj.addProperty("sub", "subject");
|
||||
tokenObj.addProperty("client_id", "123-456-789");
|
||||
|
||||
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
|
||||
|
||||
assertThat(tok.getScope(), is(equalTo(Collections.EMPTY_SET)));
|
||||
assertThat(tok.getExpiration(), is(equalTo(exp)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullScopesNullExp() {
|
||||
|
||||
|
||||
JsonObject tokenObj = new JsonObject();
|
||||
tokenObj.addProperty("active", true);
|
||||
tokenObj.addProperty("sub", "subject");
|
||||
tokenObj.addProperty("client_id", "123-456-789");
|
||||
|
||||
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
|
||||
|
||||
assertThat(tok.getScope(), is(equalTo(Collections.EMPTY_SET)));
|
||||
assertThat(tok.getExpiration(), is(equalTo(null)));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.introspectingfilter.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class TestScopeBasedIntrospectionAuthoritiesGranter {
|
||||
|
||||
private JsonObject introspectionResponse;
|
||||
|
||||
private ScopeBasedIntrospectionAuthoritiesGranter granter = new ScopeBasedIntrospectionAuthoritiesGranter();
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
introspectionResponse = new JsonObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.mitre.oauth2.introspectingfilter.service.impl.ScopeBasedIntrospectionAuthoritiesGranter#getAuthorities(com.google.gson.JsonObject)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetAuthoritiesJsonObject_withScopes() {
|
||||
introspectionResponse.addProperty("scope", "foo bar baz batman");
|
||||
|
||||
List<GrantedAuthority> expected = new ArrayList<>();
|
||||
expected.add(new SimpleGrantedAuthority("ROLE_API"));
|
||||
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_foo"));
|
||||
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_bar"));
|
||||
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_baz"));
|
||||
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_batman"));
|
||||
|
||||
List<GrantedAuthority> authorities = granter.getAuthorities(introspectionResponse);
|
||||
|
||||
assertTrue(authorities.containsAll(expected));
|
||||
assertTrue(expected.containsAll(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.mitre.oauth2.introspectingfilter.service.impl.ScopeBasedIntrospectionAuthoritiesGranter#getAuthorities(com.google.gson.JsonObject)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetAuthoritiesJsonObject_withoutScopes() {
|
||||
|
||||
List<GrantedAuthority> expected = new ArrayList<>();
|
||||
expected.add(new SimpleGrantedAuthority("ROLE_API"));
|
||||
|
||||
List<GrantedAuthority> authorities = granter.getAuthorities(introspectionResponse);
|
||||
|
||||
assertTrue(authorities.containsAll(expected));
|
||||
assertTrue(expected.containsAll(authorities));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class TestOIDCAuthenticationFilter {
|
||||
|
||||
private OIDCAuthenticationFilter filter = new OIDCAuthenticationFilter();
|
||||
|
||||
@Test
|
||||
public void attemptAuthentication_error() throws Exception {
|
||||
|
||||
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
|
||||
Mockito.when(request.getParameter("error")).thenReturn("Error");
|
||||
Mockito.when(request.getParameter("error_description")).thenReturn("Description");
|
||||
Mockito.when(request.getParameter("error_uri")).thenReturn("http://example.com");
|
||||
|
||||
try {
|
||||
filter.attemptAuthentication(request, mock(HttpServletResponse.class));
|
||||
|
||||
fail("AuthorizationEndpointException expected.");
|
||||
}
|
||||
catch (AuthorizationEndpointException exception) {
|
||||
assertThat(exception.getMessage(),
|
||||
is("Error from Authorization Endpoint: Error Description http://example.com"));
|
||||
|
||||
assertThat(exception.getError(), is("Error"));
|
||||
assertThat(exception.getErrorDescription(), is("Description"));
|
||||
assertThat(exception.getErrorURI(), is("http://example.com"));
|
||||
|
||||
assertThat(exception, is(instanceOf(AuthenticationServiceException.class)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,14 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -32,6 +28,12 @@ import org.mockito.Mock;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,15 +14,10 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
@ -32,6 +28,12 @@ import org.mockito.Mock;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,12 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
|
@ -31,6 +29,10 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
@ -68,7 +70,27 @@ public class TestPlainAuthRequestUrlBuilder {
|
|||
|
||||
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
||||
|
||||
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options);
|
||||
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options, null);
|
||||
|
||||
assertThat(actualUrl, equalTo(expectedUrl));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildAuthRequestUrl_withLoginHint() {
|
||||
|
||||
String expectedUrl = "https://server.example.com/authorize?" +
|
||||
"response_type=code" +
|
||||
"&client_id=s6BhdRkqt3" +
|
||||
"&scope=openid+profile" + // plus sign used for space per application/x-www-form-encoded standard
|
||||
"&redirect_uri=https%3A%2F%2Fclient.example.org%2F" +
|
||||
"&nonce=34fasf3ds" +
|
||||
"&state=af0ifjsldkj" +
|
||||
"&foo=bar" +
|
||||
"&login_hint=bob";
|
||||
|
||||
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
||||
|
||||
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options, "bob");
|
||||
|
||||
assertThat(actualUrl, equalTo(expectedUrl));
|
||||
}
|
||||
|
@ -80,7 +102,7 @@ public class TestPlainAuthRequestUrlBuilder {
|
|||
|
||||
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
||||
|
||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
|
||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,13 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -31,7 +28,7 @@ import java.util.Map;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.impl.DefaultJWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.RegisteredClient;
|
||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||
import org.mockito.Mockito;
|
||||
|
@ -44,12 +41,16 @@ import com.google.common.collect.Maps;
|
|||
import com.google.common.collect.Sets;
|
||||
import com.nimbusds.jose.Algorithm;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.KeyUse;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
@ -82,19 +83,20 @@ public class TestSignedAuthRequestUrlBuilder {
|
|||
"9Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
|
||||
private String alg = "RS256";
|
||||
private String kid = "2011-04-29";
|
||||
private String loginHint = "bob";
|
||||
|
||||
private DefaultJwtSigningAndValidationService signingAndValidationService;
|
||||
private DefaultJWTSigningAndValidationService signingAndValidationService;
|
||||
|
||||
private SignedAuthRequestUrlBuilder urlBuilder = new SignedAuthRequestUrlBuilder();
|
||||
|
||||
@Before
|
||||
public void prepare() throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
|
||||
RSAKey key = new RSAKey(new Base64URL(n), new Base64URL(e), new Base64URL(d), KeyUse.SIGNATURE, null, new Algorithm(alg), kid, null, null, null);
|
||||
RSAKey key = new RSAKey(new Base64URL(n), new Base64URL(e), new Base64URL(d), KeyUse.SIGNATURE, null, new Algorithm(alg), kid, null, null, null, null, null);
|
||||
Map<String, JWK> keys = Maps.newHashMap();
|
||||
keys.put("client", key);
|
||||
|
||||
signingAndValidationService = new DefaultJwtSigningAndValidationService(keys);
|
||||
signingAndValidationService = new DefaultJWTSigningAndValidationService(keys);
|
||||
signingAndValidationService.setDefaultSignerKeyId("client");
|
||||
signingAndValidationService.setDefaultSigningAlgorithmName(alg);
|
||||
|
||||
|
@ -116,7 +118,7 @@ public class TestSignedAuthRequestUrlBuilder {
|
|||
@Test
|
||||
public void buildAuthRequestUrl() {
|
||||
|
||||
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
|
||||
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, null);
|
||||
|
||||
// parsing the result
|
||||
UriComponentsBuilder builder = null;
|
||||
|
@ -129,7 +131,7 @@ public class TestSignedAuthRequestUrlBuilder {
|
|||
|
||||
UriComponents components = builder.build();
|
||||
String jwtString = components.getQueryParams().get("request").get(0);
|
||||
ReadOnlyJWTClaimsSet claims = null;
|
||||
JWTClaimsSet claims = null;
|
||||
|
||||
try {
|
||||
SignedJWT jwt = SignedJWT.parse(jwtString);
|
||||
|
@ -152,11 +154,51 @@ public class TestSignedAuthRequestUrlBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildAuthRequestUrl_withLoginHint() {
|
||||
|
||||
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, loginHint);
|
||||
|
||||
// parsing the result
|
||||
UriComponentsBuilder builder = null;
|
||||
|
||||
try {
|
||||
builder = UriComponentsBuilder.fromUri(new URI(requestUri));
|
||||
} catch (URISyntaxException e1) {
|
||||
fail("URISyntaxException was thrown.");
|
||||
}
|
||||
|
||||
UriComponents components = builder.build();
|
||||
String jwtString = components.getQueryParams().get("request").get(0);
|
||||
JWTClaimsSet claims = null;
|
||||
|
||||
try {
|
||||
SignedJWT jwt = SignedJWT.parse(jwtString);
|
||||
claims = jwt.getJWTClaimsSet();
|
||||
} catch (ParseException e) {
|
||||
fail("ParseException was thrown.");
|
||||
}
|
||||
|
||||
assertEquals(responseType, claims.getClaim("response_type"));
|
||||
assertEquals(clientConfig.getClientId(), claims.getClaim("client_id"));
|
||||
|
||||
List<String> scopeList = Arrays.asList(((String) claims.getClaim("scope")).split(" "));
|
||||
assertTrue(scopeList.containsAll(clientConfig.getScope()));
|
||||
|
||||
assertEquals(redirectUri, claims.getClaim("redirect_uri"));
|
||||
assertEquals(nonce, claims.getClaim("nonce"));
|
||||
assertEquals(state, claims.getClaim("state"));
|
||||
for (String claim : options.keySet()) {
|
||||
assertEquals(options.get(claim), claims.getClaim(claim));
|
||||
}
|
||||
assertEquals(loginHint, claims.getClaim("login_hint"));
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationServiceException.class)
|
||||
public void buildAuthRequestUrl_badUri() {
|
||||
|
||||
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
|
||||
|
||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
|
||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,15 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -34,6 +29,13 @@ import org.mockito.Mock;
|
|||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
@ -56,7 +58,7 @@ public class TestStaticClientConfigurationService {
|
|||
|
||||
service = new StaticClientConfigurationService();
|
||||
|
||||
Map<String, RegisteredClient> clients = new HashMap<String, RegisteredClient>();
|
||||
Map<String, RegisteredClient> clients = new HashMap<>();
|
||||
clients.put(issuer, mockClient);
|
||||
|
||||
service.setClients(clients);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,15 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -32,6 +27,13 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
|||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
@ -52,7 +54,7 @@ public class TestStaticServerConfigurationService {
|
|||
|
||||
service = new StaticServerConfigurationService();
|
||||
|
||||
Map<String, ServerConfiguration> servers = new HashMap<String, ServerConfiguration>();
|
||||
Map<String, ServerConfiguration> servers = new HashMap<>();
|
||||
servers.put(issuer, mockServerConfig);
|
||||
|
||||
service.setServers(servers);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,13 +14,9 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.openid.connect.client.service.impl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Before;
|
||||
|
@ -30,6 +27,11 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
|
|||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* @author wkim
|
||||
*
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2014 The MITRE Corporation
|
||||
and the MIT Kerberos and Internet Trust Consortium
|
||||
Copyright 2018 The MIT Internet Trust Consortium
|
||||
|
||||
Portions copyright 2011-2013 The MITRE Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2014 The MITRE Corporation
|
||||
and the MIT Kerberos and Internet Trust Consortium
|
||||
Copyright 2018 The MIT Internet Trust Consortium
|
||||
|
||||
Portions copyright 2011-2013 The MITRE Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -20,7 +22,7 @@
|
|||
<parent>
|
||||
<artifactId>openid-connect-parent</artifactId>
|
||||
<groupId>org.mitre</groupId>
|
||||
<version>1.1.9</version>
|
||||
<version>1.3.5-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>openid-connect-common</artifactId>
|
||||
|
@ -30,65 +32,85 @@
|
|||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>${org.springframework-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>${org.springframework-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
<version>${spring.security.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.2.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth</groupId>
|
||||
<version>2.0.0.M2</version>
|
||||
<artifactId>spring-security-oauth2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nimbusds</groupId>
|
||||
<artifactId>nimbus-jose-jwt</artifactId>
|
||||
<version>2.26.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.persistence</groupId>
|
||||
<artifactId>javax.persistence</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${org.slf4j-version}</version>
|
||||
</dependency>
|
||||
<!-- /Logging -->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>activation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract class for performing an operation on a potentially large
|
||||
* number of items by paging through the items in discreet chunks.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
* @author Colm Smyth.
|
||||
*/
|
||||
public abstract class AbstractPageOperationTemplate<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractPageOperationTemplate.class);
|
||||
|
||||
private static int DEFAULT_MAX_PAGES = 1000;
|
||||
private static long DEFAULT_MAX_TIME_MILLIS = 600000L; //10 Minutes
|
||||
|
||||
/**
|
||||
* int specifying the maximum number of
|
||||
* pages which should be fetched before
|
||||
* execution should terminate
|
||||
*/
|
||||
private int maxPages;
|
||||
|
||||
/**
|
||||
* long specifying the maximum execution time
|
||||
* in milliseconds
|
||||
*/
|
||||
private long maxTime;
|
||||
|
||||
/**
|
||||
* boolean specifying whether or not Exceptions
|
||||
* incurred performing the operation should be
|
||||
* swallowed during execution default true.
|
||||
*/
|
||||
private boolean swallowExceptions = true;
|
||||
|
||||
/**
|
||||
* String that is used for logging in final tallies.
|
||||
*/
|
||||
private String operationName = "";
|
||||
|
||||
|
||||
/**
|
||||
* default constructor which sets the value of
|
||||
* maxPages and maxTime to DEFAULT_MAX_PAGES and
|
||||
* DEFAULT_MAX_TIME_MILLIS respectively
|
||||
*/
|
||||
public AbstractPageOperationTemplate(String operationName){
|
||||
this(DEFAULT_MAX_PAGES, DEFAULT_MAX_TIME_MILLIS, operationName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new AbstractPageOperationTemplate with the
|
||||
* given maxPages and maxTime
|
||||
*
|
||||
* @param maxPages the maximum number of pages to fetch.
|
||||
* @param maxTime the maximum execution time.
|
||||
*/
|
||||
public AbstractPageOperationTemplate(int maxPages, long maxTime, String operationName){
|
||||
this.maxPages = maxPages;
|
||||
this.maxTime = maxTime;
|
||||
this.operationName = operationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the operation on each member of a page of results
|
||||
* retrieved through the fetch method. the method will execute
|
||||
* until either the maxPages or maxTime limit is reached or until
|
||||
* the fetch method returns no more results. Exceptions thrown
|
||||
* performing the operation on the item will be swallowed if the
|
||||
* swallowException (default true) field is set true.
|
||||
*/
|
||||
public void execute(){
|
||||
logger.debug("[" + getOperationName() + "] Starting execution of paged operation. maximum time: " + maxTime + ", maximum pages: " + maxPages);
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
long executionTime = 0;
|
||||
int i = 0;
|
||||
|
||||
int exceptionsSwallowedCount = 0;
|
||||
int operationsCompleted = 0;
|
||||
Set<String> exceptionsSwallowedClasses = new HashSet<String>();
|
||||
|
||||
|
||||
while (i< maxPages && executionTime < maxTime){
|
||||
Collection<T> page = fetchPage();
|
||||
if(page == null || page.size() == 0){
|
||||
break;
|
||||
}
|
||||
|
||||
for (T item : page) {
|
||||
try {
|
||||
doOperation(item);
|
||||
operationsCompleted++;
|
||||
} catch (Exception e){
|
||||
if(swallowExceptions){
|
||||
exceptionsSwallowedCount++;
|
||||
exceptionsSwallowedClasses.add(e.getClass().getName());
|
||||
logger.debug("Swallowing exception " + e.getMessage(), e);
|
||||
} else {
|
||||
logger.debug("Rethrowing exception " + e.getMessage());
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
executionTime = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
|
||||
finalReport(operationsCompleted, exceptionsSwallowedCount, exceptionsSwallowedClasses);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* method responsible for fetching
|
||||
* a page of items.
|
||||
*
|
||||
* @return the collection of items
|
||||
*/
|
||||
public abstract Collection<T> fetchPage();
|
||||
|
||||
/**
|
||||
* method responsible for performing desired
|
||||
* operation on a fetched page item.
|
||||
*
|
||||
* @param item the item
|
||||
*/
|
||||
protected abstract void doOperation(T item);
|
||||
|
||||
/**
|
||||
* Method responsible for final report of progress.
|
||||
* @return
|
||||
*/
|
||||
protected void finalReport(int operationsCompleted, int exceptionsSwallowedCount, Set<String> exceptionsSwallowedClasses) {
|
||||
if (operationsCompleted > 0 || exceptionsSwallowedCount > 0) {
|
||||
logger.info("[" + getOperationName() + "] Paged operation run: completed " + operationsCompleted + "; swallowed " + exceptionsSwallowedCount + " exceptions");
|
||||
}
|
||||
for(String className: exceptionsSwallowedClasses) {
|
||||
logger.warn("[" + getOperationName() + "] Paged operation swallowed at least one exception of type " + className);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxPages() {
|
||||
return maxPages;
|
||||
}
|
||||
|
||||
public void setMaxPages(int maxPages) {
|
||||
this.maxPages = maxPages;
|
||||
}
|
||||
|
||||
public long getMaxTime() {
|
||||
return maxTime;
|
||||
}
|
||||
|
||||
public void setMaxTime(long maxTime) {
|
||||
this.maxTime = maxTime;
|
||||
}
|
||||
|
||||
public boolean isSwallowExceptions() {
|
||||
return swallowExceptions;
|
||||
}
|
||||
|
||||
public void setSwallowExceptions(boolean swallowExceptions) {
|
||||
this.swallowExceptions = swallowExceptions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the operationName
|
||||
*/
|
||||
public String getOperationName() {
|
||||
return operationName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param operationName the operationName to set
|
||||
*/
|
||||
public void setOperationName(String operationName) {
|
||||
this.operationName = operationName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.data;
|
||||
|
||||
/**
|
||||
* Default implementation of PageCriteria which specifies
|
||||
* both page to be retrieved and page size in the constructor.
|
||||
*
|
||||
* @author Colm Smyth
|
||||
*/
|
||||
public class DefaultPageCriteria implements PageCriteria {
|
||||
|
||||
private static final int DEFAULT_PAGE_NUMBER = 0;
|
||||
private static final int DEFAULT_PAGE_SIZE = 100;
|
||||
|
||||
private int pageNumber;
|
||||
private int pageSize;
|
||||
|
||||
public DefaultPageCriteria(){
|
||||
this(DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE);
|
||||
}
|
||||
|
||||
public DefaultPageCriteria(int pageNumber, int pageSize) {
|
||||
this.pageNumber = pageNumber;
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageNumber() {
|
||||
return pageNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.data;
|
||||
|
||||
/**
|
||||
* Interface which defines page criteria for use in
|
||||
* a repository operation.
|
||||
*
|
||||
* @author Colm Smyth
|
||||
*/
|
||||
public interface PageCriteria {
|
||||
|
||||
public int getPageNumber();
|
||||
public int getPageSize();
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.discovery.util;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
|
@ -35,7 +36,10 @@ import com.google.common.base.Strings;
|
|||
*/
|
||||
public class WebfingerURLNormalizer {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WebfingerURLNormalizer.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(WebfingerURLNormalizer.class);
|
||||
|
||||
// pattern used to parse user input; we can't use the built-in java URI parser
|
||||
private static final Pattern pattern = Pattern.compile("^" +
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.jose;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
|
||||
/**
|
||||
*
|
||||
* Wrapper class for Nimbus JOSE objects to fit into JPA
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Embeddable
|
||||
public class JWEAlgorithmEmbed {
|
||||
|
||||
public static final JWEAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
private JWEAlgorithm algorithm;
|
||||
|
||||
public JWEAlgorithmEmbed() {
|
||||
|
||||
}
|
||||
|
||||
public JWEAlgorithmEmbed(JWEAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static JWEAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWEAlgorithmEmbed ent = new JWEAlgorithmEmbed();
|
||||
ent.setAlgorithmName(algorithmName);
|
||||
if (ent.getAlgorithm() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this algorithm, return null if no algorithm set.
|
||||
* @return
|
||||
*/
|
||||
@Basic
|
||||
public String getAlgorithmName() {
|
||||
if (algorithm != null) {
|
||||
return algorithm.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Calls JWEAlgorithm.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
public void setAlgorithmName(String algorithmName) {
|
||||
if (!Strings.isNullOrEmpty(algorithmName)) {
|
||||
algorithm = JWEAlgorithm.parse(algorithmName);
|
||||
} else {
|
||||
algorithm = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the algorithm
|
||||
*/
|
||||
@Transient
|
||||
public JWEAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param algorithm the algorithm to set
|
||||
*/
|
||||
public void setAlgorithm(JWEAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.jose;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Embeddable
|
||||
public class JWEEncryptionMethodEmbed {
|
||||
|
||||
public static final JWEEncryptionMethodEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
private EncryptionMethod algorithm;
|
||||
|
||||
public JWEEncryptionMethodEmbed() {
|
||||
|
||||
}
|
||||
|
||||
public JWEEncryptionMethodEmbed(EncryptionMethod algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static JWEEncryptionMethodEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWEEncryptionMethodEmbed ent = new JWEEncryptionMethodEmbed();
|
||||
ent.setAlgorithmName(algorithmName);
|
||||
if (ent.getAlgorithm() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this algorithm, return null if no algorithm set.
|
||||
* @return
|
||||
*/
|
||||
@Basic
|
||||
public String getAlgorithmName() {
|
||||
if (algorithm != null) {
|
||||
return algorithm.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Calls EncryptionMethod.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
public void setAlgorithmName(String algorithmName) {
|
||||
if (!Strings.isNullOrEmpty(algorithmName)) {
|
||||
algorithm = EncryptionMethod.parse(algorithmName);
|
||||
} else {
|
||||
algorithm = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWEEncryptionMethodEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the algorithm
|
||||
*/
|
||||
@Transient
|
||||
public EncryptionMethod getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param algorithm the algorithm to set
|
||||
*/
|
||||
public void setAlgorithm(EncryptionMethod algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.jose;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
|
||||
/**
|
||||
*
|
||||
* Wrapper class for Nimbus JOSE objects to fit into JPA
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Embeddable
|
||||
public class JWSAlgorithmEmbed {
|
||||
|
||||
public static final JWSAlgorithmEmbed NONE = getForAlgorithmName("none");
|
||||
|
||||
private JWSAlgorithm algorithm;
|
||||
|
||||
public JWSAlgorithmEmbed() {
|
||||
|
||||
}
|
||||
|
||||
public JWSAlgorithmEmbed(JWSAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param algorithmName
|
||||
* @return null if algorithmName is empty or null
|
||||
*/
|
||||
public static JWSAlgorithmEmbed getForAlgorithmName (String algorithmName) {
|
||||
JWSAlgorithmEmbed ent = new JWSAlgorithmEmbed();
|
||||
ent.setAlgorithmName(algorithmName);
|
||||
if (ent.getAlgorithm() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this algorithm, return null if no algorithm set.
|
||||
* @return
|
||||
*/
|
||||
@Basic
|
||||
public String getAlgorithmName() {
|
||||
if (algorithm != null) {
|
||||
return algorithm.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this algorithm.
|
||||
* Calls JWSAlgorithm.parse()
|
||||
* @param algorithmName
|
||||
*/
|
||||
public void setAlgorithmName(String algorithmName) {
|
||||
if (!Strings.isNullOrEmpty(algorithmName)) {
|
||||
algorithm = JWSAlgorithm.parse(algorithmName);
|
||||
} else {
|
||||
algorithm = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the algorithm
|
||||
*/
|
||||
@Transient
|
||||
public JWSAlgorithm getAlgorithm() {
|
||||
return algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param algorithm the algorithm to set
|
||||
*/
|
||||
public void setAlgorithm(JWSAlgorithm algorithm) {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JWSAlgorithmEmbed [algorithm=" + algorithm + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.jwt.assertion;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public interface AssertionValidator {
|
||||
|
||||
public boolean isValid(JWT assertion);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.jwt.assertion.impl;
|
||||
|
||||
import org.mitre.jwt.assertion.AssertionValidator;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* Reject all assertions passed in.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class NullAssertionValidator implements AssertionValidator {
|
||||
|
||||
/**
|
||||
* Reject all assertions passed in, always returns false.
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid(JWT assertion) {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.jwt.assertion.impl;
|
||||
|
||||
import java.text.ParseException;
|
||||
|
||||
import org.mitre.jwt.assertion.AssertionValidator;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
* Validates all assertions generated by this server
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Component("selfAssertionValidator")
|
||||
public class SelfAssertionValidator implements AssertionValidator {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(SelfAssertionValidator.class);
|
||||
|
||||
@Autowired
|
||||
private ConfigurationPropertiesBean config;
|
||||
|
||||
@Autowired
|
||||
private JWTSigningAndValidationService jwtService;
|
||||
|
||||
@Override
|
||||
public boolean isValid(JWT assertion) {
|
||||
if (!(assertion instanceof SignedJWT)) {
|
||||
// unsigned assertion
|
||||
return false;
|
||||
}
|
||||
|
||||
JWTClaimsSet claims;
|
||||
try {
|
||||
claims = assertion.getJWTClaimsSet();
|
||||
} catch (ParseException e) {
|
||||
logger.debug("Invalid assertion claims");
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure the issuer exists
|
||||
if (Strings.isNullOrEmpty(claims.getIssuer())) {
|
||||
logger.debug("No issuer for assertion, rejecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure the issuer is us
|
||||
if (!claims.getIssuer().equals(config.getIssuer())) {
|
||||
logger.debug("Issuer is not the same as this server, rejecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the signature based on our public key
|
||||
if (jwtService.validateSignature((SignedJWT) assertion)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.jwt.assertion.impl;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mitre.jwt.assertion.AssertionValidator;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
/**
|
||||
* Checks to see if the assertion was signed by a particular authority available from a whitelist
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class WhitelistedIssuerAssertionValidator implements AssertionValidator {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(WhitelistedIssuerAssertionValidator.class);
|
||||
|
||||
/**
|
||||
* Map of issuer -> JWKSetUri
|
||||
*/
|
||||
private Map<String, String> whitelist = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @return the whitelist
|
||||
*/
|
||||
public Map<String, String> getWhitelist() {
|
||||
return whitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param whitelist the whitelist to set
|
||||
*/
|
||||
public void setWhitelist(Map<String, String> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private JWKSetCacheService jwkCache;
|
||||
|
||||
@Override
|
||||
public boolean isValid(JWT assertion) {
|
||||
|
||||
if (!(assertion instanceof SignedJWT)) {
|
||||
// unsigned assertion
|
||||
return false;
|
||||
}
|
||||
|
||||
JWTClaimsSet claims;
|
||||
try {
|
||||
claims = assertion.getJWTClaimsSet();
|
||||
} catch (ParseException e) {
|
||||
logger.debug("Invalid assertion claims");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Strings.isNullOrEmpty(claims.getIssuer())) {
|
||||
logger.debug("No issuer for assertion, rejecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!whitelist.containsKey(claims.getIssuer())) {
|
||||
logger.debug("Issuer is not in whitelist, rejecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
String jwksUri = whitelist.get(claims.getIssuer());
|
||||
|
||||
JWTSigningAndValidationService validator = jwkCache.getValidator(jwksUri);
|
||||
|
||||
if (validator.validateSignature((SignedJWT) assertion)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.jwt.encryption.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -28,7 +29,7 @@ import com.nimbusds.jose.jwk.JWK;
|
|||
* @author wkim
|
||||
*
|
||||
*/
|
||||
public interface JwtEncryptionAndDecryptionService {
|
||||
public interface JWTEncryptionAndDecryptionService {
|
||||
|
||||
/**
|
||||
* Encrypts the JWT in place with the default encrypter.
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.jwt.encryption.service.impl;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -27,7 +28,7 @@ import java.util.Set;
|
|||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.mitre.jose.keystore.JWKSetKeyStore;
|
||||
import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -40,8 +41,12 @@ import com.nimbusds.jose.JWEEncrypter;
|
|||
import com.nimbusds.jose.JWEObject;
|
||||
import com.nimbusds.jose.crypto.DirectDecrypter;
|
||||
import com.nimbusds.jose.crypto.DirectEncrypter;
|
||||
import com.nimbusds.jose.crypto.ECDHDecrypter;
|
||||
import com.nimbusds.jose.crypto.ECDHEncrypter;
|
||||
import com.nimbusds.jose.crypto.RSADecrypter;
|
||||
import com.nimbusds.jose.crypto.RSAEncrypter;
|
||||
import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
|
||||
import com.nimbusds.jose.jwk.ECKey;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
|
@ -50,15 +55,18 @@ import com.nimbusds.jose.jwk.RSAKey;
|
|||
* @author wkim
|
||||
*
|
||||
*/
|
||||
public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAndDecryptionService {
|
||||
public class DefaultJWTEncryptionAndDecryptionService implements JWTEncryptionAndDecryptionService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DefaultJwtEncryptionAndDecryptionService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultJWTEncryptionAndDecryptionService.class);
|
||||
|
||||
// map of identifier to encrypter
|
||||
private Map<String, JWEEncrypter> encrypters = new HashMap<String, JWEEncrypter>();
|
||||
private Map<String, JWEEncrypter> encrypters = new HashMap<>();
|
||||
|
||||
// map of identifier to decrypter
|
||||
private Map<String, JWEDecrypter> decrypters = new HashMap<String, JWEDecrypter>();
|
||||
private Map<String, JWEDecrypter> decrypters = new HashMap<>();
|
||||
|
||||
private String defaultEncryptionKeyId;
|
||||
|
||||
|
@ -67,7 +75,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
private JWEAlgorithm defaultAlgorithm;
|
||||
|
||||
// map of identifier to key
|
||||
private Map<String, JWK> keys = new HashMap<String, JWK>();
|
||||
private Map<String, JWK> keys = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Build this service based on the keys given. All public keys will be used to make encrypters,
|
||||
|
@ -78,7 +86,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
* @throws InvalidKeySpecException
|
||||
* @throws JOSEException
|
||||
*/
|
||||
public DefaultJwtEncryptionAndDecryptionService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
public DefaultJWTEncryptionAndDecryptionService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
this.keys = keys;
|
||||
buildEncryptersAndDecrypters();
|
||||
}
|
||||
|
@ -92,7 +100,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
* @throws InvalidKeySpecException
|
||||
* @throws JOSEException
|
||||
*/
|
||||
public DefaultJwtEncryptionAndDecryptionService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
public DefaultJWTEncryptionAndDecryptionService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException {
|
||||
|
||||
// convert all keys in the keystore to a map based on key id
|
||||
for (JWK key : keyStore.getKeys()) {
|
||||
|
@ -109,12 +117,20 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
|
||||
|
||||
@PostConstruct
|
||||
public void afterPropertiesSet() throws NoSuchAlgorithmException, InvalidKeySpecException, JOSEException{
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
if (keys == null) {
|
||||
throw new IllegalArgumentException("Encryption and decryption service must have at least one key configured.");
|
||||
}
|
||||
try {
|
||||
buildEncryptersAndDecrypters();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalArgumentException("Encryption and decryption service could not find given algorithm.");
|
||||
} catch (InvalidKeySpecException e) {
|
||||
throw new IllegalArgumentException("Encryption and decryption service saw an invalid key specification.");
|
||||
} catch (JOSEException e) {
|
||||
throw new IllegalArgumentException("Encryption and decryption service was unable to process JOSE object.");
|
||||
}
|
||||
}
|
||||
|
||||
public String getDefaultEncryptionKeyId() {
|
||||
|
@ -212,23 +228,40 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
if (jwk instanceof RSAKey) {
|
||||
// build RSA encrypters and decrypters
|
||||
|
||||
RSAEncrypter encrypter = new RSAEncrypter(((RSAKey) jwk).toRSAPublicKey()); // there should always at least be the public key
|
||||
RSAEncrypter encrypter = new RSAEncrypter((RSAKey) jwk); // there should always at least be the public key
|
||||
encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
encrypters.put(id, encrypter);
|
||||
|
||||
if (jwk.isPrivate()) { // we can decrypt!
|
||||
RSADecrypter decrypter = new RSADecrypter(((RSAKey) jwk).toRSAPrivateKey());
|
||||
RSADecrypter decrypter = new RSADecrypter((RSAKey) jwk);
|
||||
decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
decrypters.put(id, decrypter);
|
||||
} else {
|
||||
logger.warn("No private key for key #" + jwk.getKeyID());
|
||||
}
|
||||
} else if (jwk instanceof ECKey) {
|
||||
|
||||
// build EC Encrypters and decrypters
|
||||
|
||||
ECDHEncrypter encrypter = new ECDHEncrypter((ECKey) jwk);
|
||||
encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
encrypters.put(id, encrypter);
|
||||
|
||||
if (jwk.isPrivate()) { // we can decrypt too
|
||||
ECDHDecrypter decrypter = new ECDHDecrypter((ECKey) jwk);
|
||||
decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
decrypters.put(id, decrypter);
|
||||
} else {
|
||||
logger.warn("No private key for key # " + jwk.getKeyID());
|
||||
}
|
||||
|
||||
// TODO: add support for EC keys
|
||||
|
||||
} else if (jwk instanceof OctetSequenceKey) {
|
||||
// build symmetric encrypters and decrypters
|
||||
|
||||
DirectEncrypter encrypter = new DirectEncrypter(((OctetSequenceKey) jwk).toByteArray());
|
||||
DirectDecrypter decrypter = new DirectDecrypter(((OctetSequenceKey) jwk).toByteArray());
|
||||
DirectEncrypter encrypter = new DirectEncrypter((OctetSequenceKey) jwk);
|
||||
encrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
DirectDecrypter decrypter = new DirectDecrypter((OctetSequenceKey) jwk);
|
||||
decrypter.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());
|
||||
|
||||
encrypters.put(id, encrypter);
|
||||
decrypters.put(id, decrypter);
|
||||
|
@ -242,7 +275,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
|
||||
@Override
|
||||
public Map<String, JWK> getAllPublicKeys() {
|
||||
Map<String, JWK> pubKeys = new HashMap<String, JWK>();
|
||||
Map<String, JWK> pubKeys = new HashMap<>();
|
||||
|
||||
// pull out all public keys
|
||||
for (String keyId : keys.keySet()) {
|
||||
|
@ -258,14 +291,14 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
|
||||
@Override
|
||||
public Collection<JWEAlgorithm> getAllEncryptionAlgsSupported() {
|
||||
Set<JWEAlgorithm> algs = new HashSet<JWEAlgorithm>();
|
||||
Set<JWEAlgorithm> algs = new HashSet<>();
|
||||
|
||||
for (JWEEncrypter encrypter : encrypters.values()) {
|
||||
algs.addAll(encrypter.supportedAlgorithms());
|
||||
algs.addAll(encrypter.supportedJWEAlgorithms());
|
||||
}
|
||||
|
||||
for (JWEDecrypter decrypter : decrypters.values()) {
|
||||
algs.addAll(decrypter.supportedAlgorithms());
|
||||
algs.addAll(decrypter.supportedJWEAlgorithms());
|
||||
}
|
||||
|
||||
return algs;
|
||||
|
@ -276,7 +309,7 @@ public class DefaultJwtEncryptionAndDecryptionService implements JwtEncryptionAn
|
|||
*/
|
||||
@Override
|
||||
public Collection<EncryptionMethod> getAllEncryptionEncsSupported() {
|
||||
Set<EncryptionMethod> encs = new HashSet<EncryptionMethod>();
|
||||
Set<EncryptionMethod> encs = new HashSet<>();
|
||||
|
||||
for (JWEEncrypter encrypter : encrypters.values()) {
|
||||
encs.addAll(encrypter.supportedEncryptionMethods());
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.jwt.signer.service;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -24,7 +25,7 @@ import com.nimbusds.jose.JWSAlgorithm;
|
|||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
public interface JwtSigningAndValidationService {
|
||||
public interface JWTSigningAndValidationService {
|
||||
|
||||
/**
|
||||
* Get all public keys for this service, mapped by their Key ID
|
||||
|
@ -74,6 +75,8 @@ public interface JwtSigningAndValidationService {
|
|||
*/
|
||||
public void signJwt(SignedJWT jwt, JWSAlgorithm alg);
|
||||
|
||||
public String getDefaultSignerKeyId();
|
||||
|
||||
/**
|
||||
* TODO: method to sign a jwt using a specified algorithm and a key id
|
||||
*/
|
|
@ -0,0 +1,155 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.jwt.signer.service.impl;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.mitre.jose.keystore.JWKSetKeyStore;
|
||||
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* Takes in a client and returns the appropriate validator or encrypter for
|
||||
* that client's registered key types.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class ClientKeyCacheService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ClientKeyCacheService.class);
|
||||
|
||||
@Autowired
|
||||
private JWKSetCacheService jwksUriCache = new JWKSetCacheService();
|
||||
|
||||
@Autowired
|
||||
private SymmetricKeyJWTValidatorCacheService symmetricCache = new SymmetricKeyJWTValidatorCacheService();
|
||||
|
||||
// cache of validators for by-value JWKs
|
||||
private LoadingCache<JWKSet, JWTSigningAndValidationService> jwksValidators;
|
||||
|
||||
// cache of encryptors for by-value JWKs
|
||||
private LoadingCache<JWKSet, JWTEncryptionAndDecryptionService> jwksEncrypters;
|
||||
|
||||
public ClientKeyCacheService() {
|
||||
this.jwksValidators = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
|
||||
.maximumSize(100)
|
||||
.build(new JWKSetVerifierBuilder());
|
||||
this.jwksEncrypters = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
|
||||
.maximumSize(100)
|
||||
.build(new JWKSetEncryptorBuilder());
|
||||
}
|
||||
|
||||
|
||||
public JWTSigningAndValidationService getValidator(ClientDetailsEntity client, JWSAlgorithm alg) {
|
||||
|
||||
try {
|
||||
if (alg.equals(JWSAlgorithm.RS256)
|
||||
|| alg.equals(JWSAlgorithm.RS384)
|
||||
|| alg.equals(JWSAlgorithm.RS512)
|
||||
|| alg.equals(JWSAlgorithm.ES256)
|
||||
|| alg.equals(JWSAlgorithm.ES384)
|
||||
|| alg.equals(JWSAlgorithm.ES512)
|
||||
|| alg.equals(JWSAlgorithm.PS256)
|
||||
|| alg.equals(JWSAlgorithm.PS384)
|
||||
|| alg.equals(JWSAlgorithm.PS512)) {
|
||||
|
||||
// asymmetric key
|
||||
if (client.getJwks() != null) {
|
||||
return jwksValidators.get(client.getJwks());
|
||||
} else if (!Strings.isNullOrEmpty(client.getJwksUri())) {
|
||||
return jwksUriCache.getValidator(client.getJwksUri());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
} else if (alg.equals(JWSAlgorithm.HS256)
|
||||
|| alg.equals(JWSAlgorithm.HS384)
|
||||
|| alg.equals(JWSAlgorithm.HS512)) {
|
||||
|
||||
// symmetric key
|
||||
|
||||
return symmetricCache.getSymmetricValidtor(client);
|
||||
|
||||
} else {
|
||||
|
||||
return null;
|
||||
}
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.error("Problem loading client validator", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public JWTEncryptionAndDecryptionService getEncrypter(ClientDetailsEntity client) {
|
||||
|
||||
try {
|
||||
if (client.getJwks() != null) {
|
||||
return jwksEncrypters.get(client.getJwks());
|
||||
} else if (!Strings.isNullOrEmpty(client.getJwksUri())) {
|
||||
return jwksUriCache.getEncrypter(client.getJwksUri());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.error("Problem loading client encrypter", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class JWKSetEncryptorBuilder extends CacheLoader<JWKSet, JWTEncryptionAndDecryptionService> {
|
||||
|
||||
@Override
|
||||
public JWTEncryptionAndDecryptionService load(JWKSet key) throws Exception {
|
||||
return new DefaultJWTEncryptionAndDecryptionService(new JWKSetKeyStore(key));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class JWKSetVerifierBuilder extends CacheLoader<JWKSet, JWTSigningAndValidationService> {
|
||||
|
||||
@Override
|
||||
public JWTSigningAndValidationService load(JWKSet key) throws Exception {
|
||||
return new DefaultJWTSigningAndValidationService(new JWKSetKeyStore(key));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.jwt.signer.service.impl;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
@ -26,7 +27,7 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
|
||||
import org.mitre.jose.keystore.JWKSetKeyStore;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -35,6 +36,8 @@ import com.nimbusds.jose.JOSEException;
|
|||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSSigner;
|
||||
import com.nimbusds.jose.JWSVerifier;
|
||||
import com.nimbusds.jose.crypto.ECDSASigner;
|
||||
import com.nimbusds.jose.crypto.ECDSAVerifier;
|
||||
import com.nimbusds.jose.crypto.MACSigner;
|
||||
import com.nimbusds.jose.crypto.MACVerifier;
|
||||
import com.nimbusds.jose.crypto.RSASSASigner;
|
||||
|
@ -45,22 +48,25 @@ import com.nimbusds.jose.jwk.OctetSequenceKey;
|
|||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
|
||||
public class DefaultJwtSigningAndValidationService implements JwtSigningAndValidationService {
|
||||
public class DefaultJWTSigningAndValidationService implements JWTSigningAndValidationService {
|
||||
|
||||
// map of identifier to signer
|
||||
private Map<String, JWSSigner> signers = new HashMap<String, JWSSigner>();
|
||||
private Map<String, JWSSigner> signers = new HashMap<>();
|
||||
|
||||
// map of identifier to verifier
|
||||
private Map<String, JWSVerifier> verifiers = new HashMap<String, JWSVerifier>();
|
||||
private Map<String, JWSVerifier> verifiers = new HashMap<>();
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(DefaultJwtSigningAndValidationService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultJWTSigningAndValidationService.class);
|
||||
|
||||
private String defaultSignerKeyId;
|
||||
|
||||
private JWSAlgorithm defaultAlgorithm;
|
||||
|
||||
// map of identifier to key
|
||||
private Map<String, JWK> keys = new HashMap<String, JWK>();
|
||||
private Map<String, JWK> keys = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Build this service based on the keys given. All public keys will be used
|
||||
|
@ -74,7 +80,7 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
* @throws NoSuchAlgorithmException
|
||||
* If there is no appropriate algorithm to tie the keys to.
|
||||
*/
|
||||
public DefaultJwtSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
public DefaultJWTSigningAndValidationService(Map<String, JWK> keys) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
this.keys = keys;
|
||||
buildSignersAndVerifiers();
|
||||
}
|
||||
|
@ -91,13 +97,12 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
* @throws NoSuchAlgorithmException
|
||||
* If there is no appropriate algorithm to tie the keys to.
|
||||
*/
|
||||
public DefaultJwtSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
public DefaultJWTSigningAndValidationService(JWKSetKeyStore keyStore) throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
// convert all keys in the keystore to a map based on key id
|
||||
if (keyStore!= null && keyStore.getJwkSet() != null) {
|
||||
for (JWK key : keyStore.getKeys()) {
|
||||
if (!Strings.isNullOrEmpty(key.getKeyID())) {
|
||||
// use the key ID that's built into the key itself
|
||||
// TODO (#641): deal with JWK thumbprints
|
||||
this.keys.put(key.getKeyID(), key);
|
||||
} else {
|
||||
// create a random key id
|
||||
|
@ -113,6 +118,7 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
/**
|
||||
* @return the defaultSignerKeyId
|
||||
*/
|
||||
@Override
|
||||
public String getDefaultSignerKeyId() {
|
||||
return defaultSignerKeyId;
|
||||
}
|
||||
|
@ -155,37 +161,46 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
String id = jwkEntry.getKey();
|
||||
JWK jwk = jwkEntry.getValue();
|
||||
|
||||
try {
|
||||
if (jwk instanceof RSAKey) {
|
||||
// build RSA signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // only add the signer if there's a private key
|
||||
RSASSASigner signer = new RSASSASigner(((RSAKey) jwk).toRSAPrivateKey());
|
||||
RSASSASigner signer = new RSASSASigner((RSAKey) jwk);
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
RSASSAVerifier verifier = new RSASSAVerifier(((RSAKey) jwk).toRSAPublicKey());
|
||||
RSASSAVerifier verifier = new RSASSAVerifier((RSAKey) jwk);
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else if (jwk instanceof ECKey) {
|
||||
// build EC signers & verifiers
|
||||
|
||||
// TODO: add support for EC keys
|
||||
logger.warn("EC Keys are not yet supported.");
|
||||
if (jwk.isPrivate()) {
|
||||
ECDSASigner signer = new ECDSASigner((ECKey) jwk);
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
ECDSAVerifier verifier = new ECDSAVerifier((ECKey) jwk);
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else if (jwk instanceof OctetSequenceKey) {
|
||||
// build HMAC signers & verifiers
|
||||
|
||||
if (jwk.isPrivate()) { // technically redundant check because all HMAC keys are private
|
||||
MACSigner signer = new MACSigner(((OctetSequenceKey) jwk).toByteArray());
|
||||
MACSigner signer = new MACSigner((OctetSequenceKey) jwk);
|
||||
signers.put(id, signer);
|
||||
}
|
||||
|
||||
MACVerifier verifier = new MACVerifier(((OctetSequenceKey) jwk).toByteArray());
|
||||
MACVerifier verifier = new MACVerifier((OctetSequenceKey) jwk);
|
||||
verifiers.put(id, verifier);
|
||||
|
||||
} else {
|
||||
logger.warn("Unknown key type: " + jwk);
|
||||
}
|
||||
} catch (JOSEException e) {
|
||||
logger.warn("Exception loading signer/verifier", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultSignerKeyId == null && keys.size() == 1) {
|
||||
|
@ -220,7 +235,7 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
JWSSigner signer = null;
|
||||
|
||||
for (JWSSigner s : signers.values()) {
|
||||
if (s.supportedAlgorithms().contains(alg)) {
|
||||
if (s.supportedJWSAlgorithms().contains(alg)) {
|
||||
signer = s;
|
||||
break;
|
||||
}
|
||||
|
@ -251,7 +266,7 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
}
|
||||
} catch (JOSEException e) {
|
||||
|
||||
logger.error("Failed to validate signature, error was: ", e);
|
||||
logger.error("Failed to validate signature with " + verifier + " error message: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -259,7 +274,7 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
|
||||
@Override
|
||||
public Map<String, JWK> getAllPublicKeys() {
|
||||
Map<String, JWK> pubKeys = new HashMap<String, JWK>();
|
||||
Map<String, JWK> pubKeys = new HashMap<>();
|
||||
|
||||
// pull all keys out of the verifiers if we know how
|
||||
for (String keyId : keys.keySet()) {
|
||||
|
@ -279,14 +294,14 @@ public class DefaultJwtSigningAndValidationService implements JwtSigningAndValid
|
|||
@Override
|
||||
public Collection<JWSAlgorithm> getAllSigningAlgsSupported() {
|
||||
|
||||
Set<JWSAlgorithm> algs = new HashSet<JWSAlgorithm>();
|
||||
Set<JWSAlgorithm> algs = new HashSet<>();
|
||||
|
||||
for (JWSSigner signer : signers.values()) {
|
||||
algs.addAll(signer.supportedAlgorithms());
|
||||
algs.addAll(signer.supportedJWSAlgorithms());
|
||||
}
|
||||
|
||||
for (JWSVerifier verifier : verifiers.values()) {
|
||||
algs.addAll(verifier.supportedAlgorithms());
|
||||
algs.addAll(verifier.supportedJWSAlgorithms());
|
||||
}
|
||||
|
||||
return algs;
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -23,21 +24,23 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.SystemDefaultHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.mitre.jose.keystore.JWKSetKeyStore;
|
||||
import org.mitre.jwt.encryption.service.JwtEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.encryption.service.impl.DefaultJwtEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.encryption.service.impl.DefaultJWTEncryptionAndDecryptionService;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
|
||||
/**
|
||||
|
@ -51,23 +54,26 @@ import com.nimbusds.jose.jwk.JWKSet;
|
|||
@Service
|
||||
public class JWKSetCacheService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JWKSetCacheService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(JWKSetCacheService.class);
|
||||
|
||||
// map of jwk set uri -> signing/validation service built on the keys found in that jwk set
|
||||
private LoadingCache<String, JwtSigningAndValidationService> validators;
|
||||
private LoadingCache<String, JWTSigningAndValidationService> validators;
|
||||
|
||||
// map of jwk set uri -> encryption/decryption service built on the keys found in that jwk set
|
||||
private LoadingCache<String, JwtEncryptionAndDecryptionService> encrypters;
|
||||
private LoadingCache<String, JWTEncryptionAndDecryptionService> encrypters;
|
||||
|
||||
public JWKSetCacheService() {
|
||||
this.validators = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
|
||||
.maximumSize(100)
|
||||
.build(new JWKSetVerifierFetcher());
|
||||
.build(new JWKSetVerifierFetcher(HttpClientBuilder.create().useSystemProperties().build()));
|
||||
this.encrypters = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
|
||||
.maximumSize(100)
|
||||
.build(new JWKSetEncryptorFetcher());
|
||||
.build(new JWKSetEncryptorFetcher(HttpClientBuilder.create().useSystemProperties().build()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,26 +82,20 @@ public class JWKSetCacheService {
|
|||
* @throws ExecutionException
|
||||
* @see com.google.common.cache.Cache#get(java.lang.Object)
|
||||
*/
|
||||
public JwtSigningAndValidationService getValidator(String jwksUri) {
|
||||
public JWTSigningAndValidationService getValidator(String jwksUri) {
|
||||
try {
|
||||
return validators.get(jwksUri);
|
||||
} catch (UncheckedExecutionException ue) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, ue);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public JwtEncryptionAndDecryptionService getEncrypter(String jwksUri) {
|
||||
public JWTEncryptionAndDecryptionService getEncrypter(String jwksUri) {
|
||||
try {
|
||||
return encrypters.get(jwksUri);
|
||||
} catch (UncheckedExecutionException ue) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, ue);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri, e);
|
||||
} catch (UncheckedExecutionException | ExecutionException e) {
|
||||
logger.warn("Couldn't load JWK Set from " + jwksUri + ": " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -104,26 +104,28 @@ public class JWKSetCacheService {
|
|||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class JWKSetVerifierFetcher extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
private class JWKSetVerifierFetcher extends CacheLoader<String, JWTSigningAndValidationService> {
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
JWKSetVerifierFetcher(HttpClient httpClient) {
|
||||
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
this.restTemplate = new RestTemplate(httpFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the JWK Set and build the appropriate signing service.
|
||||
*/
|
||||
@Override
|
||||
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||
|
||||
public JWTSigningAndValidationService load(String key) throws Exception {
|
||||
String jsonString = restTemplate.getForObject(key, String.class);
|
||||
JWKSet jwkSet = JWKSet.parse(jsonString);
|
||||
|
||||
JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet);
|
||||
|
||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keyStore);
|
||||
JWTSigningAndValidationService service = new DefaultJWTSigningAndValidationService(keyStore);
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -132,23 +134,32 @@ public class JWKSetCacheService {
|
|||
* @author jricher
|
||||
*
|
||||
*/
|
||||
private class JWKSetEncryptorFetcher extends CacheLoader<String, JwtEncryptionAndDecryptionService> {
|
||||
private HttpClient httpClient = new SystemDefaultHttpClient();
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
private RestTemplate restTemplate = new RestTemplate(httpFactory);
|
||||
private class JWKSetEncryptorFetcher extends CacheLoader<String, JWTEncryptionAndDecryptionService> {
|
||||
private HttpComponentsClientHttpRequestFactory httpFactory;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
public JWKSetEncryptorFetcher(HttpClient httpClient) {
|
||||
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
|
||||
this.restTemplate = new RestTemplate(httpFactory);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see com.google.common.cache.CacheLoader#load(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public JwtEncryptionAndDecryptionService load(String key) throws Exception {
|
||||
public JWTEncryptionAndDecryptionService load(String key) throws Exception {
|
||||
try {
|
||||
String jsonString = restTemplate.getForObject(key, String.class);
|
||||
JWKSet jwkSet = JWKSet.parse(jsonString);
|
||||
|
||||
JWKSetKeyStore keyStore = new JWKSetKeyStore(jwkSet);
|
||||
|
||||
JwtEncryptionAndDecryptionService service = new DefaultJwtEncryptionAndDecryptionService(keyStore);
|
||||
JWTEncryptionAndDecryptionService service = new DefaultJWTEncryptionAndDecryptionService(keyStore);
|
||||
|
||||
return service;
|
||||
} catch (JsonParseException | RestClientException e) {
|
||||
throw new IllegalArgumentException("Unable to load JWK Set");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -22,8 +21,7 @@ import java.util.Map;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.nimbusds.jose.Algorithm;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -36,8 +34,8 @@ import com.google.common.cache.LoadingCache;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import com.nimbusds.jose.jwk.JWK;
|
||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
||||
import com.nimbusds.jose.jwk.KeyUse;
|
||||
import com.nimbusds.jose.jwk.OctetSequenceKey;
|
||||
import com.nimbusds.jose.util.Base64URL;
|
||||
|
||||
/**
|
||||
|
@ -47,14 +45,17 @@ import com.nimbusds.jose.util.Base64URL;
|
|||
*
|
||||
*/
|
||||
@Service
|
||||
public class SymmetricCacheService {
|
||||
public class SymmetricKeyJWTValidatorCacheService {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(SymmetricCacheService.class);
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(SymmetricKeyJWTValidatorCacheService.class);
|
||||
|
||||
private LoadingCache<String, JwtSigningAndValidationService> validators;
|
||||
private LoadingCache<String, JWTSigningAndValidationService> validators;
|
||||
|
||||
|
||||
public SymmetricCacheService() {
|
||||
public SymmetricKeyJWTValidatorCacheService() {
|
||||
validators = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(24, TimeUnit.HOURS)
|
||||
.maximumSize(100)
|
||||
|
@ -68,7 +69,7 @@ public class SymmetricCacheService {
|
|||
* @param client
|
||||
* @return
|
||||
*/
|
||||
public JwtSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
||||
public JWTSigningAndValidationService getSymmetricValidtor(ClientDetailsEntity client) {
|
||||
|
||||
if (client == null) {
|
||||
logger.error("Couldn't create symmetric validator for null client");
|
||||
|
@ -92,22 +93,22 @@ public class SymmetricCacheService {
|
|||
|
||||
}
|
||||
|
||||
public class SymmetricValidatorBuilder extends CacheLoader<String, JwtSigningAndValidationService> {
|
||||
public class SymmetricValidatorBuilder extends CacheLoader<String, JWTSigningAndValidationService> {
|
||||
@Override
|
||||
public JwtSigningAndValidationService load(String key) throws Exception {
|
||||
public JWTSigningAndValidationService load(String key) throws Exception {
|
||||
try {
|
||||
|
||||
String id = "SYMMETRIC-KEY";
|
||||
|
||||
JWK jwk = new OctetSequenceKey(Base64URL.encode(key), KeyUse.SIGNATURE, null, null, id, null, null, null);
|
||||
JWK jwk = new OctetSequenceKey.Builder(Base64URL.encode(key))
|
||||
.keyUse(KeyUse.SIGNATURE)
|
||||
.keyID(id)
|
||||
.build();
|
||||
Map<String, JWK> keys = ImmutableMap.of(id, jwk);
|
||||
JwtSigningAndValidationService service = new DefaultJwtSigningAndValidationService(keys);
|
||||
JWTSigningAndValidationService service = new DefaultJWTSigningAndValidationService(keys);
|
||||
|
||||
return service;
|
||||
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error("Couldn't create symmetric validator for client", e);
|
||||
} catch (InvalidKeySpecException e) {
|
||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
logger.error("Couldn't create symmetric validator for client", e);
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.exception;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class DeviceCodeCreationException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 8078568710169208466L;
|
||||
|
||||
private String error;
|
||||
|
||||
public DeviceCodeCreationException(String error, String message) {
|
||||
super(message);
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the error
|
||||
*/
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param error the error to set
|
||||
*/
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,36 +14,76 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.oauth2.model.convert.SerializableStringConverter;
|
||||
import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Request;
|
||||
|
||||
@Entity
|
||||
@Table(name = "authentication_holder")
|
||||
@NamedQueries ({
|
||||
@NamedQuery(name = "AuthenticationHolderEntity.getByAuthentication", query = "select a from AuthenticationHolderEntity a where a.authentication = :authentication"),
|
||||
@NamedQuery(name = "AuthenticationHolderEntity.getUnusedAuthenticationHolders", query = "select a from AuthenticationHolderEntity a where a.id not in (select t.authenticationHolder.id from OAuth2AccessTokenEntity t) and a.id not in (select r.authenticationHolder.id from OAuth2RefreshTokenEntity r)")
|
||||
@NamedQuery(name = AuthenticationHolderEntity.QUERY_ALL, query = "select a from AuthenticationHolderEntity a"),
|
||||
@NamedQuery(name = AuthenticationHolderEntity.QUERY_GET_UNUSED, query = "select a from AuthenticationHolderEntity a where " +
|
||||
"a.id not in (select t.authenticationHolder.id from OAuth2AccessTokenEntity t) and " +
|
||||
"a.id not in (select r.authenticationHolder.id from OAuth2RefreshTokenEntity r) and " +
|
||||
"a.id not in (select c.authenticationHolder.id from AuthorizationCodeEntity c)")
|
||||
})
|
||||
public class AuthenticationHolderEntity {
|
||||
|
||||
public static final String QUERY_GET_UNUSED = "AuthenticationHolderEntity.getUnusedAuthenticationHolders";
|
||||
public static final String QUERY_ALL = "AuthenticationHolderEntity.getAll";
|
||||
|
||||
private Long id;
|
||||
|
||||
private Long ownerId;
|
||||
private SavedUserAuthentication userAuth;
|
||||
|
||||
private OAuth2Authentication authentication;
|
||||
private Collection<GrantedAuthority> authorities;
|
||||
|
||||
private Set<String> resourceIds;
|
||||
|
||||
private boolean approved;
|
||||
|
||||
private String redirectUri;
|
||||
|
||||
private Set<String> responseTypes;
|
||||
|
||||
private Map<String, Serializable> extensions;
|
||||
|
||||
private String clientId;
|
||||
|
||||
private Set<String> scope;
|
||||
|
||||
private Map<String, String> requestParameters;
|
||||
|
||||
public AuthenticationHolderEntity() {
|
||||
|
||||
|
@ -59,25 +100,226 @@ public class AuthenticationHolderEntity {
|
|||
this.id = id;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name = "owner_id")
|
||||
public Long getOwnerId() {
|
||||
return ownerId;
|
||||
}
|
||||
|
||||
public void setOwnerId(Long owner_id) {
|
||||
this.ownerId = owner_id;
|
||||
}
|
||||
|
||||
@Lob
|
||||
@Basic(fetch=FetchType.LAZY)
|
||||
@Column(name = "authentication")
|
||||
@Transient
|
||||
public OAuth2Authentication getAuthentication() {
|
||||
return authentication;
|
||||
// TODO: memoize this
|
||||
return new OAuth2Authentication(createOAuth2Request(), getUserAuth());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private OAuth2Request createOAuth2Request() {
|
||||
return new OAuth2Request(requestParameters, clientId, authorities, approved, scope, resourceIds, redirectUri, responseTypes, extensions);
|
||||
}
|
||||
|
||||
public void setAuthentication(OAuth2Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
|
||||
// pull apart the request and save its bits
|
||||
OAuth2Request o2Request = authentication.getOAuth2Request();
|
||||
setAuthorities(o2Request.getAuthorities() == null ? null : new HashSet<>(o2Request.getAuthorities()));
|
||||
setClientId(o2Request.getClientId());
|
||||
setExtensions(o2Request.getExtensions() == null ? null : new HashMap<>(o2Request.getExtensions()));
|
||||
setRedirectUri(o2Request.getRedirectUri());
|
||||
setRequestParameters(o2Request.getRequestParameters() == null ? null : new HashMap<>(o2Request.getRequestParameters()));
|
||||
setResourceIds(o2Request.getResourceIds() == null ? null : new HashSet<>(o2Request.getResourceIds()));
|
||||
setResponseTypes(o2Request.getResponseTypes() == null ? null : new HashSet<>(o2Request.getResponseTypes()));
|
||||
setScope(o2Request.getScope() == null ? null : new HashSet<>(o2Request.getScope()));
|
||||
setApproved(o2Request.isApproved());
|
||||
|
||||
if (authentication.getUserAuthentication() != null) {
|
||||
this.userAuth = new SavedUserAuthentication(authentication.getUserAuthentication());
|
||||
} else {
|
||||
this.userAuth = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userAuth
|
||||
*/
|
||||
@OneToOne(cascade=CascadeType.ALL)
|
||||
@JoinColumn(name = "user_auth_id")
|
||||
public SavedUserAuthentication getUserAuth() {
|
||||
return userAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userAuth the userAuth to set
|
||||
*/
|
||||
public void setUserAuth(SavedUserAuthentication userAuth) {
|
||||
this.userAuth = userAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the authorities
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_authority",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Convert(converter = SimpleGrantedAuthorityStringConverter.class)
|
||||
@Column(name="authority")
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorities the authorities to set
|
||||
*/
|
||||
public void setAuthorities(Collection<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the resourceIds
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_resource_id",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="resource_id")
|
||||
public Set<String> getResourceIds() {
|
||||
return resourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resourceIds the resourceIds to set
|
||||
*/
|
||||
public void setResourceIds(Set<String> resourceIds) {
|
||||
this.resourceIds = resourceIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the approved
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="approved")
|
||||
public boolean isApproved() {
|
||||
return approved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param approved the approved to set
|
||||
*/
|
||||
public void setApproved(boolean approved) {
|
||||
this.approved = approved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the redirectUri
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="redirect_uri")
|
||||
public String getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param redirectUri the redirectUri to set
|
||||
*/
|
||||
public void setRedirectUri(String redirectUri) {
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the responseTypes
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_response_type",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="response_type")
|
||||
public Set<String> getResponseTypes() {
|
||||
return responseTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param responseTypes the responseTypes to set
|
||||
*/
|
||||
public void setResponseTypes(Set<String> responseTypes) {
|
||||
this.responseTypes = responseTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the extensions
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_extension",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="val")
|
||||
@MapKeyColumn(name="extension")
|
||||
@Convert(converter=SerializableStringConverter.class)
|
||||
public Map<String, Serializable> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param extensions the extensions to set
|
||||
*/
|
||||
public void setExtensions(Map<String, Serializable> extensions) {
|
||||
this.extensions = extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="client_id")
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scope
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="scope")
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope the scope to set
|
||||
*/
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the requestParameters
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="authentication_holder_request_parameter",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="val")
|
||||
@MapKeyColumn(name="param")
|
||||
public Map<String, String> getRequestParameters() {
|
||||
return requestParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requestParameters the requestParameters to set
|
||||
*/
|
||||
public void setRequestParameters(Map<String, String> requestParameters) {
|
||||
this.requestParameters = requestParameters;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,22 +14,23 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import javax.persistence.Temporal;
|
||||
|
||||
/**
|
||||
* Entity class for authorization codes
|
||||
|
@ -39,15 +41,23 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
|||
@Entity
|
||||
@Table(name = "authorization_code")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "AuthorizationCodeEntity.getByValue", query = "select a from AuthorizationCodeEntity a where a.code = :code")
|
||||
@NamedQuery(name = AuthorizationCodeEntity.QUERY_BY_VALUE, query = "select a from AuthorizationCodeEntity a where a.code = :code"),
|
||||
@NamedQuery(name = AuthorizationCodeEntity.QUERY_EXPIRATION_BY_DATE, query = "select a from AuthorizationCodeEntity a where a.expiration <= :" + AuthorizationCodeEntity.PARAM_DATE)
|
||||
})
|
||||
public class AuthorizationCodeEntity {
|
||||
|
||||
public static final String QUERY_BY_VALUE = "AuthorizationCodeEntity.getByValue";
|
||||
public static final String QUERY_EXPIRATION_BY_DATE = "AuthorizationCodeEntity.expirationByDate";
|
||||
|
||||
public static final String PARAM_DATE = "date";
|
||||
|
||||
private Long id;
|
||||
|
||||
private String code;
|
||||
|
||||
private OAuth2Authentication authentication;
|
||||
private AuthenticationHolderEntity authenticationHolder;
|
||||
|
||||
private Date expiration;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
|
@ -62,9 +72,10 @@ public class AuthorizationCodeEntity {
|
|||
* @param code the authorization code
|
||||
* @param authRequest the AuthoriztionRequestHolder associated with the original code request
|
||||
*/
|
||||
public AuthorizationCodeEntity(String code, OAuth2Authentication authRequest) {
|
||||
public AuthorizationCodeEntity(String code, AuthenticationHolderEntity authenticationHolder, Date expiration) {
|
||||
this.code = code;
|
||||
this.authentication = authRequest;
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,20 +112,30 @@ public class AuthorizationCodeEntity {
|
|||
}
|
||||
|
||||
/**
|
||||
* The authentication in place when this token was created.
|
||||
* @return the authentication
|
||||
*/
|
||||
@Lob
|
||||
@Basic(fetch=FetchType.EAGER)
|
||||
@Column(name="authentication")
|
||||
public OAuth2Authentication getAuthentication() {
|
||||
return authentication;
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "auth_holder_id")
|
||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||
return authenticationHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authentication the authentication to set
|
||||
*/
|
||||
public void setAuthentication(OAuth2Authentication authentication) {
|
||||
this.authentication = authentication;
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name = "expiration")
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -25,13 +26,11 @@ import java.util.HashSet;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
|
@ -49,15 +48,21 @@ import javax.persistence.Temporal;
|
|||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.jose.JWEAlgorithmEmbed;
|
||||
import org.mitre.jose.JWEEncryptionMethodEmbed;
|
||||
import org.mitre.jose.JWSAlgorithmEmbed;
|
||||
import org.mitre.oauth2.model.convert.JWEAlgorithmStringConverter;
|
||||
import org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter;
|
||||
import org.mitre.oauth2.model.convert.JWKSetStringConverter;
|
||||
import org.mitre.oauth2.model.convert.JWSAlgorithmStringConverter;
|
||||
import org.mitre.oauth2.model.convert.JWTStringConverter;
|
||||
import org.mitre.oauth2.model.convert.PKCEAlgorithmStringConverter;
|
||||
import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -66,14 +71,16 @@ import com.nimbusds.jose.JWSAlgorithm;
|
|||
@Entity
|
||||
@Table(name = "client_details")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "ClientDetailsEntity.findAll", query = "SELECT c FROM ClientDetailsEntity c"),
|
||||
@NamedQuery(name = "ClientDetailsEntity.getByClientId", query = "select c from ClientDetailsEntity c where c.clientId = :clientId")
|
||||
@NamedQuery(name = ClientDetailsEntity.QUERY_ALL, query = "SELECT c FROM ClientDetailsEntity c"),
|
||||
@NamedQuery(name = ClientDetailsEntity.QUERY_BY_CLIENT_ID, query = "select c from ClientDetailsEntity c where c.clientId = :" + ClientDetailsEntity.PARAM_CLIENT_ID)
|
||||
})
|
||||
public class ClientDetailsEntity implements ClientDetails {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String QUERY_BY_CLIENT_ID = "ClientDetailsEntity.getByClientId";
|
||||
public static final String QUERY_ALL = "ClientDetailsEntity.findAll";
|
||||
|
||||
public static final String PARAM_CLIENT_ID = "clientId";
|
||||
|
||||
private static final int DEFAULT_ID_TOKEN_VALIDITY_SECONDS = 600;
|
||||
|
||||
private static final long serialVersionUID = -1617727085733786296L;
|
||||
|
@ -83,51 +90,54 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
/** Fields from the OAuth2 Dynamic Registration Specification */
|
||||
private String clientId = null; // client_id
|
||||
private String clientSecret = null; // client_secret
|
||||
private Set<String> redirectUris = new HashSet<String>(); // redirect_uris
|
||||
private Set<String> redirectUris = new HashSet<>(); // redirect_uris
|
||||
private String clientName; // client_name
|
||||
private String clientUri; // client_uri
|
||||
private String logoUri; // logo_uri
|
||||
private Set<String> contacts; // contacts
|
||||
private String tosUri; // tos_uri
|
||||
private AuthMethod tokenEndpointAuthMethod = AuthMethod.SECRET_BASIC; // token_endpoint_auth_method
|
||||
private Set<String> scope = new HashSet<String>(); // scope
|
||||
private Set<String> grantTypes = new HashSet<String>(); // grant_types
|
||||
private Set<String> responseTypes = new HashSet<String>(); // response_types
|
||||
private Set<String> scope = new HashSet<>(); // scope
|
||||
private Set<String> grantTypes = new HashSet<>(); // grant_types
|
||||
private Set<String> responseTypes = new HashSet<>(); // response_types
|
||||
private String policyUri;
|
||||
private String jwksUri;
|
||||
private String jwksUri; // URI pointer to keys
|
||||
private JWKSet jwks; // public key stored by value
|
||||
private String softwareId;
|
||||
private String softwareVersion;
|
||||
|
||||
/** Fields from OIDC Client Registration Specification **/
|
||||
private AppType applicationType; // application_type
|
||||
private String sectorIdentifierUri; // sector_identifier_uri
|
||||
private SubjectType subjectType; // subject_type
|
||||
|
||||
private JWSAlgorithmEmbed requestObjectSigningAlg = null; // request_object_signing_alg
|
||||
private JWSAlgorithm requestObjectSigningAlg = null; // request_object_signing_alg
|
||||
|
||||
private JWSAlgorithmEmbed userInfoSignedResponseAlg = null; // user_info_signed_response_alg
|
||||
private JWEAlgorithmEmbed userInfoEncryptedResponseAlg = null; // user_info_encrypted_response_alg
|
||||
private JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc = null; // user_info_encrypted_response_enc
|
||||
private JWSAlgorithm userInfoSignedResponseAlg = null; // user_info_signed_response_alg
|
||||
private JWEAlgorithm userInfoEncryptedResponseAlg = null; // user_info_encrypted_response_alg
|
||||
private EncryptionMethod userInfoEncryptedResponseEnc = null; // user_info_encrypted_response_enc
|
||||
|
||||
private JWSAlgorithmEmbed idTokenSignedResponseAlg = null; // id_token_signed_response_alg
|
||||
private JWEAlgorithmEmbed idTokenEncryptedResponseAlg = null; // id_token_encrypted_response_alg
|
||||
private JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc = null; // id_token_encrypted_response_enc
|
||||
private JWSAlgorithm idTokenSignedResponseAlg = null; // id_token_signed_response_alg
|
||||
private JWEAlgorithm idTokenEncryptedResponseAlg = null; // id_token_encrypted_response_alg
|
||||
private EncryptionMethod idTokenEncryptedResponseEnc = null; // id_token_encrypted_response_enc
|
||||
|
||||
private JWSAlgorithmEmbed tokenEndpointAuthSigningAlg = null; // token_endpoint_auth_signing_alg
|
||||
private JWSAlgorithm tokenEndpointAuthSigningAlg = null; // token_endpoint_auth_signing_alg
|
||||
|
||||
private Integer defaultMaxAge; // default_max_age
|
||||
private Boolean requireAuthTime; // require_auth_time
|
||||
private Set<String> defaultACRvalues; // default_acr_values
|
||||
|
||||
private String initiateLoginUri; // initiate_login_uri
|
||||
private String postLogoutRedirectUri; // post_logout_redirect_uri
|
||||
private Set<String> postLogoutRedirectUris; // post_logout_redirect_uris
|
||||
|
||||
private Set<String> requestUris; // request_uris
|
||||
|
||||
/** Fields to support the ClientDetails interface **/
|
||||
private Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
|
||||
private Set<GrantedAuthority> authorities = new HashSet<>();
|
||||
private Integer accessTokenValiditySeconds = 0; // in seconds
|
||||
private Integer refreshTokenValiditySeconds = 0; // in seconds
|
||||
private Set<String> resourceIds = new HashSet<String>();
|
||||
private Map<String, Object> additionalInformation = new HashMap<String, Object>();
|
||||
private Set<String> resourceIds = new HashSet<>();
|
||||
private Map<String, Object> additionalInformation = new HashMap<>();
|
||||
|
||||
/** Our own fields **/
|
||||
private String clientDescription = ""; // human-readable description
|
||||
|
@ -136,6 +146,17 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private boolean allowIntrospection = false; // do we let this client call the introspection endpoint?
|
||||
private Integer idTokenValiditySeconds; //timeout for id tokens
|
||||
private Date createdAt; // time the client was created
|
||||
private boolean clearAccessTokensOnRefresh = true; // do we clear access tokens on refresh?
|
||||
private Integer deviceCodeValiditySeconds; // timeout for device codes
|
||||
|
||||
/** fields for UMA */
|
||||
private Set<String> claimsRedirectUris;
|
||||
|
||||
/** Software statement **/
|
||||
private JWT softwareStatement;
|
||||
|
||||
/** PKCE **/
|
||||
private PKCEAlgorithm codeChallengeMethod;
|
||||
|
||||
public enum AuthMethod {
|
||||
SECRET_POST("client_secret_post"),
|
||||
|
@ -147,7 +168,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private final String value;
|
||||
|
||||
// map to aid reverse lookup
|
||||
private static final Map<String, AuthMethod> lookup = new HashMap<String, AuthMethod>();
|
||||
private static final Map<String, AuthMethod> lookup = new HashMap<>();
|
||||
static {
|
||||
for (AuthMethod a : AuthMethod.values()) {
|
||||
lookup.put(a.getValue(), a);
|
||||
|
@ -173,7 +194,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private final String value;
|
||||
|
||||
// map to aid reverse lookup
|
||||
private static final Map<String, AppType> lookup = new HashMap<String, AppType>();
|
||||
private static final Map<String, AppType> lookup = new HashMap<>();
|
||||
static {
|
||||
for (AppType a : AppType.values()) {
|
||||
lookup.put(a.getValue(), a);
|
||||
|
@ -199,7 +220,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
private final String value;
|
||||
|
||||
// map to aid reverse lookup
|
||||
private static final Map<String, SubjectType> lookup = new HashMap<String, SubjectType>();
|
||||
private static final Map<String, SubjectType> lookup = new HashMap<>();
|
||||
static {
|
||||
for (SubjectType u : SubjectType.values()) {
|
||||
lookup.put(u.getValue(), u);
|
||||
|
@ -450,6 +471,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
* passthrough for SECOAUTH api
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public Set<String> getAuthorizedGrantTypes() {
|
||||
return getGrantTypes();
|
||||
}
|
||||
|
@ -463,6 +485,7 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Override
|
||||
@Convert(converter = SimpleGrantedAuthorityStringConverter.class)
|
||||
@Column(name="authority")
|
||||
public Set<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
|
@ -687,6 +710,23 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
this.jwksUri = jwksUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwks
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="jwks")
|
||||
@Convert(converter = JWKSetStringConverter.class)
|
||||
public JWKSet getJwks() {
|
||||
return jwks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwks the jwks to set
|
||||
*/
|
||||
public void setJwks(JWKSet jwks) {
|
||||
this.jwks = jwks;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name="sector_identifier_uri")
|
||||
public String getSectorIdentifierUri() {
|
||||
|
@ -697,212 +737,94 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
this.sectorIdentifierUri = sectorIdentifierUri;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="request_object_signing_alg"))
|
||||
})
|
||||
public JWSAlgorithmEmbed getRequestObjectSigningAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name = "request_object_signing_alg")
|
||||
@Convert(converter = JWSAlgorithmStringConverter.class)
|
||||
public JWSAlgorithm getRequestObjectSigningAlg() {
|
||||
return requestObjectSigningAlg;
|
||||
}
|
||||
|
||||
public void setRequestObjectSigningAlgEmbed(JWSAlgorithmEmbed requestObjectSigningAlg) {
|
||||
public void setRequestObjectSigningAlg(JWSAlgorithm requestObjectSigningAlg) {
|
||||
this.requestObjectSigningAlg = requestObjectSigningAlg;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="user_info_signed_response_alg"))
|
||||
})
|
||||
public JWSAlgorithmEmbed getUserInfoSignedResponseAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name = "user_info_signed_response_alg")
|
||||
@Convert(converter = JWSAlgorithmStringConverter.class)
|
||||
public JWSAlgorithm getUserInfoSignedResponseAlg() {
|
||||
return userInfoSignedResponseAlg;
|
||||
}
|
||||
|
||||
public void setUserInfoSignedResponseAlgEmbed(JWSAlgorithmEmbed userInfoSignedResponseAlg) {
|
||||
public void setUserInfoSignedResponseAlg(JWSAlgorithm userInfoSignedResponseAlg) {
|
||||
this.userInfoSignedResponseAlg = userInfoSignedResponseAlg;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="user_info_encrypted_response_alg"))
|
||||
})
|
||||
public JWEAlgorithmEmbed getUserInfoEncryptedResponseAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name = "user_info_encrypted_response_alg")
|
||||
@Convert(converter = JWEAlgorithmStringConverter.class)
|
||||
public JWEAlgorithm getUserInfoEncryptedResponseAlg() {
|
||||
return userInfoEncryptedResponseAlg;
|
||||
}
|
||||
|
||||
public void setUserInfoEncryptedResponseAlgEmbed(JWEAlgorithmEmbed userInfoEncryptedResponseAlg) {
|
||||
public void setUserInfoEncryptedResponseAlg(JWEAlgorithm userInfoEncryptedResponseAlg) {
|
||||
this.userInfoEncryptedResponseAlg = userInfoEncryptedResponseAlg;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="user_info_encrypted_response_enc"))
|
||||
})
|
||||
public JWEEncryptionMethodEmbed getUserInfoEncryptedResponseEncEmbed() {
|
||||
@Basic
|
||||
@Column(name = "user_info_encrypted_response_enc")
|
||||
@Convert(converter = JWEEncryptionMethodStringConverter.class)
|
||||
public EncryptionMethod getUserInfoEncryptedResponseEnc() {
|
||||
return userInfoEncryptedResponseEnc;
|
||||
}
|
||||
|
||||
public void setUserInfoEncryptedResponseEncEmbed(JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc) {
|
||||
public void setUserInfoEncryptedResponseEnc(EncryptionMethod userInfoEncryptedResponseEnc) {
|
||||
this.userInfoEncryptedResponseEnc = userInfoEncryptedResponseEnc;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="id_token_signed_response_alg"))
|
||||
})
|
||||
public JWSAlgorithmEmbed getIdTokenSignedResponseAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name="id_token_signed_response_alg")
|
||||
@Convert(converter = JWSAlgorithmStringConverter.class)
|
||||
public JWSAlgorithm getIdTokenSignedResponseAlg() {
|
||||
return idTokenSignedResponseAlg;
|
||||
}
|
||||
|
||||
public void setIdTokenSignedResponseAlgEmbed(JWSAlgorithmEmbed idTokenSignedResponseAlg) {
|
||||
public void setIdTokenSignedResponseAlg(JWSAlgorithm idTokenSignedResponseAlg) {
|
||||
this.idTokenSignedResponseAlg = idTokenSignedResponseAlg;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="id_token_encrypted_response_alg"))
|
||||
})
|
||||
public JWEAlgorithmEmbed getIdTokenEncryptedResponseAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name = "id_token_encrypted_response_alg")
|
||||
@Convert(converter = JWEAlgorithmStringConverter.class)
|
||||
public JWEAlgorithm getIdTokenEncryptedResponseAlg() {
|
||||
return idTokenEncryptedResponseAlg;
|
||||
}
|
||||
|
||||
public void setIdTokenEncryptedResponseAlgEmbed(JWEAlgorithmEmbed idTokenEncryptedResponseAlg) {
|
||||
public void setIdTokenEncryptedResponseAlg(JWEAlgorithm idTokenEncryptedResponseAlg) {
|
||||
this.idTokenEncryptedResponseAlg = idTokenEncryptedResponseAlg;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="id_token_encrypted_response_enc"))
|
||||
})
|
||||
public JWEEncryptionMethodEmbed getIdTokenEncryptedResponseEncEmbed() {
|
||||
@Basic
|
||||
@Column(name = "id_token_encrypted_response_enc")
|
||||
@Convert(converter = JWEEncryptionMethodStringConverter.class)
|
||||
public EncryptionMethod getIdTokenEncryptedResponseEnc() {
|
||||
return idTokenEncryptedResponseEnc;
|
||||
}
|
||||
|
||||
public void setIdTokenEncryptedResponseEncEmbed(JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc) {
|
||||
public void setIdTokenEncryptedResponseEnc(EncryptionMethod idTokenEncryptedResponseEnc) {
|
||||
this.idTokenEncryptedResponseEnc = idTokenEncryptedResponseEnc;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "algorithmName", column=@Column(name="token_endpoint_auth_signing_alg"))
|
||||
})
|
||||
public JWSAlgorithmEmbed getTokenEndpointAuthSigningAlgEmbed() {
|
||||
@Basic
|
||||
@Column(name="token_endpoint_auth_signing_alg")
|
||||
@Convert(converter = JWSAlgorithmStringConverter.class)
|
||||
public JWSAlgorithm getTokenEndpointAuthSigningAlg() {
|
||||
return tokenEndpointAuthSigningAlg;
|
||||
}
|
||||
|
||||
public void setTokenEndpointAuthSigningAlgEmbed(JWSAlgorithmEmbed tokenEndpointAuthSigningAlgEmbed) {
|
||||
this.tokenEndpointAuthSigningAlg = tokenEndpointAuthSigningAlgEmbed;
|
||||
}
|
||||
|
||||
//
|
||||
// Transient passthrough methods for JOSE elements
|
||||
//
|
||||
|
||||
@Transient
|
||||
public JWSAlgorithm getRequestObjectSigningAlg() {
|
||||
if (requestObjectSigningAlg != null) {
|
||||
return requestObjectSigningAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setRequestObjectSigningAlg(JWSAlgorithm requestObjectSigningAlg) {
|
||||
this.requestObjectSigningAlg = new JWSAlgorithmEmbed(requestObjectSigningAlg);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public JWSAlgorithm getUserInfoSignedResponseAlg() {
|
||||
if (userInfoSignedResponseAlg != null) {
|
||||
return userInfoSignedResponseAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUserInfoSignedResponseAlg(JWSAlgorithm userInfoSignedResponseAlg) {
|
||||
this.userInfoSignedResponseAlg = new JWSAlgorithmEmbed(userInfoSignedResponseAlg);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public JWEAlgorithm getUserInfoEncryptedResponseAlg() {
|
||||
if (userInfoEncryptedResponseAlg != null) {
|
||||
return userInfoEncryptedResponseAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUserInfoEncryptedResponseAlg(JWEAlgorithm userInfoEncryptedResponseAlg) {
|
||||
this.userInfoEncryptedResponseAlg = new JWEAlgorithmEmbed(userInfoEncryptedResponseAlg);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public EncryptionMethod getUserInfoEncryptedResponseEnc() {
|
||||
if (userInfoEncryptedResponseEnc != null) {
|
||||
return userInfoEncryptedResponseEnc.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setUserInfoEncryptedResponseEnc(EncryptionMethod userInfoEncryptedResponseEnc) {
|
||||
this.userInfoEncryptedResponseEnc = new JWEEncryptionMethodEmbed(userInfoEncryptedResponseEnc);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public JWSAlgorithm getIdTokenSignedResponseAlg() {
|
||||
if (idTokenSignedResponseAlg != null) {
|
||||
return idTokenSignedResponseAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdTokenSignedResponseAlg(JWSAlgorithm idTokenSignedResponseAlg) {
|
||||
this.idTokenSignedResponseAlg = new JWSAlgorithmEmbed(idTokenSignedResponseAlg);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public JWEAlgorithm getIdTokenEncryptedResponseAlg() {
|
||||
if (idTokenEncryptedResponseAlg != null) {
|
||||
return idTokenEncryptedResponseAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdTokenEncryptedResponseAlg(JWEAlgorithm idTokenEncryptedResponseAlg) {
|
||||
this.idTokenEncryptedResponseAlg = new JWEAlgorithmEmbed(idTokenEncryptedResponseAlg);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public EncryptionMethod getIdTokenEncryptedResponseEnc() {
|
||||
if (idTokenEncryptedResponseEnc != null) {
|
||||
return idTokenEncryptedResponseEnc.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setIdTokenEncryptedResponseEnc(EncryptionMethod idTokenEncryptedResponseEnc) {
|
||||
this.idTokenEncryptedResponseEnc = new JWEEncryptionMethodEmbed(idTokenEncryptedResponseEnc);
|
||||
}
|
||||
|
||||
@Transient
|
||||
public JWSAlgorithm getTokenEndpointAuthSigningAlg() {
|
||||
if (tokenEndpointAuthSigningAlg != null) {
|
||||
return tokenEndpointAuthSigningAlg.getAlgorithm();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTokenEndpointAuthSigningAlg(JWSAlgorithm tokenEndpointAuthSigningAlg) {
|
||||
this.tokenEndpointAuthSigningAlg = new JWSAlgorithmEmbed(tokenEndpointAuthSigningAlg);
|
||||
this.tokenEndpointAuthSigningAlg = tokenEndpointAuthSigningAlg;
|
||||
}
|
||||
|
||||
// END Transient JOSE methods
|
||||
|
||||
@Basic
|
||||
@Column(name="default_max_age")
|
||||
public Integer getDefaultMaxAge() {
|
||||
|
@ -982,17 +904,21 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
/**
|
||||
* @return the postLogoutRedirectUri
|
||||
*/
|
||||
@Basic
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="client_post_logout_redirect_uri",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="post_logout_redirect_uri")
|
||||
public String getPostLogoutRedirectUri() {
|
||||
return postLogoutRedirectUri;
|
||||
public Set<String> getPostLogoutRedirectUris() {
|
||||
return postLogoutRedirectUris;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param postLogoutRedirectUri the postLogoutRedirectUri to set
|
||||
*/
|
||||
public void setPostLogoutRedirectUri(String postLogoutRedirectUri) {
|
||||
this.postLogoutRedirectUri = postLogoutRedirectUri;
|
||||
public void setPostLogoutRedirectUris(Set<String> postLogoutRedirectUri) {
|
||||
this.postLogoutRedirectUris = postLogoutRedirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1039,4 +965,122 @@ public class ClientDetailsEntity implements ClientDetails {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clearAccessTokensOnRefresh
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "clear_access_tokens_on_refresh")
|
||||
public boolean isClearAccessTokensOnRefresh() {
|
||||
return clearAccessTokensOnRefresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clearAccessTokensOnRefresh the clearAccessTokensOnRefresh to set
|
||||
*/
|
||||
public void setClearAccessTokensOnRefresh(boolean clearAccessTokensOnRefresh) {
|
||||
this.clearAccessTokensOnRefresh = clearAccessTokensOnRefresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the claimsRedirectUris
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="client_claims_redirect_uri",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="redirect_uri")
|
||||
public Set<String> getClaimsRedirectUris() {
|
||||
return claimsRedirectUris;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param claimsRedirectUris the claimsRedirectUris to set
|
||||
*/
|
||||
public void setClaimsRedirectUris(Set<String> claimsRedirectUris) {
|
||||
this.claimsRedirectUris = claimsRedirectUris;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareStatement
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "software_statement")
|
||||
@Convert(converter = JWTStringConverter.class)
|
||||
public JWT getSoftwareStatement() {
|
||||
return softwareStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareStatement the softwareStatement to set
|
||||
*/
|
||||
public void setSoftwareStatement(JWT softwareStatement) {
|
||||
this.softwareStatement = softwareStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the codeChallengeMethod
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "code_challenge_method")
|
||||
@Convert(converter = PKCEAlgorithmStringConverter.class)
|
||||
public PKCEAlgorithm getCodeChallengeMethod() {
|
||||
return codeChallengeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param codeChallengeMethod the codeChallengeMethod to set
|
||||
*/
|
||||
public void setCodeChallengeMethod(PKCEAlgorithm codeChallengeMethod) {
|
||||
this.codeChallengeMethod = codeChallengeMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deviceCodeValiditySeconds
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="device_code_validity_seconds")
|
||||
public Integer getDeviceCodeValiditySeconds() {
|
||||
return deviceCodeValiditySeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deviceCodeValiditySeconds the deviceCodeValiditySeconds to set
|
||||
*/
|
||||
public void setDeviceCodeValiditySeconds(Integer deviceCodeValiditySeconds) {
|
||||
this.deviceCodeValiditySeconds = deviceCodeValiditySeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareId
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="software_id")
|
||||
public String getSoftwareId() {
|
||||
return softwareId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareId the softwareId to set
|
||||
*/
|
||||
public void setSoftwareId(String softwareId) {
|
||||
this.softwareId = softwareId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the softwareVersion
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="software_version")
|
||||
public String getSoftwareVersion() {
|
||||
return softwareVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareVersion the softwareVersion to set
|
||||
*/
|
||||
public void setSoftwareVersion(String softwareVersion) {
|
||||
this.softwareVersion = softwareVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.MapKeyColumn;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "device_code")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = DeviceCode.QUERY_BY_USER_CODE, query = "select d from DeviceCode d where d.userCode = :" + DeviceCode.PARAM_USER_CODE),
|
||||
@NamedQuery(name = DeviceCode.QUERY_BY_DEVICE_CODE, query = "select d from DeviceCode d where d.deviceCode = :" + DeviceCode.PARAM_DEVICE_CODE),
|
||||
@NamedQuery(name = DeviceCode.QUERY_EXPIRED_BY_DATE, query = "select d from DeviceCode d where d.expiration <= :" + DeviceCode.PARAM_DATE)
|
||||
})
|
||||
public class DeviceCode {
|
||||
|
||||
public static final String QUERY_BY_USER_CODE = "DeviceCode.queryByUserCode";
|
||||
public static final String QUERY_BY_DEVICE_CODE = "DeviceCode.queryByDeviceCode";
|
||||
public static final String QUERY_EXPIRED_BY_DATE = "DeviceCode.queryExpiredByDate";
|
||||
|
||||
public static final String PARAM_USER_CODE = "userCode";
|
||||
public static final String PARAM_DEVICE_CODE = "deviceCode";
|
||||
public static final String PARAM_DATE = "date";
|
||||
|
||||
private Long id;
|
||||
private String deviceCode;
|
||||
private String userCode;
|
||||
private Set<String> scope;
|
||||
private Date expiration;
|
||||
private String clientId;
|
||||
private Map<String, String> requestParameters;
|
||||
private boolean approved;
|
||||
private AuthenticationHolderEntity authenticationHolder;
|
||||
|
||||
public DeviceCode() {
|
||||
|
||||
}
|
||||
|
||||
public DeviceCode(String deviceCode, String userCode, Set<String> scope, String clientId, Map<String, String> params) {
|
||||
this.deviceCode = deviceCode;
|
||||
this.userCode = userCode;
|
||||
this.scope = scope;
|
||||
this.clientId = clientId;
|
||||
this.requestParameters = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the deviceCode
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "device_code")
|
||||
public String getDeviceCode() {
|
||||
return deviceCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deviceCode the deviceCode to set
|
||||
*/
|
||||
public void setDeviceCode(String deviceCode) {
|
||||
this.deviceCode = deviceCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userCode
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "user_code")
|
||||
public String getUserCode() {
|
||||
return userCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userCode the userCode to set
|
||||
*/
|
||||
public void setUserCode(String userCode) {
|
||||
this.userCode = userCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the scope
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="device_code_scope",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="scope")
|
||||
public Set<String> getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param scope the scope to set
|
||||
*/
|
||||
public void setScope(Set<String> scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name = "expiration")
|
||||
public Date getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Date expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the clientId
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "client_id")
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clientId the clientId to set
|
||||
*/
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the params
|
||||
*/
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="device_code_request_parameter",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Column(name="val")
|
||||
@MapKeyColumn(name="param")
|
||||
public Map<String, String> getRequestParameters() {
|
||||
return requestParameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param params the params to set
|
||||
*/
|
||||
public void setRequestParameters(Map<String, String> params) {
|
||||
this.requestParameters = params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the approved
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "approved")
|
||||
public boolean isApproved() {
|
||||
return approved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param approved the approved to set
|
||||
*/
|
||||
public void setApproved(boolean approved) {
|
||||
this.approved = approved;
|
||||
}
|
||||
|
||||
/**
|
||||
* The authentication in place when this token was created.
|
||||
* @return the authentication
|
||||
*/
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "auth_holder_id")
|
||||
public AuthenticationHolderEntity getAuthenticationHolder() {
|
||||
return authenticationHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authentication the authentication to set
|
||||
*/
|
||||
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
|
||||
this.authenticationHolder = authenticationHolder;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,13 +14,12 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -29,6 +29,7 @@ import javax.persistence.Basic;
|
|||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
|
@ -36,19 +37,26 @@ import javax.persistence.GeneratedValue;
|
|||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinTable;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.oauth2.model.convert.JWTStringConverter;
|
||||
import org.mitre.openid.connect.model.ApprovedSite;
|
||||
import org.mitre.uma.model.Permission;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson1Deserializer;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson1Serializer;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Deserializer;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessTokenJackson2Serializer;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -57,19 +65,39 @@ import com.nimbusds.jwt.JWTParser;
|
|||
@Entity
|
||||
@Table(name = "access_token")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getAll", query = "select a from OAuth2AccessTokenEntity a"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getAllExpiredByDate", query = "select a from OAuth2AccessTokenEntity a where a.expiration <= :date"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByRefreshToken", query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :refreshToken"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByClient", query = "select a from OAuth2AccessTokenEntity a where a.client = :client"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByAuthentication", query = "select a from OAuth2AccessTokenEntity a where a.authenticationHolder.authentication = :authentication"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByIdToken", query = "select a from OAuth2AccessTokenEntity a where a.idToken = :idToken"),
|
||||
@NamedQuery(name = "OAuth2AccessTokenEntity.getByTokenValue", query = "select a from OAuth2AccessTokenEntity a where a.value = :tokenValue")
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_ALL, query = "select a from OAuth2AccessTokenEntity a"),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_EXPIRED_BY_DATE, query = "select a from OAuth2AccessTokenEntity a where a.expiration <= :" + OAuth2AccessTokenEntity.PARAM_DATE),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_REFRESH_TOKEN, query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :" + OAuth2AccessTokenEntity.PARAM_REFERSH_TOKEN),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_CLIENT, query = "select a from OAuth2AccessTokenEntity a where a.client = :" + OAuth2AccessTokenEntity.PARAM_CLIENT),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_TOKEN_VALUE, query = "select a from OAuth2AccessTokenEntity a where a.jwt = :" + OAuth2AccessTokenEntity.PARAM_TOKEN_VALUE),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_APPROVED_SITE, query = "select a from OAuth2AccessTokenEntity a where a.approvedSite = :" + OAuth2AccessTokenEntity.PARAM_APPROVED_SITE),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_RESOURCE_SET, query = "select a from OAuth2AccessTokenEntity a join a.permissions p where p.resourceSet.id = :" + OAuth2AccessTokenEntity.PARAM_RESOURCE_SET_ID),
|
||||
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_NAME, query = "select r from OAuth2AccessTokenEntity r where r.authenticationHolder.userAuth.name = :" + OAuth2AccessTokenEntity.PARAM_NAME)
|
||||
})
|
||||
//@JsonSerialize(using = OAuth2AccessTokenSerializer.class)
|
||||
//@JsonDeserialize(using = OAuth2AccessTokenDeserializer.class)
|
||||
@org.codehaus.jackson.map.annotate.JsonSerialize(using = OAuth2AccessTokenJackson1Serializer.class)
|
||||
@org.codehaus.jackson.map.annotate.JsonDeserialize(using = OAuth2AccessTokenJackson1Deserializer.class)
|
||||
@com.fasterxml.jackson.databind.annotation.JsonSerialize(using = OAuth2AccessTokenJackson2Serializer.class)
|
||||
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class)
|
||||
public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
||||
|
||||
public static String ID_TOKEN_FIELD_NAME = "id_token";
|
||||
public static final String QUERY_BY_APPROVED_SITE = "OAuth2AccessTokenEntity.getByApprovedSite";
|
||||
public static final String QUERY_BY_TOKEN_VALUE = "OAuth2AccessTokenEntity.getByTokenValue";
|
||||
public static final String QUERY_BY_CLIENT = "OAuth2AccessTokenEntity.getByClient";
|
||||
public static final String QUERY_BY_REFRESH_TOKEN = "OAuth2AccessTokenEntity.getByRefreshToken";
|
||||
public static final String QUERY_EXPIRED_BY_DATE = "OAuth2AccessTokenEntity.getAllExpiredByDate";
|
||||
public static final String QUERY_ALL = "OAuth2AccessTokenEntity.getAll";
|
||||
public static final String QUERY_BY_RESOURCE_SET = "OAuth2AccessTokenEntity.getByResourceSet";
|
||||
public static final String QUERY_BY_NAME = "OAuth2AccessTokenEntity.getByName";
|
||||
|
||||
public static final String PARAM_TOKEN_VALUE = "tokenValue";
|
||||
public static final String PARAM_CLIENT = "client";
|
||||
public static final String PARAM_REFERSH_TOKEN = "refreshToken";
|
||||
public static final String PARAM_DATE = "date";
|
||||
public static final String PARAM_RESOURCE_SET_ID = "rsid";
|
||||
public static final String PARAM_APPROVED_SITE = "approvedSite";
|
||||
public static final String PARAM_NAME = "name";
|
||||
|
||||
public static final String ID_TOKEN_FIELD_NAME = "id_token";
|
||||
|
||||
private Long id;
|
||||
|
||||
|
@ -79,8 +107,6 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
|
||||
private JWT jwtValue; // JWT-encoded access token value
|
||||
|
||||
private OAuth2AccessTokenEntity idToken; // JWT-encoded OpenID Connect IdToken
|
||||
|
||||
private Date expiration;
|
||||
|
||||
private String tokenType = OAuth2AccessToken.BEARER_TYPE;
|
||||
|
@ -89,6 +115,12 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
|
||||
private Set<String> scope;
|
||||
|
||||
private Set<Permission> permissions;
|
||||
|
||||
private ApprovedSite approvedSite;
|
||||
|
||||
private Map<String, Object> additionalInformation = new HashMap<>(); // ephemeral map of items to be added to the OAuth token response
|
||||
|
||||
/**
|
||||
* Create a new, blank access token
|
||||
*/
|
||||
|
@ -114,16 +146,13 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get all additional information to be sent to the serializer. Inserts a copy of the IdToken (in JWT String form).
|
||||
* Get all additional information to be sent to the serializer as part of the token response.
|
||||
* This map is not persisted to the database.
|
||||
*/
|
||||
@Override
|
||||
@Transient
|
||||
public Map<String, Object> getAdditionalInformation() {
|
||||
Map<String, Object> map = new HashMap<String, Object>(); //super.getAdditionalInformation();
|
||||
if (getIdToken() != null) {
|
||||
map.put(ID_TOKEN_FIELD_NAME, getIdTokenString());
|
||||
}
|
||||
return map;
|
||||
return additionalInformation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -163,22 +192,11 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
* Get the string-encoded value of this access token.
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
@Transient
|
||||
public String getValue() {
|
||||
return jwtValue.serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "value" of this Access Token
|
||||
*
|
||||
* @param value the JWT string
|
||||
* @throws ParseException if "value" is not a properly formatted JWT string
|
||||
*/
|
||||
public void setValue(String value) throws ParseException {
|
||||
setJwt(JWTParser.parse(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
|
@ -241,38 +259,12 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
return getExpiration() == null ? false : System.currentTimeMillis() > getExpiration().getTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the idToken
|
||||
*/
|
||||
@OneToOne(cascade=CascadeType.ALL) // one-to-one mapping for now
|
||||
@JoinColumn(name = "id_token_id")
|
||||
public OAuth2AccessTokenEntity getIdToken() {
|
||||
return idToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idToken the idToken to set
|
||||
*/
|
||||
public void setIdToken(OAuth2AccessTokenEntity idToken) {
|
||||
this.idToken = idToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the idTokenString
|
||||
*/
|
||||
@Transient
|
||||
public String getIdTokenString() {
|
||||
if (idToken != null) {
|
||||
return idToken.getValue(); // get the JWT string value of the id token entity
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the jwtValue
|
||||
*/
|
||||
@Transient
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
@Convert(converter = JWTStringConverter.class)
|
||||
public JWT getJwt() {
|
||||
return jwtValue;
|
||||
}
|
||||
|
@ -300,4 +292,44 @@ public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the permissions
|
||||
*/
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
@JoinTable(
|
||||
name = "access_token_permissions",
|
||||
joinColumns = @JoinColumn(name = "access_token_id"),
|
||||
inverseJoinColumns = @JoinColumn(name = "permission_id")
|
||||
)
|
||||
public Set<Permission> getPermissions() {
|
||||
return permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissions the permissions to set
|
||||
*/
|
||||
public void setPermissions(Set<Permission> permissions) {
|
||||
this.permissions = permissions;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name="approved_site_id")
|
||||
public ApprovedSite getApprovedSite() {
|
||||
return approvedSite;
|
||||
}
|
||||
|
||||
public void setApprovedSite(ApprovedSite approvedSite) {
|
||||
this.approvedSite = approvedSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the ID Token to the additionalInformation map for a token response.
|
||||
* @param idToken
|
||||
*/
|
||||
@Transient
|
||||
public void setIdToken(JWT idToken) {
|
||||
if (idToken != null) {
|
||||
additionalInformation.put(ID_TOKEN_FIELD_NAME, idToken.serialize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,17 +14,17 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
|
@ -37,10 +38,10 @@ import javax.persistence.Table;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.oauth2.model.convert.JWTStringConverter;
|
||||
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -49,14 +50,25 @@ import com.nimbusds.jwt.JWTParser;
|
|||
@Entity
|
||||
@Table(name = "refresh_token")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getAll", query = "select r from OAuth2RefreshTokenEntity r"),
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getAllExpiredByDate", query = "select r from OAuth2RefreshTokenEntity r where r.expiration <= :date"),
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByClient", query = "select r from OAuth2RefreshTokenEntity r where r.client = :client"),
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByTokenValue", query = "select r from OAuth2RefreshTokenEntity r where r.value = :tokenValue"),
|
||||
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByAuthentication", query = "select r from OAuth2RefreshTokenEntity r where r.authenticationHolder.authentication = :authentication")
|
||||
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_ALL, query = "select r from OAuth2RefreshTokenEntity r"),
|
||||
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_EXPIRED_BY_DATE, query = "select r from OAuth2RefreshTokenEntity r where r.expiration <= :" + OAuth2RefreshTokenEntity.PARAM_DATE),
|
||||
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_CLIENT, query = "select r from OAuth2RefreshTokenEntity r where r.client = :" + OAuth2RefreshTokenEntity.PARAM_CLIENT),
|
||||
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_TOKEN_VALUE, query = "select r from OAuth2RefreshTokenEntity r where r.jwt = :" + OAuth2RefreshTokenEntity.PARAM_TOKEN_VALUE),
|
||||
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_NAME, query = "select r from OAuth2RefreshTokenEntity r where r.authenticationHolder.userAuth.name = :" + OAuth2RefreshTokenEntity.PARAM_NAME)
|
||||
})
|
||||
public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
||||
|
||||
public static final String QUERY_BY_TOKEN_VALUE = "OAuth2RefreshTokenEntity.getByTokenValue";
|
||||
public static final String QUERY_BY_CLIENT = "OAuth2RefreshTokenEntity.getByClient";
|
||||
public static final String QUERY_EXPIRED_BY_DATE = "OAuth2RefreshTokenEntity.getAllExpiredByDate";
|
||||
public static final String QUERY_ALL = "OAuth2RefreshTokenEntity.getAll";
|
||||
public static final String QUERY_BY_NAME = "OAuth2RefreshTokenEntity.getByName";
|
||||
|
||||
public static final String PARAM_TOKEN_VALUE = "tokenValue";
|
||||
public static final String PARAM_CLIENT = "client";
|
||||
public static final String PARAM_DATE = "date";
|
||||
public static final String PARAM_NAME = "name";
|
||||
|
||||
private Long id;
|
||||
|
||||
private AuthenticationHolderEntity authenticationHolder;
|
||||
|
@ -116,21 +128,11 @@ public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
|||
* Get the JWT-encoded value of this token
|
||||
*/
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
@Transient
|
||||
public String getValue() {
|
||||
return jwt.serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this token as a string. Parses the string into a JWT.
|
||||
* @param value
|
||||
* @throws ParseException if the value is not a valid JWT string
|
||||
*/
|
||||
public void setValue(String value) throws ParseException {
|
||||
setJwt(JWTParser.parse(value));
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
|
||||
@Column(name = "expiration")
|
||||
|
@ -175,7 +177,9 @@ public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
|
|||
* Get the JWT object directly
|
||||
* @return the jwt
|
||||
*/
|
||||
@Transient
|
||||
@Basic
|
||||
@Column(name="token_value")
|
||||
@Convert(converter = JWTStringConverter.class)
|
||||
public JWT getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import com.nimbusds.jose.Algorithm;
|
||||
import com.nimbusds.jose.Requirement;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public final class PKCEAlgorithm extends Algorithm {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 7752852583210088925L;
|
||||
|
||||
public static final PKCEAlgorithm plain = new PKCEAlgorithm("plain", Requirement.REQUIRED);
|
||||
|
||||
public static final PKCEAlgorithm S256 = new PKCEAlgorithm("S256", Requirement.OPTIONAL);
|
||||
|
||||
public PKCEAlgorithm(String name, Requirement req) {
|
||||
super(name, req);
|
||||
}
|
||||
|
||||
public PKCEAlgorithm(String name) {
|
||||
super(name, null);
|
||||
}
|
||||
|
||||
public static PKCEAlgorithm parse(final String s) {
|
||||
if (s.equals(plain.getName())) {
|
||||
return plain;
|
||||
} else if (s.equals(S256.getName())) {
|
||||
return S256;
|
||||
} else {
|
||||
return new PKCEAlgorithm(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -23,17 +24,17 @@ import java.util.Date;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mitre.jose.JWEAlgorithmEmbed;
|
||||
import org.mitre.jose.JWEEncryptionMethodEmbed;
|
||||
import org.mitre.jose.JWSAlgorithmEmbed;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.jwk.JWKSet;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -47,6 +48,7 @@ public class RegisteredClient {
|
|||
private Date clientSecretExpiresAt;
|
||||
private Date clientIdIssuedAt;
|
||||
private ClientDetailsEntity client;
|
||||
private JsonObject src;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -463,6 +465,22 @@ public class RegisteredClient {
|
|||
public void setJwksUri(String jwksUri) {
|
||||
client.setJwksUri(jwksUri);
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getJwks()
|
||||
*/
|
||||
public JWKSet getJwks() {
|
||||
return client.getJwks();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwks
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setJwks(com.nimbusds.jose.jwk.JWKSet)
|
||||
*/
|
||||
public void setJwks(JWKSet jwks) {
|
||||
client.setJwks(jwks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getSectorIdentifierUri()
|
||||
|
@ -549,17 +567,17 @@ public class RegisteredClient {
|
|||
}
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getPostLogoutRedirectUri()
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getPostLogoutRedirectUris()
|
||||
*/
|
||||
public String getPostLogoutRedirectUri() {
|
||||
return client.getPostLogoutRedirectUri();
|
||||
public Set<String> getPostLogoutRedirectUris() {
|
||||
return client.getPostLogoutRedirectUris();
|
||||
}
|
||||
/**
|
||||
* @param postLogoutRedirectUri
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setPostLogoutRedirectUri(java.lang.String)
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setPostLogoutRedirectUris(java.lang.String)
|
||||
*/
|
||||
public void setPostLogoutRedirectUri(String postLogoutRedirectUri) {
|
||||
client.setPostLogoutRedirectUri(postLogoutRedirectUri);
|
||||
public void setPostLogoutRedirectUris(Set<String> postLogoutRedirectUri) {
|
||||
client.setPostLogoutRedirectUris(postLogoutRedirectUri);
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
|
@ -575,117 +593,6 @@ public class RegisteredClient {
|
|||
public void setRequestUris(Set<String> requestUris) {
|
||||
client.setRequestUris(requestUris);
|
||||
}
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getRequestObjectSigningAlgEmbed()
|
||||
*/
|
||||
public JWSAlgorithmEmbed getRequestObjectSigningAlgEmbed() {
|
||||
return client.getRequestObjectSigningAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requestObjectSigningAlg
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setRequestObjectSigningAlgEmbed(org.mitre.jose.JWSAlgorithmEmbed)
|
||||
*/
|
||||
public void setRequestObjectSigningAlgEmbed(JWSAlgorithmEmbed requestObjectSigningAlg) {
|
||||
client.setRequestObjectSigningAlgEmbed(requestObjectSigningAlg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getUserInfoSignedResponseAlgEmbed()
|
||||
*/
|
||||
public JWSAlgorithmEmbed getUserInfoSignedResponseAlgEmbed() {
|
||||
return client.getUserInfoSignedResponseAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userInfoSignedResponseAlg
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setUserInfoSignedResponseAlgEmbed(org.mitre.jose.JWSAlgorithmEmbed)
|
||||
*/
|
||||
public void setUserInfoSignedResponseAlgEmbed(JWSAlgorithmEmbed userInfoSignedResponseAlg) {
|
||||
client.setUserInfoSignedResponseAlgEmbed(userInfoSignedResponseAlg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getUserInfoEncryptedResponseAlgEmbed()
|
||||
*/
|
||||
public JWEAlgorithmEmbed getUserInfoEncryptedResponseAlgEmbed() {
|
||||
return client.getUserInfoEncryptedResponseAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userInfoEncryptedResponseAlg
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setUserInfoEncryptedResponseAlgEmbed(org.mitre.jose.JWEAlgorithmEmbed)
|
||||
*/
|
||||
public void setUserInfoEncryptedResponseAlgEmbed(JWEAlgorithmEmbed userInfoEncryptedResponseAlg) {
|
||||
client.setUserInfoEncryptedResponseAlgEmbed(userInfoEncryptedResponseAlg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getUserInfoEncryptedResponseEncEmbed()
|
||||
*/
|
||||
public JWEEncryptionMethodEmbed getUserInfoEncryptedResponseEncEmbed() {
|
||||
return client.getUserInfoEncryptedResponseEncEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userInfoEncryptedResponseEnc
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setUserInfoEncryptedResponseEncEmbed(org.mitre.jose.JWEEncryptionMethodEmbed)
|
||||
*/
|
||||
public void setUserInfoEncryptedResponseEncEmbed(JWEEncryptionMethodEmbed userInfoEncryptedResponseEnc) {
|
||||
client.setUserInfoEncryptedResponseEncEmbed(userInfoEncryptedResponseEnc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getIdTokenSignedResponseAlgEmbed()
|
||||
*/
|
||||
public JWSAlgorithmEmbed getIdTokenSignedResponseAlgEmbed() {
|
||||
return client.getIdTokenSignedResponseAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idTokenSignedResponseAlg
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setIdTokenSignedResponseAlgEmbed(org.mitre.jose.JWSAlgorithmEmbed)
|
||||
*/
|
||||
public void setIdTokenSignedResponseAlgEmbed(JWSAlgorithmEmbed idTokenSignedResponseAlg) {
|
||||
client.setIdTokenSignedResponseAlgEmbed(idTokenSignedResponseAlg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getIdTokenEncryptedResponseAlgEmbed()
|
||||
*/
|
||||
public JWEAlgorithmEmbed getIdTokenEncryptedResponseAlgEmbed() {
|
||||
return client.getIdTokenEncryptedResponseAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idTokenEncryptedResponseAlg
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setIdTokenEncryptedResponseAlgEmbed(org.mitre.jose.JWEAlgorithmEmbed)
|
||||
*/
|
||||
public void setIdTokenEncryptedResponseAlgEmbed(JWEAlgorithmEmbed idTokenEncryptedResponseAlg) {
|
||||
client.setIdTokenEncryptedResponseAlgEmbed(idTokenEncryptedResponseAlg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getIdTokenEncryptedResponseEncEmbed()
|
||||
*/
|
||||
public JWEEncryptionMethodEmbed getIdTokenEncryptedResponseEncEmbed() {
|
||||
return client.getIdTokenEncryptedResponseEncEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param idTokenEncryptedResponseEnc
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setIdTokenEncryptedResponseEncEmbed(org.mitre.jose.JWEEncryptionMethodEmbed)
|
||||
*/
|
||||
public void setIdTokenEncryptedResponseEncEmbed(JWEEncryptionMethodEmbed idTokenEncryptedResponseEnc) {
|
||||
client.setIdTokenEncryptedResponseEncEmbed(idTokenEncryptedResponseEnc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
|
@ -799,22 +706,6 @@ public class RegisteredClient {
|
|||
client.setIdTokenEncryptedResponseEnc(idTokenEncryptedResponseEnc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getTokenEndpointAuthSigningAlgEmbed()
|
||||
*/
|
||||
public JWSAlgorithmEmbed getTokenEndpointAuthSigningAlgEmbed() {
|
||||
return client.getTokenEndpointAuthSigningAlgEmbed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tokenEndpointAuthSigningAlgEmbed
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setTokenEndpointAuthSigningAlgEmbed(org.mitre.jose.JWSAlgorithmEmbed)
|
||||
*/
|
||||
public void setTokenEndpointAuthSigningAlgEmbed(JWSAlgorithmEmbed tokenEndpointAuthSigningAlgEmbed) {
|
||||
client.setTokenEndpointAuthSigningAlgEmbed(tokenEndpointAuthSigningAlgEmbed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getTokenEndpointAuthSigningAlg()
|
||||
|
@ -894,6 +785,116 @@ public class RegisteredClient {
|
|||
this.clientIdIssuedAt = issuedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getClaimsRedirectUris()
|
||||
*/
|
||||
public Set<String> getClaimsRedirectUris() {
|
||||
return client.getClaimsRedirectUris();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param claimsRedirectUris
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setClaimsRedirectUris(java.util.Set)
|
||||
*/
|
||||
public void setClaimsRedirectUris(Set<String> claimsRedirectUris) {
|
||||
client.setClaimsRedirectUris(claimsRedirectUris);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getSoftwareStatement()
|
||||
*/
|
||||
public JWT getSoftwareStatement() {
|
||||
return client.getSoftwareStatement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareStatement
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setSoftwareStatement(com.nimbusds.jwt.JWT)
|
||||
*/
|
||||
public void setSoftwareStatement(JWT softwareStatement) {
|
||||
client.setSoftwareStatement(softwareStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getCodeChallengeMethod()
|
||||
*/
|
||||
public PKCEAlgorithm getCodeChallengeMethod() {
|
||||
return client.getCodeChallengeMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param codeChallengeMethod
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setCodeChallengeMethod(org.mitre.oauth2.model.PKCEAlgorithm)
|
||||
*/
|
||||
public void setCodeChallengeMethod(PKCEAlgorithm codeChallengeMethod) {
|
||||
client.setCodeChallengeMethod(codeChallengeMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the src
|
||||
*/
|
||||
public JsonObject getSource() {
|
||||
return src;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param src the src to set
|
||||
*/
|
||||
public void setSource(JsonObject src) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getDeviceCodeValiditySeconds()
|
||||
*/
|
||||
public Integer getDeviceCodeValiditySeconds() {
|
||||
return client.getDeviceCodeValiditySeconds();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param deviceCodeValiditySeconds
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setDeviceCodeValiditySeconds(java.lang.Integer)
|
||||
*/
|
||||
public void setDeviceCodeValiditySeconds(Integer deviceCodeValiditySeconds) {
|
||||
client.setDeviceCodeValiditySeconds(deviceCodeValiditySeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getSoftwareId()
|
||||
*/
|
||||
public String getSoftwareId() {
|
||||
return client.getSoftwareId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareId
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setSoftwareId(java.lang.String)
|
||||
*/
|
||||
public void setSoftwareId(String softwareId) {
|
||||
client.setSoftwareId(softwareId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#getSoftwareVersion()
|
||||
*/
|
||||
public String getSoftwareVersion() {
|
||||
return client.getSoftwareVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param softwareVersion
|
||||
* @see org.mitre.oauth2.model.ClientDetailsEntity#setSoftwareVersion(java.lang.String)
|
||||
*/
|
||||
public void setSoftwareVersion(String softwareVersion) {
|
||||
client.setSoftwareVersion(softwareVersion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
public interface RegisteredClientFields {
|
||||
public String SOFTWARE_ID = "software_id";
|
||||
public String SOFTWARE_VERSION = "software_version";
|
||||
public String SOFTWARE_STATEMENT = "software_statement";
|
||||
public String CLAIMS_REDIRECT_URIS = "claims_redirect_uris";
|
||||
public String CLIENT_SECRET_EXPIRES_AT = "client_secret_expires_at";
|
||||
public String CLIENT_ID_ISSUED_AT = "client_id_issued_at";
|
||||
public String REGISTRATION_CLIENT_URI = "registration_client_uri";
|
||||
public String REGISTRATION_ACCESS_TOKEN = "registration_access_token";
|
||||
public String REQUEST_URIS = "request_uris";
|
||||
public String POST_LOGOUT_REDIRECT_URIS = "post_logout_redirect_uris";
|
||||
public String INITIATE_LOGIN_URI = "initiate_login_uri";
|
||||
public String DEFAULT_ACR_VALUES = "default_acr_values";
|
||||
public String REQUIRE_AUTH_TIME = "require_auth_time";
|
||||
public String DEFAULT_MAX_AGE = "default_max_age";
|
||||
public String TOKEN_ENDPOINT_AUTH_SIGNING_ALG = "token_endpoint_auth_signing_alg";
|
||||
public String ID_TOKEN_ENCRYPTED_RESPONSE_ENC = "id_token_encrypted_response_enc";
|
||||
public String ID_TOKEN_ENCRYPTED_RESPONSE_ALG = "id_token_encrypted_response_alg";
|
||||
public String ID_TOKEN_SIGNED_RESPONSE_ALG = "id_token_signed_response_alg";
|
||||
public String USERINFO_ENCRYPTED_RESPONSE_ENC = "userinfo_encrypted_response_enc";
|
||||
public String USERINFO_ENCRYPTED_RESPONSE_ALG = "userinfo_encrypted_response_alg";
|
||||
public String USERINFO_SIGNED_RESPONSE_ALG = "userinfo_signed_response_alg";
|
||||
public String REQUEST_OBJECT_SIGNING_ALG = "request_object_signing_alg";
|
||||
public String SUBJECT_TYPE = "subject_type";
|
||||
public String SECTOR_IDENTIFIER_URI = "sector_identifier_uri";
|
||||
public String APPLICATION_TYPE = "application_type";
|
||||
public String JWKS_URI = "jwks_uri";
|
||||
public String JWKS = "jwks";
|
||||
public String SCOPE_SEPARATOR = " ";
|
||||
public String POLICY_URI = "policy_uri";
|
||||
public String RESPONSE_TYPES = "response_types";
|
||||
public String GRANT_TYPES = "grant_types";
|
||||
public String SCOPE = "scope";
|
||||
public String TOKEN_ENDPOINT_AUTH_METHOD = "token_endpoint_auth_method";
|
||||
public String TOS_URI = "tos_uri";
|
||||
public String CONTACTS = "contacts";
|
||||
public String LOGO_URI = "logo_uri";
|
||||
public String CLIENT_URI = "client_uri";
|
||||
public String CLIENT_NAME = "client_name";
|
||||
public String REDIRECT_URIS = "redirect_uris";
|
||||
public String CLIENT_SECRET = "client_secret";
|
||||
public String CLIENT_ID = "client_id";
|
||||
public String CODE_CHALLENGE_METHOD = "code_challenge_method";
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.model;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Convert;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
* This class stands in for an original Authentication object.
|
||||
*
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
@Entity
|
||||
@Table(name="saved_user_auth")
|
||||
public class SavedUserAuthentication implements Authentication {
|
||||
|
||||
private static final long serialVersionUID = -1804249963940323488L;
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Collection<GrantedAuthority> authorities;
|
||||
|
||||
private boolean authenticated;
|
||||
|
||||
private String sourceClass;
|
||||
|
||||
/**
|
||||
* Create a Saved Auth from an existing Auth token
|
||||
*/
|
||||
public SavedUserAuthentication(Authentication src) {
|
||||
setName(src.getName());
|
||||
setAuthorities(new HashSet<>(src.getAuthorities()));
|
||||
setAuthenticated(src.isAuthenticated());
|
||||
|
||||
if (src instanceof SavedUserAuthentication) {
|
||||
// if we're copying in a saved auth, carry over the original class name
|
||||
setSourceClass(((SavedUserAuthentication) src).getSourceClass());
|
||||
} else {
|
||||
setSourceClass(src.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty saved auth
|
||||
*/
|
||||
public SavedUserAuthentication() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(name = "id")
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="name")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(
|
||||
name="saved_user_auth_authority",
|
||||
joinColumns=@JoinColumn(name="owner_id")
|
||||
)
|
||||
@Convert(converter = SimpleGrantedAuthorityStringConverter.class)
|
||||
@Column(name="authority")
|
||||
public Collection<GrantedAuthority> getAuthorities() {
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transient
|
||||
public Object getCredentials() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transient
|
||||
public Object getDetails() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transient
|
||||
public Object getPrincipal() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Basic
|
||||
@Column(name="authenticated")
|
||||
public boolean isAuthenticated() {
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
|
||||
this.authenticated = isAuthenticated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the sourceClass
|
||||
*/
|
||||
@Basic
|
||||
@Column(name="source_class")
|
||||
public String getSourceClass() {
|
||||
return sourceClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sourceClass the sourceClass to set
|
||||
*/
|
||||
public void setSourceClass(String sourceClass) {
|
||||
this.sourceClass = sourceClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorities the authorities to set
|
||||
*/
|
||||
public void setAuthorities(Collection<GrantedAuthority> authorities) {
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2014 The MITRE Corporation
|
||||
* and the MIT Kerberos and Internet Trust Consortium
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Portions copyright 2011-2013 The MITRE Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -13,7 +14,7 @@
|
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
******************************************************************************/
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -28,7 +29,6 @@ import javax.persistence.Id;
|
|||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -37,20 +37,22 @@ import javax.persistence.Transient;
|
|||
@Entity
|
||||
@Table(name = "system_scope")
|
||||
@NamedQueries({
|
||||
@NamedQuery(name = "SystemScope.findAll", query = "select s from SystemScope s ORDER BY s.id"),
|
||||
@NamedQuery(name = "SystemScope.getByValue", query = "select s from SystemScope s WHERE s.value = :value")
|
||||
@NamedQuery(name = SystemScope.QUERY_ALL, query = "select s from SystemScope s ORDER BY s.id"),
|
||||
@NamedQuery(name = SystemScope.QUERY_BY_VALUE, query = "select s from SystemScope s WHERE s.value = :" + SystemScope.PARAM_VALUE)
|
||||
})
|
||||
public class SystemScope {
|
||||
|
||||
public static final String QUERY_BY_VALUE = "SystemScope.getByValue";
|
||||
public static final String QUERY_ALL = "SystemScope.findAll";
|
||||
|
||||
public static final String PARAM_VALUE = "value";
|
||||
|
||||
private Long id;
|
||||
private String value; // scope value
|
||||
private String description; // human-readable description
|
||||
private String icon; // class of the icon to display on the auth page
|
||||
private boolean allowDynReg = false; // can a dynamically registered client ask for this scope?
|
||||
private boolean defaultScope = false; // is this a default scope for newly-registered clients?
|
||||
private boolean structured = false; // is this a default scope for newly-registered clients?
|
||||
private String structuredParamDescription;
|
||||
private String structuredValue;
|
||||
private boolean restricted = false; // is this scope restricted to admin-only registration access?
|
||||
|
||||
/**
|
||||
* Make a blank system scope with no value
|
||||
|
@ -124,20 +126,6 @@ public class SystemScope {
|
|||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
/**
|
||||
* @return the allowDynReg
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "allow_dyn_reg")
|
||||
public boolean isAllowDynReg() {
|
||||
return allowDynReg;
|
||||
}
|
||||
/**
|
||||
* @param allowDynReg the allowDynReg to set
|
||||
*/
|
||||
public void setAllowDynReg(boolean allowDynReg) {
|
||||
this.allowDynReg = allowDynReg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the defaultScope
|
||||
|
@ -156,51 +144,21 @@ public class SystemScope {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the isStructured status
|
||||
* @return the restricted
|
||||
*/
|
||||
@Basic
|
||||
@Column(name = "structured")
|
||||
public boolean isStructured() {
|
||||
return structured;
|
||||
@Column(name = "restricted")
|
||||
public boolean isRestricted() {
|
||||
return restricted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param structured the structured to set
|
||||
* @param restricted the restricted to set
|
||||
*/
|
||||
public void setStructured(boolean structured) {
|
||||
this.structured = structured;
|
||||
public void setRestricted(boolean restricted) {
|
||||
this.restricted = restricted;
|
||||
}
|
||||
|
||||
@Basic
|
||||
@Column(name = "structured_param_description")
|
||||
public String getStructuredParamDescription() {
|
||||
return structuredParamDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isStructured the isStructured to set
|
||||
*/
|
||||
public void setStructuredParamDescription(String d) {
|
||||
this.structuredParamDescription = d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the structuredValue
|
||||
*/
|
||||
@Transient // we don't save the value of a system scope separately
|
||||
public String getStructuredValue() {
|
||||
return structuredValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param structuredValue the structuredValue to set
|
||||
*/
|
||||
public void setStructuredValue(String structuredValue) {
|
||||
this.structuredValue = structuredValue;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
|
@ -208,14 +166,12 @@ public class SystemScope {
|
|||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + (allowDynReg ? 1231 : 1237);
|
||||
result = prime * result + (defaultScope ? 1231 : 1237);
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result
|
||||
+ ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((icon == null) ? 0 : icon.hashCode());
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + (structured ? 1231 : 1237);
|
||||
result = prime * result + ((structuredParamDescription == null) ? 0 : structuredParamDescription.hashCode());
|
||||
result = prime * result + ((structuredValue == null) ? 0 : structuredValue.hashCode());
|
||||
result = prime * result + (restricted ? 1231 : 1237);
|
||||
result = prime * result + ((value == null) ? 0 : value.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
@ -231,13 +187,10 @@ public class SystemScope {
|
|||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof SystemScope)) {
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SystemScope other = (SystemScope) obj;
|
||||
if (allowDynReg != other.allowDynReg) {
|
||||
return false;
|
||||
}
|
||||
if (defaultScope != other.defaultScope) {
|
||||
return false;
|
||||
}
|
||||
|
@ -262,21 +215,7 @@ public class SystemScope {
|
|||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (structured != other.structured) {
|
||||
return false;
|
||||
}
|
||||
if (structuredParamDescription == null) {
|
||||
if (other.structuredParamDescription != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!structuredParamDescription.equals(other.structuredParamDescription)) {
|
||||
return false;
|
||||
}
|
||||
if (structuredValue == null) {
|
||||
if (other.structuredValue != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!structuredValue.equals(other.structuredValue)) {
|
||||
if (restricted != other.restricted) {
|
||||
return false;
|
||||
}
|
||||
if (value == null) {
|
||||
|
@ -294,8 +233,9 @@ public class SystemScope {
|
|||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SystemScope [id=" + id + ", value=" + value + ", description=" + description + ", icon=" + icon + ", allowDynReg=" + allowDynReg + ", defaultScope=" + defaultScope + ", structured=" + structured + ", structuredParamDescription=" + structuredParamDescription + ", structuredValue="
|
||||
+ structuredValue + "]";
|
||||
return "SystemScope [id=" + id + ", value=" + value + ", description="
|
||||
+ description + ", icon=" + icon + ", defaultScope="
|
||||
+ defaultScope + ", restricted=" + restricted + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.model.convert;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
import com.nimbusds.jose.JWEAlgorithm;
|
||||
|
||||
@Converter
|
||||
public class JWEAlgorithmStringConverter implements AttributeConverter<JWEAlgorithm, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(JWEAlgorithm attribute) {
|
||||
if (attribute != null) {
|
||||
return attribute.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public JWEAlgorithm convertToEntityAttribute(String dbData) {
|
||||
if (dbData != null) {
|
||||
return JWEAlgorithm.parse(dbData);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2018 The MIT Internet Trust Consortium
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*******************************************************************************/
|
||||
|
||||
package org.mitre.oauth2.model.convert;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
import com.nimbusds.jose.EncryptionMethod;
|
||||
|
||||
@Converter
|
||||
public class JWEEncryptionMethodStringConverter implements AttributeConverter<EncryptionMethod, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(EncryptionMethod attribute) {
|
||||
if (attribute != null) {
|
||||
return attribute.getName();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public EncryptionMethod convertToEntityAttribute(String dbData) {
|
||||
if (dbData != null) {
|
||||
return EncryptionMethod.parse(dbData);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue