mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
811 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9533595394 | ||
|
5b977b1495 | ||
|
1c47ec51f8 | ||
|
fbf4388b01 | ||
|
a867fdd891 | ||
|
1041a39d08 | ||
|
e23570535f | ||
|
b1cf6a8436 | ||
|
fe0ed765a5 | ||
|
7ce31bda87 | ||
|
630a92b45f | ||
|
2b76e2bf6e | ||
|
115237bc1a | ||
|
6383a58755 | ||
|
614fbde56e | ||
|
0fbe109e20 | ||
|
57216984e9 | ||
|
267bd3c5d4 | ||
|
a18b8c57b2 | ||
|
cca401e66e | ||
|
55ff59edf4 | ||
|
a49c762683 | ||
|
b5b5d9f347 | ||
|
07b2758cba | ||
|
864a27f2c8 | ||
|
a698a4da7e | ||
|
95cdaae17f | ||
|
61986db5ee | ||
|
878afeb9f9 | ||
|
e9dd1478c4 | ||
|
945731cb39 | ||
|
f688401f63 | ||
|
09770dc537 | ||
|
dcf3f50b87 | ||
|
59e8785f50 | ||
|
ca54a387c8 | ||
|
6fea054381 | ||
|
ed17b6540e | ||
|
e27b13ee7d | ||
|
67f835a606 | ||
|
8685006743 | ||
|
400eae153b | ||
|
c880d5c1ec | ||
|
9ee2e7271f | ||
|
b629b5e53f | ||
|
4b775fe241 | ||
|
8196f5c832 | ||
|
890fdeba16 | ||
|
c2e83ff359 | ||
|
51a1a75d37 | ||
|
251190d828 | ||
|
a350705a01 | ||
|
7293ff9e9d | ||
|
c207addf87 | ||
|
3af75729b8 | ||
|
7b8d9c9af3 | ||
|
15b6506644 | ||
|
bd12c8b1a9 | ||
|
c3c49c83f9 | ||
|
2f459b6470 | ||
|
ee91072455 | ||
|
25f93071ea | ||
|
079ed0040a | ||
|
5bbf703711 | ||
|
d635b3484b | ||
|
3365f3d733 | ||
|
9e828f8f3c | ||
|
c7a5a57304 | ||
|
ae0edc40aa | ||
|
264bc7b625 | ||
|
7159352108 | ||
|
a70bc2360a | ||
|
472ec68bbe | ||
|
e946c1e106 | ||
|
4c392db673 | ||
|
66e473b1f0 | ||
|
91c8daeb99 | ||
|
9ffe806112 | ||
|
9e04da01de | ||
|
592f60de70 | ||
|
5ae9827d67 | ||
|
5e8d2fe0f5 | ||
|
9b665f494f | ||
|
ced63e2051 | ||
|
c3ffed2daf | ||
|
ecad2b98ae | ||
|
a0402f1994 | ||
|
6e74de50e5 | ||
|
4ab9c52767 | ||
|
2b2d4a3df7 | ||
|
0ae8863322 | ||
|
4c55b6879d | ||
|
9590550799 | ||
|
c40a10a071 | ||
|
f7f3cdee24 | ||
|
edf0ee8622 | ||
|
c490cd4ef2 | ||
|
a716a08be6 | ||
|
3b4a8cf5f3 | ||
|
8f0cb0e78c | ||
|
fb1fa71b5d | ||
|
0216638903 | ||
|
5074ad9a6c | ||
|
721a31534e | ||
|
01517bb57a | ||
|
0f2c6e7f4e | ||
|
320d9e65d5 | ||
|
1218cede79 | ||
|
8ff0cb6495 | ||
|
1bdeb71efb | ||
|
1632b80631 | ||
|
5760450854 | ||
|
9c66688d19 | ||
|
da53067e63 | ||
|
84172c0d29 | ||
|
997d390f3d | ||
|
e2794c47af | ||
|
0d0aaa8764 | ||
|
ad270f7d9d | ||
|
a1bdaae9a9 | ||
|
e08669d50c | ||
|
d02437dd73 | ||
|
cee4147688 | ||
|
eedcfe115c | ||
|
f06adb38cd | ||
|
9675dff220 | ||
|
2488cbd55d | ||
|
27d4441d1d | ||
|
bc82f5badd | ||
|
7f539f8736 | ||
|
a4b65241ad | ||
|
8b601d79b9 | ||
|
d0878300d0 | ||
|
97c138bb0b | ||
|
937d425e4c | ||
|
ff5ea52ccd | ||
|
a2460886f6 | ||
|
65bcc97fc3 | ||
|
60c45ab8fe | ||
|
a644eacea7 | ||
|
13baa0bb26 | ||
|
e8a01c3bcd | ||
|
064eb85f4e | ||
|
ad5b242d10 | ||
|
704e114568 | ||
|
73cd377c4b | ||
|
3b36ae9000 | ||
|
7f67000d53 | ||
|
de000b72a4 | ||
|
e808528cc8 | ||
|
fb77a78fb3 | ||
|
0d8cb0d06f | ||
|
fc53d636f5 | ||
|
dbcaaa1f35 | ||
|
5d6634aa9f | ||
|
099c9ce41b | ||
|
186853390a | ||
|
335630f150 | ||
|
de13e14cdd | ||
|
2bd45f2a6b | ||
|
e20c529f39 | ||
|
08ad67e401 | ||
|
7f2fd69d0a | ||
|
29068dd84c | ||
|
174ae490fc | ||
|
fa3fb36ed8 | ||
|
21e2ccd0fb | ||
|
aa0570c932 | ||
|
9a8b7ec898 | ||
|
1f6bb40952 | ||
|
2f914a0aa3 | ||
|
95e3c1d1a2 | ||
|
64d4c4a38a | ||
|
655f6b9771 | ||
|
d95958bae4 | ||
|
85b9412813 | ||
|
1a5030200a | ||
|
796106b6c1 | ||
|
4234b69f3a | ||
|
6dd4caf056 | ||
|
f6cc8bbb42 | ||
|
0115c41eea | ||
|
f314154216 | ||
|
9b97778618 | ||
|
5e326d9e45 | ||
|
d2760e4ec7 | ||
|
2025749fa4 | ||
|
1c913fe75e | ||
|
556c9fa782 | ||
|
c5bc63027f | ||
|
ac9955b393 | ||
|
fccb06ed67 | ||
|
f29703ea24 | ||
|
dcc3f5d856 | ||
|
264eba9f20 | ||
|
c2c199cf98 | ||
|
0b6bcad9fb | ||
|
38a7e53cb5 | ||
|
f4b83baf74 | ||
|
5a08a0cbe2 | ||
|
7a628409db | ||
|
c6d806d3f7 | ||
|
bfcf7af4d8 | ||
|
d96f57d27f | ||
|
95919a688e | ||
|
8b185e0580 | ||
|
ca776e83a2 | ||
|
ddf3f1b890 | ||
|
a40ac5d77b | ||
|
4bc89f3fc2 | ||
|
11d25eb5a1 | ||
|
770bda8f10 | ||
|
7a8c92b3d9 | ||
|
96620c8b3b | ||
|
92a101f263 | ||
|
b85f81c429 | ||
|
8fb64041df | ||
|
44155a8efc | ||
|
b7b1f56d0c | ||
|
3e5889e93b | ||
|
ef5904ab1a | ||
|
94cc7c2bc7 | ||
|
1e1043c04f | ||
|
8591fc7686 | ||
|
86b75edca0 | ||
|
13ddec3283 | ||
|
322caa77af | ||
|
95634fb390 | ||
|
6beb8d42ff | ||
|
6cffbfe33b | ||
|
5fcb47d66a | ||
|
cbd45cc5ab | ||
|
8566a128c8 | ||
|
419cb6d149 | ||
|
f1d06e7c33 | ||
|
212938d1e2 | ||
|
cd19f11799 | ||
|
4862ca7d60 | ||
|
660378c7b3 | ||
|
06ee612bb1 | ||
|
3c4347e385 | ||
|
168e7640c6 | ||
|
3d08051cbb | ||
|
0486d93fa3 | ||
|
5a8659471c | ||
|
f6664c6917 | ||
|
5f22ead287 | ||
|
19b12cda8e | ||
|
6c787c374c | ||
|
cd68103267 | ||
|
6332ecfa0b | ||
|
e43d95415b | ||
|
d755a8c01d | ||
|
c7a904ca40 | ||
|
8ee4dc7eb9 | ||
|
645f719ee9 | ||
|
0cc13630cc | ||
|
e21a13c82c | ||
|
a4ce1e510e | ||
|
ad05a5cae6 | ||
|
e6cc6c35ec | ||
|
f74bca33ab | ||
|
90d9d7bdd6 | ||
|
8d8dbaea0c | ||
|
03391e9630 | ||
|
7242a8db31 | ||
|
f44b618531 | ||
|
9e4fd82763 | ||
|
0744d8e926 | ||
|
3efe7b3c0a | ||
|
44ff8692dc | ||
|
6108c06e34 | ||
|
dce1620f60 | ||
|
bcd84320da | ||
|
a40374e6ec | ||
|
748ae15376 | ||
|
7811721d28 | ||
|
c5e5ae5555 | ||
|
8f724bb720 | ||
|
e9f8e7ac19 | ||
|
c4830608a2 | ||
|
65d981ad32 | ||
|
3de1b5917a | ||
|
0fbe447862 | ||
|
84a9802a67 | ||
|
f7b3c018c5 | ||
|
a88c30cb53 | ||
|
5e6f0fc6a3 | ||
|
b57b497cb7 | ||
|
0b061e3086 | ||
|
304ea2baf4 | ||
|
56060b2c16 | ||
|
633746b02e | ||
|
94b221c8a1 | ||
|
20ad5d251c | ||
|
e95a228128 | ||
|
dc2919710c | ||
|
936b8f93ec | ||
|
c1d15aa15c | ||
|
70e9d7b699 | ||
|
79791e5848 | ||
|
0efa7cd7ea | ||
|
eef5cf39d4 | ||
|
6fb3fb5110 | ||
|
a2bbb17483 | ||
|
3135f1796e | ||
|
d565665ccb | ||
|
13a1ea6db8 | ||
|
6358be90c2 | ||
|
de89a6bc89 | ||
|
e03ad0d52f | ||
|
2a20de991b | ||
|
b8732a2f83 | ||
|
1bdad3ad14 | ||
|
fd47712060 | ||
|
6339524c86 | ||
|
5f9feda80c | ||
|
9958e1bf80 | ||
|
758471ec16 | ||
|
3fcba9339d | ||
|
f9c0cb08e0 | ||
|
a9313e76d4 | ||
|
59080a8319 | ||
|
524f04c78c | ||
|
8e04868320 | ||
|
fa3dc4e055 | ||
|
f9b2441c41 | ||
|
09f1d0fbb1 | ||
|
5ab91d7345 | ||
|
6c054dbf35 | ||
|
530cdb02f0 | ||
|
0a2d4c1649 | ||
|
bb17abfe26 | ||
|
e7e4892408 | ||
|
46648f3e80 | ||
|
6f2e2a0071 | ||
|
b7ba593856 | ||
|
c0bdd22154 | ||
|
32b451aa21 | ||
|
96a0c34d41 | ||
|
b95780022a | ||
|
c0823c464e | ||
|
cc43a31ca6 | ||
|
da8efa20cd | ||
|
03e4ac7ea6 | ||
|
1442842da9 | ||
|
0a602cb022 | ||
|
b479cb7912 | ||
|
41c7a6e731 | ||
|
82413513e8 | ||
|
18b104d0ac | ||
|
2e3c6b4f3a | ||
|
8e9b12fefd | ||
|
95a2308ff6 | ||
|
9985f3eee2 | ||
|
39df4ff9b1 | ||
|
90d18c553d | ||
|
385b03db6f | ||
|
a15995c126 | ||
|
f4cfd37745 | ||
|
a0d5d5817b | ||
|
d468cbf600 | ||
|
be14b3a2df | ||
|
1f1f0d8f15 | ||
|
8fcf93c489 | ||
|
bdd71743cd | ||
|
77b5282b46 | ||
|
e88d802918 | ||
|
61ab070692 | ||
|
d3ed454881 | ||
|
b5bbf8332f | ||
|
110d5ce76f | ||
|
bf1c46d62f | ||
|
5840ace38f | ||
|
eabcf82268 | ||
|
6a78d53d03 | ||
|
b831d19f8d | ||
|
721e52c5d9 | ||
|
6e73099d8c | ||
|
784af67367 | ||
|
4f053bb63a | ||
|
5211d1902c | ||
|
ffc8823e4f | ||
|
f912f60a59 | ||
|
476b8d81c1 | ||
|
2b2067e162 | ||
|
9048617e35 | ||
|
775d42115a | ||
|
f3705865a3 | ||
|
15cef6ba16 | ||
|
72b741d7c9 | ||
|
26c1abdd3c | ||
|
56f6df11a8 | ||
|
997d4f2eb7 | ||
|
d63efc8dbf | ||
|
7a3670523d | ||
|
1e39f1d84a | ||
|
0b66fd1948 | ||
|
164de644e9 | ||
|
f1da0d2943 | ||
|
f964fd2962 | ||
|
36a1a430b5 | ||
|
3721ecb40a | ||
|
5fcf01f4c8 | ||
|
a16a1dbb7d | ||
|
f357602090 | ||
|
a48630c837 | ||
|
171be1c422 | ||
|
324b6db5e6 | ||
|
a73322fb43 | ||
|
027971776b | ||
|
7c57310b67 | ||
|
5d7eeb0512 | ||
|
742b51c2cd | ||
|
cc7596f3b3 | ||
|
7da7484008 | ||
|
b42ba4af17 | ||
|
dd795a82f4 | ||
|
166362d3cd | ||
|
ea6edf572a | ||
|
19b64c2e65 | ||
|
612775466c | ||
|
740ea24e08 | ||
|
e1c14abf6c | ||
|
d1aae27359 | ||
|
80aeaf9200 | ||
|
282bb20cc8 | ||
|
b727be55a2 | ||
|
cf80a2d6ce | ||
|
72a5c1794a | ||
|
707c85b0d6 | ||
|
c56562b0b8 | ||
|
d0b2498b43 | ||
|
17be6f4549 | ||
|
b50fbff1e3 | ||
|
7375a348c6 | ||
|
ae5dd9ce65 | ||
|
f9e56ff62a | ||
|
1bcf7ee20f | ||
|
bee9c6a51d | ||
|
851c7c0eb1 | ||
|
7fff4a8fe8 | ||
|
44ac01ee0e | ||
|
60bd334b46 | ||
|
7398bee59e | ||
|
40420f27ed | ||
|
d32bfaa757 | ||
|
2653a174bb | ||
|
676fb4c06a | ||
|
7f815275d6 | ||
|
a056e2fe03 | ||
|
48d9fde133 | ||
|
a12786cbd5 | ||
|
164cc6ddb9 | ||
|
27f51d33e1 | ||
|
2108c88dfb | ||
|
a1726903b5 | ||
|
8075190e0c | ||
|
3b176fe220 | ||
|
986dc59627 | ||
|
0878897969 | ||
|
0ce7ecb45a | ||
|
7a63f42462 | ||
|
774341c346 | ||
|
c8983b35a0 | ||
|
edaccab04b | ||
|
f8b61b47b9 | ||
|
b8331d12e4 | ||
|
92404ab2bf | ||
|
3b17872f10 | ||
|
8cfa3dcdad | ||
|
9ec1380889 | ||
|
2af7195f06 | ||
|
8c6fd6c05a | ||
|
2df6446eb2 | ||
|
e1c0ff2685 | ||
|
6157bd77ca | ||
|
76de634f2b | ||
|
cfada388db | ||
|
2f971dc77f | ||
|
ae7b7e9aa9 | ||
|
bed6c3287e | ||
|
f83e5a8731 | ||
|
35369038db | ||
|
6a1f927a6c | ||
|
b2c0933ee6 | ||
|
3104d13eba | ||
|
8b1f3ef193 | ||
|
1ff885cff1 | ||
|
d950797bd9 | ||
|
d6e6b8b710 | ||
|
001c15bfad | ||
|
7fbc563524 | ||
|
0d949d53f3 | ||
|
d071cd112a | ||
|
4c1cd04a24 | ||
|
30162c8899 | ||
|
b21aac0ab2 | ||
|
73917a0327 | ||
|
ad86f71b34 | ||
|
d58877131d | ||
|
846b4d1652 | ||
|
583c21e7db | ||
|
7dc5a8090f | ||
|
6b29b7450e | ||
|
b9debaab26 | ||
|
856051bfb3 | ||
|
fa55a791e7 | ||
|
5c5d7d5340 | ||
|
a2a768b6e6 | ||
|
4bbbc72035 | ||
|
3815355489 | ||
|
9bb7af6f83 | ||
|
d16b1b72ba | ||
|
e37289231d | ||
|
1c2ec943e9 | ||
|
17dfc897b4 | ||
|
7586e62da1 | ||
|
a1c3746a5a | ||
|
d23dc4d247 | ||
|
293bc52972 | ||
|
11ab167376 | ||
|
f290de6dfc | ||
|
d260167155 | ||
|
3f114dc5e3 | ||
|
fedd10b5ed | ||
|
746cd4ab7d | ||
|
5848c0d920 | ||
|
db7c42cc91 | ||
|
f01cf7ef2f | ||
|
61f8195edd | ||
|
c38d20b163 | ||
|
fbf1535db1 | ||
|
90ce1932cc | ||
|
b60693c5d6 | ||
|
736a7b95eb | ||
|
b50f7ce04e | ||
|
b2514e35f4 | ||
|
bc314f7c52 | ||
|
72e3ddad1e | ||
|
6333a975f8 | ||
|
44ab7b6135 | ||
|
bfcccb2671 | ||
|
3183828c1c | ||
|
6be7c119db | ||
|
0f13ff188a | ||
|
099f009b39 | ||
|
136edf16c5 | ||
|
62d658524b | ||
|
5b9f9a500d | ||
|
05d33f7020 | ||
|
d9bf0e5899 | ||
|
63be2684d3 | ||
|
536ef3244d | ||
|
a3f5d20592 | ||
|
1e3a192920 | ||
|
b68a5c2abb | ||
|
643c3493c4 | ||
|
64ca2a4b49 | ||
|
1ff3d1adda | ||
|
9e2a6ed238 | ||
|
be51cdf9b1 | ||
|
13cd0cacdf | ||
|
67587e450b | ||
|
6ce190d33b | ||
|
f923e89c3d | ||
|
31c3cbe593 | ||
|
f03e4a9e37 | ||
|
7d8989a8cd | ||
|
b9e12a7fec | ||
|
d32cea1988 | ||
|
ce1a650ae1 | ||
|
01e823427f | ||
|
da92410ecb | ||
|
d65bd112a9 | ||
|
2ca3df60be | ||
|
23303905a8 | ||
|
0b8e69f0d0 | ||
|
a448f2167b | ||
|
3494b65be0 | ||
|
9ff841aa6f | ||
|
dc4136a6f5 | ||
|
7e4317cf54 | ||
|
522c7478c7 | ||
|
130d42c85e | ||
|
0433791bc6 | ||
|
79f15f3855 | ||
|
0754b9ec75 | ||
|
6568ca5790 | ||
|
30abfeefbf | ||
|
1483ce936b | ||
|
661086d3b8 | ||
|
ca1b977786 | ||
|
7525fc0884 | ||
|
06d5b343d6 | ||
|
07a42f6f43 | ||
|
8be92d413d | ||
|
71ac21b70e | ||
|
12ab753f15 | ||
|
684a8a269e | ||
|
cd60c2961f | ||
|
f046a024e4 | ||
|
90e585ba9a | ||
|
7e0e337134 | ||
|
324da27ea9 | ||
|
0a260f0c8c | ||
|
1a4cc3b750 | ||
|
b3da61822e | ||
|
69208fe0ac | ||
|
806838b8e4 | ||
|
2637af87ec | ||
|
ac3e787278 | ||
|
ffe59f5a5f | ||
|
7b9899c46b | ||
|
c29340ae27 | ||
|
ad12a088cf | ||
|
0810be9ce4 | ||
|
7f75246619 | ||
|
5ec1bf8a88 | ||
|
443d72ee24 | ||
|
861da5fee9 | ||
|
f3fc921212 | ||
|
54e6bbd4a6 | ||
|
0d6c4f65b9 | ||
|
cfd1c93a46 | ||
|
29b09227ac | ||
|
6cb5863b81 | ||
|
2f14f6b391 | ||
|
94369abd60 | ||
|
45edac4216 | ||
|
5bdfc9908a | ||
|
1890d71838 | ||
|
00d5fb5834 | ||
|
49b776c495 | ||
|
31e03c2d36 | ||
|
395ee3bf49 | ||
|
6f85bcbbf1 | ||
|
47a5c1ba08 | ||
|
d123ba095c | ||
|
bfad6c7e28 | ||
|
7067a35d3a | ||
|
f40ada9ac7 | ||
|
ca61d5d4e0 | ||
|
7771bc04ec | ||
|
20032f33a2 | ||
|
b694cca743 | ||
|
1e78f62823 | ||
|
c6bc1b0cfc | ||
|
48dea185d8 | ||
|
f34dd4a0cb | ||
|
0a3215be8e | ||
|
954f29f879 | ||
|
f2b5967f10 | ||
|
92779ad078 | ||
|
83c7dea1cc | ||
|
33c68a2103 | ||
|
92639fbbd6 | ||
|
9af1d2a201 | ||
|
f24d1be3e9 | ||
|
80802e5df4 | ||
|
6aa52adb3e | ||
|
0b1edadaa7 | ||
|
c1269a97d6 | ||
|
5e4cd98706 | ||
|
4ebf3f838f | ||
|
11c4c93398 | ||
|
cf32b5dd1b | ||
|
f7231b2c6a | ||
|
9a6ab4141f | ||
|
ad5cef3b7d | ||
|
cd44bf8f48 | ||
|
d065549e95 | ||
|
e43bdc837c | ||
|
45b971d286 | ||
|
4096c8cd20 | ||
|
66febb7744 | ||
|
d517b4c9e1 | ||
|
2412f1f826 | ||
|
c5aee31405 | ||
|
81e9e7364b | ||
|
11664e6d37 | ||
|
d40ee11ef5 | ||
|
b9cedc8b93 | ||
|
58adefa7d0 | ||
|
61f039366b | ||
|
6a0596f40b | ||
|
e32f153acf | ||
|
4823bfde8b | ||
|
7e0115f0ad | ||
|
49650d1ae9 | ||
|
aae99c2487 | ||
|
0d293e7c30 | ||
|
be4799edc9 | ||
|
7516606fd3 | ||
|
e4c43faa33 | ||
|
87fbcb19af | ||
|
6300cd5d72 | ||
|
0b047fd8e4 | ||
|
07c04d15d7 | ||
|
54c2c48704 | ||
|
95d068e818 | ||
|
c5ffd05eee | ||
|
b3c3676381 | ||
|
7356c5ad74 | ||
|
b8e2c5a3f8 | ||
|
f7e68d6e10 | ||
|
719b87a40c | ||
|
62f5766908 | ||
|
f46c1d2aa4 | ||
|
1f61f45f5f | ||
|
8e0b525ba2 | ||
|
19bd476395 | ||
|
7fada0964d | ||
|
b82551c97d | ||
|
5c8ed58c67 | ||
|
ed7f5370ca | ||
|
97e7a00bca | ||
|
193018aecf | ||
|
76289c68da | ||
|
9f6576c0fa | ||
|
107991b0a7 | ||
|
ffc25fb276 | ||
|
97fd115530 | ||
|
8fbbc7bd07 | ||
|
228144a701 | ||
|
184fac507b | ||
|
82c10c32fd | ||
|
782f43c73a | ||
|
6e5327a0e2 | ||
|
5206d77167 | ||
|
bdd2bc322c | ||
|
e5315dc016 | ||
|
8b4b884a03 | ||
|
f78caa24bb | ||
|
79b1e39798 | ||
|
797ed66eda | ||
|
16bdc36ccb | ||
|
b5f02d0739 | ||
|
1183fe80c6 | ||
|
9f1f0cc3bc | ||
|
6981ced972 | ||
|
019dfa8836 | ||
|
7f6ca35628 | ||
|
e1a7f576e4 | ||
|
6250daabd3 | ||
|
04277aeaa0 | ||
|
647de842ff | ||
|
ed10cbb4dc | ||
|
5893ba4e8e | ||
|
b2c07aa68f | ||
|
ac29fc4a62 | ||
|
f78bb954d0 | ||
|
29b0389a75 | ||
|
2aa318cfd7 | ||
|
82f7c7abaf | ||
|
2d90540531 | ||
|
de681b1ebf | ||
|
b5217271b0 | ||
|
9ac56ad547 | ||
|
c60b29d201 | ||
|
2a524efff5 | ||
|
c8c69829f0 | ||
|
22794d49d1 | ||
|
4e37d9bb61 | ||
|
af06f9f3ea | ||
|
aef86227da | ||
|
d10cc5040d | ||
|
d314c1efd9 | ||
|
468acbc369 | ||
|
013b1b53b4 | ||
|
5254c9d225 | ||
|
e07e0dba78 | ||
|
064d4d967c | ||
|
a85feb1a32 | ||
|
e4622b1f65 | ||
|
c5f48782e6 | ||
|
9de979a4ee | ||
|
20df1f50a6 | ||
|
40ea409aed | ||
|
a5b4198cb7 | ||
|
e71eb8074c | ||
|
0c4a45f329 | ||
|
115ca30f5a | ||
|
310c00a096 | ||
|
add1aa5949 | ||
|
36760a07cc | ||
|
11e0b004bd | ||
|
a2db7e1929 | ||
|
3cd5f50e64 | ||
|
603efeb80d | ||
|
69571bc8ef | ||
|
ca3b7d51df | ||
|
ac2beb08d6 | ||
|
0250d8d4d1 | ||
|
2d90a09f65 | ||
|
e9d867ba95 | ||
|
2c732a6647 | ||
|
0b1221ac14 | ||
|
ca4763483d | ||
|
9d6ecfae46 | ||
|
a3863fec2e | ||
|
5cd420bd5d | ||
|
e62bc4e98d | ||
|
7a38187076 | ||
|
40490db27f | ||
|
bc74aff46d | ||
|
337cb088e9 | ||
|
9e5bd4cd67 | ||
|
427ae50704 | ||
|
449ba5005c | ||
|
b86d1f1406 |
16
.gitattributes
vendored
16
.gitattributes
vendored
@@ -1,5 +1,13 @@
|
||||
tests/ export-ignore
|
||||
phpunit.xml export-ignore
|
||||
build.xml export-ignore
|
||||
test export-ignore
|
||||
* text=auto
|
||||
|
||||
/examples export-ignore
|
||||
/tests export-ignore
|
||||
/.gitattributes export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
.travis.yml export-ignore
|
||||
.scrutinizer.yml export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/CHANGELOG.md export-ignore
|
||||
/CONTRIBUTING.md export-ignore
|
||||
/README.md export-ignore
|
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
/vendor
|
||||
/composer.lock
|
||||
/tests/coverage
|
||||
/docs
|
||||
/testing
|
||||
build/coverage
|
||||
phpunit.xml
|
||||
.idea
|
||||
/examples/vendor
|
||||
examples/public.key
|
||||
examples/private.key
|
||||
build
|
||||
|
37
.scrutinizer.yml
Normal file
37
.scrutinizer.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
filter:
|
||||
excluded_paths:
|
||||
- tests/*
|
||||
- vendor/*
|
||||
- examples/*
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
remove_extra_empty_lines: true
|
||||
remove_php_closing_tag: true
|
||||
remove_trailing_whitespace: true
|
||||
fix_use_statements:
|
||||
remove_unused: true
|
||||
preserve_multiple: false
|
||||
preserve_blanklines: true
|
||||
order_alphabetically: true
|
||||
fix_php_opening_tag: true
|
||||
fix_linefeed: true
|
||||
fix_line_ending: true
|
||||
fix_identation_4spaces: true
|
||||
fix_doc_comments: true
|
||||
tools:
|
||||
external_code_coverage:
|
||||
timeout: 600
|
||||
runs: 3
|
||||
php_code_coverage: false
|
||||
php_code_sniffer:
|
||||
config:
|
||||
standard: PSR2
|
||||
filter:
|
||||
paths: ['src']
|
||||
php_loc:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
||||
php_cpd:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests, examples]
|
53
.styleci.yml
Normal file
53
.styleci.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
preset: psr2
|
||||
|
||||
enabled:
|
||||
- binary_operator_spaces
|
||||
- blank_line_before_return
|
||||
- concat_with_spaces
|
||||
- function_typehint_space
|
||||
- hash_to_slash_comment
|
||||
- include
|
||||
- lowercase_cast
|
||||
- method_separation
|
||||
- native_function_casing
|
||||
- no_blank_lines_after_class_opening
|
||||
- no_blank_lines_between_uses
|
||||
- no_duplicate_semicolons
|
||||
- no_leading_import_slash
|
||||
- no_leading_namespace_whitespace
|
||||
- no_multiline_whitespace_before_semicolons
|
||||
- no_php4_constructor
|
||||
- no_short_bool_cast
|
||||
- no_singleline_whitespace_before_semicolons
|
||||
- no_trailing_comma_in_singleline_array
|
||||
- no_unreachable_default_argument_value
|
||||
- no_unused_imports
|
||||
- no_whitespace_before_comma_in_array
|
||||
- ordered_imports
|
||||
- phpdoc_align
|
||||
- phpdoc_indent
|
||||
- phpdoc_inline_tag
|
||||
- phpdoc_no_access
|
||||
- phpdoc_no_simplified_null_return
|
||||
- phpdoc_order
|
||||
- phpdoc_property
|
||||
- phpdoc_scalar
|
||||
- phpdoc_separation
|
||||
- phpdoc_to_comment
|
||||
- phpdoc_trim
|
||||
- phpdoc_type_to_var
|
||||
- phpdoc_types
|
||||
- phpdoc_var_without_name
|
||||
- print_to_echo
|
||||
- short_array_syntax
|
||||
- short_scalar_cast
|
||||
- simplified_null_return
|
||||
- single_quote
|
||||
- spaces_cast
|
||||
- standardize_not_equal
|
||||
- ternary_operator_spaces
|
||||
- trailing_comma_in_multiline_array
|
||||
- trim_array_spaces
|
||||
- unary_operator_spaces
|
||||
- whitespace_after_comma_in_array
|
||||
- whitespacy_lines
|
30
.travis.yml
30
.travis.yml
@@ -1,18 +1,24 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
|
||||
before_script: composer install --prefer-source
|
||||
script: phpunit --configuration phpunit.xml.dist
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- vendor
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- V5-WIP
|
106
CHANGELOG.md
106
CHANGELOG.md
@@ -1,6 +1,108 @@
|
||||
# Changelog
|
||||
|
||||
## 3.2 (released 2014-04-16)
|
||||
## 5.0.0-RC1 (release 2016-03-24)
|
||||
|
||||
Version 5 is a complete code rewrite.
|
||||
|
||||
* JWT support
|
||||
* PSR-7 support
|
||||
* Improved exception errors
|
||||
* Replace all occurrences of the term "Storage" with "Repository"
|
||||
* Simplify repositories
|
||||
* Entities conform to interfaces and use traits
|
||||
* Auth code grant updated
|
||||
* Allow support for public clients
|
||||
* Add support for #439
|
||||
* Client credentials grant updated
|
||||
* Password grant updated
|
||||
* Allow support for public clients
|
||||
* Refresh token grant updated
|
||||
* Implement Implicit grant
|
||||
* Bearer token output type
|
||||
* Remove MAC token output type
|
||||
* Authorization server rewrite
|
||||
* Resource server class moved to PSR-7 middleware
|
||||
* Tests
|
||||
* Much much better documentation
|
||||
|
||||
## 4.1.5 (released 2016-01-04)
|
||||
|
||||
* Enable Symfony 3.0 support (#412)
|
||||
|
||||
## 4.1.4 (released 2015-11-13)
|
||||
|
||||
* Fix for determining access token in header (Issue #328)
|
||||
* Refresh tokens are now returned for MAC responses (Issue #356)
|
||||
* Added integration list to readme (Issue #341)
|
||||
* Expose parameter passed to exceptions (Issue #345)
|
||||
* Removed duplicate routing setup code (Issue #346)
|
||||
* Docs fix (Issues #347, #360, #380)
|
||||
* Examples fix (Issues #348, #358)
|
||||
* Fix typo in docblock (Issue #352)
|
||||
* Improved timeouts for MAC tokens (Issue #364)
|
||||
* `hash_hmac()` should output raw binary data, not hexits (Issue #370)
|
||||
* Improved regex for matching all Base64 characters (Issue #371)
|
||||
* Fix incorrect signature parameter (Issue #372)
|
||||
* AuthCodeGrant and RefreshTokenGrant don't require client_secret (Issue #377)
|
||||
* Added priority argument to event listener (Issue #388)
|
||||
|
||||
## 4.1.3 (released 2015-03-22)
|
||||
|
||||
* Docblock, namespace and inconsistency fixes (Issue #303)
|
||||
* Docblock type fix (Issue #310)
|
||||
* Example bug fix (Issue #300)
|
||||
* Updated league/event to ~2.1 (Issue #311)
|
||||
* Fixed missing session scope (Issue #319)
|
||||
* Updated interface docs (Issue #323)
|
||||
* `.travis.yml` updates
|
||||
|
||||
## 4.1.2 (released 2015-01-01)
|
||||
|
||||
* Remove side-effects in hash_equals() implementation (Issue #290)
|
||||
|
||||
## 4.1.1 (released 2014-12-31)
|
||||
|
||||
* Changed `symfony/http-foundation` dependency version to `~2.4` so package can be installed in Laravel `4.1.*`
|
||||
|
||||
## 4.1.0 (released 2014-12-27)
|
||||
|
||||
* Added MAC token support (Issue #158)
|
||||
* Fixed example init code (Issue #280)
|
||||
* Toggle refresh token rotation (Issue #286)
|
||||
* Docblock fixes
|
||||
|
||||
## 4.0.5 (released 2014-12-15)
|
||||
|
||||
* Prevent duplicate session in auth code grant (Issue #282)
|
||||
|
||||
## 4.0.4 (released 2014-12-03)
|
||||
|
||||
* Ensure refresh token hasn't expired (Issue #270)
|
||||
|
||||
## 4.0.3 (released 2014-12-02)
|
||||
|
||||
* Fix bad type hintings (Issue #267)
|
||||
* Do not forget to set the expire time (Issue #268)
|
||||
|
||||
## 4.0.2 (released 2014-11-21)
|
||||
|
||||
* Improved interfaces (Issue #255)
|
||||
* Learnt how to spell delimiter and so `getScopeDelimiter()` and `setScopeDelimiter()` methods have been renamed
|
||||
* Docblock improvements (Issue #254)
|
||||
|
||||
## 4.0.1 (released 2014-11-09)
|
||||
|
||||
* Alias the master branch in composer.json (Issue #243)
|
||||
* Numerous PHP CodeSniffer fixes (Issue #244)
|
||||
* .travis.yml update (Issue #245)
|
||||
* The getAccessToken method should return an AccessTokenEntity object instead of a string in ResourceServer.php (#246)
|
||||
|
||||
## 4.0.0 (released 2014-11-08)
|
||||
|
||||
* Complete rewrite
|
||||
* Check out the documentation - [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com)
|
||||
|
||||
## 3.2.0 (released 2014-04-16)
|
||||
|
||||
* Added the ability to change the algorithm that is used to generate the token strings (Issue #151)
|
||||
|
||||
@@ -82,7 +184,7 @@
|
||||
* Included a PDO driver which implements the storage interfaces so the library is more "get up and go"
|
||||
* Further normalised the database structure so all sessions no longer contain infomation related to authorization grant (which may or may not be enabled)
|
||||
* A session can have multiple associated access tokens
|
||||
* Induvidual grants can have custom expire times for access tokens
|
||||
* Individual grants can have custom expire times for access tokens
|
||||
* Authorization codes now have a TTL of 10 minutes by default (can be manually set)
|
||||
* Refresh tokens now have a TTL of one week by default (can be manually set)
|
||||
* The client credentials grant will no longer gives out refresh tokens as per the specification
|
||||
|
22
CONDUCT.md
Normal file
22
CONDUCT.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community in a direct capacity. Personal views, beliefs and values of individuals do not necessarily reflect those of the organisation or affiliated individuals and organisations.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
|
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2013 PHP League of Extraordinary Packages
|
||||
Copyright (C) Alex Bilbie
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
100
README.md
100
README.md
@@ -1,68 +1,44 @@
|
||||
# PHP OAuth 2.0 Server
|
||||
# PHP OAuth 2.0 Server by [@alexbilbie](https://twitter.com/alexbilbie)
|
||||
|
||||
[](https://packagist.org/packages/league/oauth2-server) [](https://coveralls.io/r/thephpleague/oauth2-server?branch=master) [](https://packagist.org/packages/league/oauth2-server) [](https://bitdeli.com/free "Bitdeli Badge")
|
||||
[](https://github.com/thephpleague/oauth2-server/releases)
|
||||
[](LICENSE.md)
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server/code-structure)
|
||||
[](https://scrutinizer-ci.com/g/thephpleague/oauth2-server)
|
||||
[](https://packagist.org/packages/league/oauth2-server)
|
||||
|
||||
`league/oauth2-server` is a a standards compliant implementation of an [OAuth 2.0](https://tools.ietf.org/html/rfc6749) authorization server written in PHP which makes working with OAuth 2.0 trivial. You can easily configure an OAuth 2.0 server to protect your API with access tokens, or allow clients to request new access tokens and refresh them.
|
||||
|
||||
A standards compliant [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authorization server and resource server written in PHP.
|
||||
It supports out of the box the following grants:
|
||||
|
||||
## Package Installation
|
||||
* Authorization code grant
|
||||
* Implicit grant
|
||||
* Client credentials grant
|
||||
* Resource owner password credentials grant
|
||||
* Refresh grant
|
||||
|
||||
The framework is provided as a Composer package which can be installed by adding the package to your `composer.json` file:
|
||||
You can also easily define your own grants.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"require": {
|
||||
"league/oauth2-server": "3.*"
|
||||
}
|
||||
}
|
||||
```
|
||||
In addition it supports the following token response types:
|
||||
|
||||
### Framework Integrations
|
||||
* Bearer (JWT) tokens
|
||||
* MAC tokens
|
||||
|
||||
* [Laravel Service Provider](https://packagist.org/packages/lucadegasperi/oauth2-server-laravel) by @lucadegasperi
|
||||
* [Laravel Eloquent implementation](https://github.com/ScubaClick/scubaclick-oauth2) by @ScubaClick (under development)
|
||||
You can also create you own tokens.
|
||||
|
||||
---
|
||||
## Requirements
|
||||
|
||||
The library features 100% unit test code coverage. To run the tests yourself run `phpunit` from the project root.
|
||||
The following versions of PHP are supported:
|
||||
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server) [master]
|
||||
* PHP 5.5 (>=5.5.9)
|
||||
* PHP 5.6
|
||||
* PHP 7.0
|
||||
* HHVM
|
||||
|
||||
[](https://travis-ci.org/thephpleague/oauth2-server) [develop]
|
||||
## Documentation
|
||||
|
||||
|
||||
## Current Features
|
||||
|
||||
### Authorization Server
|
||||
|
||||
The authorization server is a flexible class and the following core specification grants are implemented:
|
||||
|
||||
* authorization code ([section 4.1](http://tools.ietf.org/html/rfc6749#section-4.1))
|
||||
* refresh token ([section 6](http://tools.ietf.org/html/rfc6749#section-6))
|
||||
* client credentials ([section 2.3.1](http://tools.ietf.org/html/rfc6749#section-2.3.1))
|
||||
* password (user credentials) ([section 4.3](http://tools.ietf.org/html/rfc6749#section-4.3))
|
||||
|
||||
An [overview of the different OAuth 2.0 grants](https://github.com/thephpleague/oauth2-server/wiki/Which-OAuth-2.0-grant-should-I-use%3F) can be found in the [wiki].
|
||||
|
||||
### Resource Server
|
||||
|
||||
The resource server allows you to secure your API endpoints by checking for a valid OAuth access token in the request and ensuring the token has the correct scope(s) (i.e. permissions) to access resources.
|
||||
|
||||
### Custom grants
|
||||
|
||||
Custom grants can be created easily by implementing an interface. Check out the [custom grant guide](https://github.com/thephpleague/oauth2-server/wiki/Creating-custom-grants).
|
||||
|
||||
## Tutorials and Documentation
|
||||
|
||||
* **[Wiki]** - The wiki has lots of guides on how to use this library.
|
||||
|
||||
* **[Developing an OAuth-2.0 Authorization Server]** - A simple tutorial on how to use the authorization server.
|
||||
|
||||
* **[Securing your API with OAuth 2.0]** - A simple tutorial on how to use the resource server to secure an API server.
|
||||
|
||||
[Wiki]: https://github.com/thephpleague/oauth2-server/wiki
|
||||
[Securing your API with OAuth 2.0]: https://github.com/thephpleague/oauth2-server/wiki/Securing-your-API-with-OAuth-2.0
|
||||
[Developing an OAuth-2.0 Authorization Server]: https://github.com/thephpleague/oauth2-server/wiki/Developing-an-OAuth-2.0-authorization-server
|
||||
The library documentation can be found at [http://oauth2.thephpleague.com](http://oauth2.thephpleague.com).
|
||||
You can contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/).
|
||||
|
||||
## Changelog
|
||||
|
||||
@@ -70,11 +46,17 @@ Custom grants can be created easily by implementing an interface. Check out the
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) for details.
|
||||
Please see [CONTRIBUTING.md](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) and [CONDUCT.md](https://github.com/thephpleague/oauth2-server/blob/master/CONDUCT.md) for details.
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues)
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues).
|
||||
|
||||
If you have any questions about OAuth _please_ open a ticket here; please **don't** email the address below.
|
||||
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email hello@alexbilbie.com instead of using the issue tracker.
|
||||
|
||||
## License
|
||||
|
||||
@@ -84,14 +66,6 @@ This package is released under the MIT License. See the bundled [LICENSE](https:
|
||||
|
||||
This code is principally developed and maintained by [Alex Bilbie](https://twitter.com/alexbilbie).
|
||||
|
||||
Special thanks to:
|
||||
|
||||
* [Dan Horrigan](https://github.com/dandoescode)
|
||||
* [Nick Jackson](https://github.com/jacksonj04)
|
||||
* [Michael Gooden](https://github.com/MichaelGooden)
|
||||
* [Phil Sturgeon](https://github.com/philsturgeon)
|
||||
* [and all the other contributors](https://github.com/thephpleague/oauth2-server/contributors)
|
||||
Special thanks to [all of these awesome contributors](https://github.com/thephpleague/oauth2-server/contributors)
|
||||
|
||||
The initial code was developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which was funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme.
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
@@ -1,13 +1,19 @@
|
||||
{
|
||||
"name": "league/oauth2-server",
|
||||
"description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
|
||||
"homepage": "http://oauth2.thephpleague.com/",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
"php": ">=5.5.9",
|
||||
"league/event": "^2.1",
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"paragonie/random_compat": "^1.1",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": ">=0.7.2",
|
||||
"league/phpunit-coverage-listener": "~1.0"
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"league/plates": "^3.1",
|
||||
"zendframework/zend-diactoros": "^1.0"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
@@ -18,8 +24,12 @@
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"oauth 2",
|
||||
"oauth 2.0",
|
||||
"server",
|
||||
"auth",
|
||||
"authorization",
|
||||
"authorisation",
|
||||
"authentication",
|
||||
"resource",
|
||||
"api",
|
||||
@@ -36,14 +46,28 @@
|
||||
}
|
||||
],
|
||||
"replace": {
|
||||
"lncd/oauth2": "*"
|
||||
"lncd/oauth2": "*",
|
||||
"league/oauth2server": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"League\\OAuth2\\Server": "src/"
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"suggest": {
|
||||
|
||||
"league/plates": "Used for parsing authorization code templates",
|
||||
"twig/twig": "Used for parsing authorization code templates",
|
||||
"smarty/smarty": "Used for parsing authorization code templates",
|
||||
"mustache/mustache": "Used for parsing authorization code templates"
|
||||
}
|
||||
}
|
||||
|
53
examples/README.md
Normal file
53
examples/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Example implementations
|
||||
|
||||
## Installation
|
||||
|
||||
0. Run `composer install --no-dev` in this directory to install dependencies
|
||||
0. Create a private key `openssl genrsa -out private.key 1024`
|
||||
0. Create a public key `openssl rsa -in private.key -pubout > public.key`
|
||||
0. `cd` into the public directory
|
||||
0. Start a PHP server `php -S localhost:4444`
|
||||
|
||||
## Testing the client credentials grant example
|
||||
|
||||
Send the following cURL request:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/client_credentials.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=client_credentials" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "scope=basic email"
|
||||
```
|
||||
|
||||
## Testing the password grant example
|
||||
|
||||
Send the following cURL request:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/password.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=password" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "username=alex" \
|
||||
--data-urlencode "password=whisky" \
|
||||
--data-urlencode "scope=basic email"
|
||||
```
|
||||
|
||||
## Testing the refresh token grant example
|
||||
|
||||
Send the following cURL request. Replace `{{REFRESH_TOKEN}}` with a refresh token from another grant above:
|
||||
|
||||
```
|
||||
curl -X "POST" "http://localhost:4444/refresh_token.php/access_token" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-H "Accept: 1.0" \
|
||||
--data-urlencode "grant_type=refresh_token" \
|
||||
--data-urlencode "client_id=myawesomeapp" \
|
||||
--data-urlencode "client_secret=abc123" \
|
||||
--data-urlencode "refresh_token={{REFRESH_TOKEN}}"
|
||||
```
|
18
examples/composer.json
Normal file
18
examples/composer.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": ".."
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"slim/slim": "3.0.*",
|
||||
"league/oauth2-server": "dev-V5-WIP",
|
||||
"league/plates": "^3.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"OAuth2ServerExamples\\": "src/"
|
||||
}
|
||||
}
|
||||
}
|
537
examples/composer.lock
generated
Normal file
537
examples/composer.lock
generated
Normal file
@@ -0,0 +1,537 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "143453cc35e7f499b130b6460222dc5a",
|
||||
"content-hash": "1ea46581fb6db25f323a37a45ef74f95",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
"version": "1.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/container-interop/container-interop.git",
|
||||
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
|
||||
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Interop\\Container\\": "src/Interop/Container/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||
"time": "2014-12-30 15:22:37"
|
||||
},
|
||||
{
|
||||
"name": "lcobucci/jwt",
|
||||
"version": "3.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lcobucci/jwt.git",
|
||||
"reference": "31499db4e692b343cec7ff345932899f98fde1cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/lcobucci/jwt/zipball/31499db4e692b343cec7ff345932899f98fde1cf",
|
||||
"reference": "31499db4e692b343cec7ff345932899f98fde1cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"mdanter/ecc": "~0.3",
|
||||
"mikey179/vfsstream": "~1.5",
|
||||
"phpmd/phpmd": "~2.2",
|
||||
"phpunit/php-invoker": "~1.1",
|
||||
"phpunit/phpunit": "~4.5",
|
||||
"squizlabs/php_codesniffer": "~2.3"
|
||||
},
|
||||
"suggest": {
|
||||
"mdanter/ecc": "Required to use Elliptic Curves based algorithms."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Lcobucci\\JWT\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Luís Otávio Cobucci Oblonczyk",
|
||||
"email": "lcobucci@gmail.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A simple library to work with JSON Web Token and JSON Web Signature",
|
||||
"keywords": [
|
||||
"JWS",
|
||||
"jwt"
|
||||
],
|
||||
"time": "2015-11-15 01:42:47"
|
||||
},
|
||||
{
|
||||
"name": "league/event",
|
||||
"version": "2.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/event.git",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"henrikbjorn/phpspec-code-coverage": "~1.0.1",
|
||||
"phpspec/phpspec": "~2.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Event\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank de Jonge",
|
||||
"email": "info@frenky.net"
|
||||
}
|
||||
],
|
||||
"description": "Event package",
|
||||
"keywords": [
|
||||
"emitter",
|
||||
"event",
|
||||
"listener"
|
||||
],
|
||||
"time": "2015-05-21 12:24:47"
|
||||
},
|
||||
{
|
||||
"name": "league/oauth2-server",
|
||||
"version": "dev-V5-WIP",
|
||||
"dist": {
|
||||
"type": "path",
|
||||
"url": "../",
|
||||
"reference": "0fbe109e2004c71feac2bd14fd85aff97704b2e5",
|
||||
"shasum": null
|
||||
},
|
||||
"require": {
|
||||
"lcobucci/jwt": "^3.1",
|
||||
"league/event": "^2.1",
|
||||
"paragonie/random_compat": "^1.1",
|
||||
"php": ">=5.5.9",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"replace": {
|
||||
"league/oauth2server": "*",
|
||||
"lncd/oauth2": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"league/plates": "^3.1",
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"zendframework/zend-diactoros": "^1.0"
|
||||
},
|
||||
"suggest": {
|
||||
"league/plates": "Used for parsing authorization code templates",
|
||||
"mustache/mustache": "Used for parsing authorization code templates",
|
||||
"smarty/smarty": "Used for parsing authorization code templates",
|
||||
"twig/twig": "Used for parsing authorization code templates"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-V5-WIP": "5.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "hello@alexbilbie.com",
|
||||
"homepage": "http://www.alexbilbie.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "A lightweight and powerful OAuth 2.0 authorization and resource server library with support for all the core specification grants. This library will allow you to secure your API with OAuth and allow your applications users to approve apps that want to access their data from your API.",
|
||||
"homepage": "http://oauth2.thephpleague.com/",
|
||||
"keywords": [
|
||||
"api",
|
||||
"auth",
|
||||
"auth",
|
||||
"authentication",
|
||||
"authorisation",
|
||||
"authorization",
|
||||
"oauth",
|
||||
"oauth 2",
|
||||
"oauth 2.0",
|
||||
"oauth2",
|
||||
"protect",
|
||||
"resource",
|
||||
"secure",
|
||||
"server"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "league/plates",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/plates.git",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/plates/zipball/2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"reference": "2d8569e9f140a70d6a05db38006926f7547cb802",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"mikey179/vfsstream": "~1.4.0",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~1.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Plates\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Reinink",
|
||||
"email": "jonathan@reinink.ca",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Plates, the native PHP template system that's fast, easy to use and easy to extend.",
|
||||
"homepage": "http://platesphp.com",
|
||||
"keywords": [
|
||||
"league",
|
||||
"package",
|
||||
"templates",
|
||||
"templating",
|
||||
"views"
|
||||
],
|
||||
"time": "2015-07-09 02:14:40"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v0.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/FastRoute.git",
|
||||
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FastRoute\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nikita Popov",
|
||||
"email": "nikic@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Fast request router for PHP",
|
||||
"keywords": [
|
||||
"router",
|
||||
"routing"
|
||||
],
|
||||
"time": "2015-06-18 19:15:47"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*|5.*"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https://paragonie.com"
|
||||
}
|
||||
],
|
||||
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
|
||||
"keywords": [
|
||||
"csprng",
|
||||
"pseudorandom",
|
||||
"random"
|
||||
],
|
||||
"time": "2016-03-18 20:34:03"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/silexphp/Pimple.git",
|
||||
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
|
||||
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Pimple": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Pimple, a simple Dependency Injection Container",
|
||||
"homepage": "http://pimple.sensiolabs.org",
|
||||
"keywords": [
|
||||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2015-09-11 15:10:35"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
||||
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2015-05-04 20:22:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/Slim.git",
|
||||
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/Slim/zipball/3b06f0f2d84dabbe81b6cea46ace46a3e883253e",
|
||||
"reference": "3b06f0f2d84dabbe81b6cea46ace46a3e883253e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"container-interop/container-interop": "^1.1",
|
||||
"nikic/fast-route": "^0.6",
|
||||
"php": ">=5.5.0",
|
||||
"pimple/pimple": "^3.0",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Slim\\": "Slim"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rob Allen",
|
||||
"email": "rob@akrabat.com",
|
||||
"homepage": "http://akrabat.com"
|
||||
},
|
||||
{
|
||||
"name": "Josh Lockhart",
|
||||
"email": "hello@joshlockhart.com",
|
||||
"homepage": "https://joshlockhart.com"
|
||||
},
|
||||
{
|
||||
"name": "Gabriel Manricks",
|
||||
"email": "gmanricks@me.com",
|
||||
"homepage": "http://gabrielmanricks.com"
|
||||
},
|
||||
{
|
||||
"name": "Andrew Smith",
|
||||
"email": "a.smith@silentworks.co.uk",
|
||||
"homepage": "http://silentworks.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
|
||||
"homepage": "http://slimframework.com",
|
||||
"keywords": [
|
||||
"api",
|
||||
"framework",
|
||||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2015-12-07 14:11:09"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"league/oauth2-server": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
74
examples/public/api.php
Normal file
74
examples/public/api.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
new ClientRepository(),
|
||||
new AccessTokenRepository(),
|
||||
new ScopeRepository(),
|
||||
'file://' . __DIR__ . '/../private.key',
|
||||
'file://' . __DIR__ . '/../public.key'
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->add(
|
||||
new \League\OAuth2\Server\Middleware\ResourceServerMiddleware(
|
||||
$app->getContainer()->get(Server::class)
|
||||
)
|
||||
);
|
||||
|
||||
$app->get('/users', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
|
||||
$users = [
|
||||
[
|
||||
'id' => 123,
|
||||
'name' => 'Alex',
|
||||
'email' => 'alex@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 124,
|
||||
'name' => 'Frank',
|
||||
'email' => 'frank@thephpleague.com',
|
||||
],
|
||||
[
|
||||
'id' => 125,
|
||||
'name' => 'Phil',
|
||||
'email' => 'phil@thephpleague.com',
|
||||
],
|
||||
];
|
||||
|
||||
if (in_array('basic', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['name']);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('email', $request->getAttribute('oauth_scopes')) === false) {
|
||||
for ($i = 0; $i < count($users); $i++) {
|
||||
unset($users[$i]['email']);
|
||||
}
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode($users));
|
||||
|
||||
return $response->withStatus(200);
|
||||
});
|
||||
|
||||
$app->run();
|
91
examples/public/auth_code.php
Normal file
91
examples/public/auth_code.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
$userRepository = new UserRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
$userRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->any('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
64
examples/public/client_credentials.php
Normal file
64
examples/public/client_credentials.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ClientCredentialsGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the client credentials grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new ClientCredentialsGrant(),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
66
examples/public/implicit.php
Normal file
66
examples/public/implicit.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\ImplicitGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$userRepository = new UserRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the implicit grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new ImplicitGrant($userRepository),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->any('/authorize', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
95
examples/public/middleware_use.php
Normal file
95
examples/public/middleware_use.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Grant\AuthCodeGrant;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\Middleware\AuthenticationServerMiddleware;
|
||||
use League\OAuth2\Server\Middleware\ResourceServerMiddleware;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\AuthCodeRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$authCodeRepository = new AuthCodeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
$userRepository = new UserRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the authentication code grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new AuthCodeGrant(
|
||||
$authCodeRepository,
|
||||
$refreshTokenRepository,
|
||||
$userRepository,
|
||||
new \DateInterval('PT10M')
|
||||
),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
// Enable the refresh token grant on the server with a token TTL of 1 month
|
||||
$server->enableGrantType(
|
||||
new RefreshTokenGrant($refreshTokenRepository),
|
||||
new \DateInterval('PT1M')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
// Access token issuer
|
||||
$app->post('/access_token', function () {
|
||||
})->add(new AuthenticationServerMiddleware($app->getContainer()->get(Server::class)));
|
||||
|
||||
// Secured API
|
||||
$app->group('/api', function () {
|
||||
$this->get('/user', function (ServerRequestInterface $request, ResponseInterface $response) {
|
||||
$params = [];
|
||||
|
||||
if (in_array('basic', $request->getAttribute('oauth_scopes', []))) {
|
||||
$params = [
|
||||
'id' => 1,
|
||||
'name' => 'Alex',
|
||||
'city' => 'London',
|
||||
];
|
||||
}
|
||||
|
||||
if (in_array('email', $request->getAttribute('oauth_scopes', []))) {
|
||||
$params['email'] = 'alex@example.com';
|
||||
}
|
||||
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write(json_encode($params));
|
||||
|
||||
return $response->withBody($body);
|
||||
});
|
||||
})->add(new ResourceServerMiddleware($app->getContainer()->get(Server::class)));
|
||||
|
||||
$app->run();
|
68
examples/public/password.php
Normal file
68
examples/public/password.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\PasswordGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use OAuth2ServerExamples\Repositories\UserRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$userRepository = new UserRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the password grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new PasswordGrant($userRepository, $refreshTokenRepository),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
66
examples/public/refresh_token.php
Normal file
66
examples/public/refresh_token.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\RefreshTokenGrant;
|
||||
use League\OAuth2\Server\Server;
|
||||
use OAuth2ServerExamples\Repositories\AccessTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ClientRepository;
|
||||
use OAuth2ServerExamples\Repositories\RefreshTokenRepository;
|
||||
use OAuth2ServerExamples\Repositories\ScopeRepository;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Slim\App;
|
||||
use Zend\Diactoros\Stream;
|
||||
|
||||
include __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$app = new App([
|
||||
'settings' => [
|
||||
'displayErrorDetails' => true,
|
||||
],
|
||||
Server::class => function () {
|
||||
// Init our repositories
|
||||
$clientRepository = new ClientRepository();
|
||||
$accessTokenRepository = new AccessTokenRepository();
|
||||
$scopeRepository = new ScopeRepository();
|
||||
$refreshTokenRepository = new RefreshTokenRepository();
|
||||
|
||||
$privateKeyPath = 'file://' . __DIR__ . '/../private.key';
|
||||
$publicKeyPath = 'file://' . __DIR__ . '/../public.key';
|
||||
|
||||
// Setup the authorization server
|
||||
$server = new Server(
|
||||
$clientRepository,
|
||||
$accessTokenRepository,
|
||||
$scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath
|
||||
);
|
||||
|
||||
// Enable the refresh token grant on the server with a token TTL of 1 hour
|
||||
$server->enableGrantType(
|
||||
new RefreshTokenGrant($refreshTokenRepository),
|
||||
new \DateInterval('PT1H')
|
||||
);
|
||||
|
||||
return $server;
|
||||
},
|
||||
]);
|
||||
|
||||
$app->post('/access_token', function (ServerRequestInterface $request, ResponseInterface $response) use ($app) {
|
||||
/* @var \League\OAuth2\Server\Server $server */
|
||||
$server = $app->getContainer()->get(Server::class);
|
||||
|
||||
try {
|
||||
return $server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
} catch (\Exception $exception) {
|
||||
$body = new Stream('php://temp', 'r+');
|
||||
$body->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500)->withBody($body);
|
||||
}
|
||||
});
|
||||
|
||||
$app->run();
|
85
examples/src/Entities/ClientEntity.php
Normal file
85
examples/src/Entities/ClientEntity.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class ClientEntity implements ClientEntityInterface
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
private $name;
|
||||
|
||||
private $secret;
|
||||
|
||||
private $redirectUri;
|
||||
|
||||
/**
|
||||
* Get the client's name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client's name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secret
|
||||
*/
|
||||
public function setSecret($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hashed client secret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client's redirect uri.
|
||||
*
|
||||
* @param string $redirectUri
|
||||
*/
|
||||
public function setRedirectUri($redirectUri)
|
||||
{
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered redirect URI.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the client is capable of keeping it's secrets secret.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canKeepASecret()
|
||||
{
|
||||
return $this->secret !== null;
|
||||
}
|
||||
}
|
16
examples/src/Entities/ScopeEntity.php
Normal file
16
examples/src/Entities/ScopeEntity.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
|
||||
class ScopeEntity implements ScopeEntityInterface
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getIdentifier();
|
||||
}
|
||||
}
|
18
examples/src/Entities/UserEntity.php
Normal file
18
examples/src/Entities/UserEntity.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Entities;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
|
||||
|
||||
class UserEntity implements UserEntityInterface
|
||||
{
|
||||
/**
|
||||
* Return the user's identifier.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
41
examples/src/Repositories/AccessTokenRepository.php
Normal file
41
examples/src/Repositories/AccessTokenRepository.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
|
||||
class AccessTokenRepository implements AccessTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Persists a new access token to permanent storage.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity)
|
||||
{
|
||||
// TODO: Implement persistNewAccessToken() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeAccessToken($tokenId)
|
||||
{
|
||||
// TODO: Implement revokeAccessToken() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the access token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId)
|
||||
{
|
||||
// TODO: Implement isAccessTokenRevoked() method.
|
||||
}
|
||||
}
|
41
examples/src/Repositories/AuthCodeRepository.php
Normal file
41
examples/src/Repositories/AuthCodeRepository.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
|
||||
class AuthCodeRepository implements AuthCodeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Persists a new auth code to permanent storage.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity)
|
||||
{
|
||||
// TODO: Implement persistNewAuthCode() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an auth code.
|
||||
*
|
||||
* @param string $codeId
|
||||
*/
|
||||
public function revokeAuthCode($codeId)
|
||||
{
|
||||
// TODO: Implement revokeAuthCode() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the auth code has been revoked.
|
||||
*
|
||||
* @param string $codeId
|
||||
*
|
||||
* @return bool Return true if this code has been revoked
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId)
|
||||
{
|
||||
// TODO: Implement isAuthCodeRevoked() method.
|
||||
}
|
||||
}
|
36
examples/src/Repositories/ClientRepository.php
Normal file
36
examples/src/Repositories/ClientRepository.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ClientEntity;
|
||||
|
||||
class ClientRepository implements ClientRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $clientSecret = null, $redirectUri = null, $grantType = null)
|
||||
{
|
||||
$clients = [
|
||||
'myawesomeapp' => [
|
||||
'secret' => password_hash('abc123', PASSWORD_BCRYPT),
|
||||
'name' => 'My Awesome App',
|
||||
'redirect_uri' => 'http://foo/bar',
|
||||
],
|
||||
];
|
||||
|
||||
// Check if client is registered
|
||||
if (array_key_exists($clientIdentifier, $clients) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$client = new ClientEntity();
|
||||
$client->setIdentifier($clientIdentifier);
|
||||
$client->setName($clients[$clientIdentifier]['name']);
|
||||
$client->setRedirectUri($clients[$clientIdentifier]['redirect_uri']);
|
||||
$client->setSecret($clients[$clientIdentifier]['secret']);
|
||||
|
||||
return $client;
|
||||
}
|
||||
}
|
41
examples/src/Repositories/RefreshTokenRepository.php
Normal file
41
examples/src/Repositories/RefreshTokenRepository.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
|
||||
class RefreshTokenRepository implements RefreshTokenRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new refresh token_name.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntityInterface
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface)
|
||||
{
|
||||
// TODO: Implement persistNewRefreshToken() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke the refresh token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId)
|
||||
{
|
||||
// TODO: Implement revokeRefreshToken() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the refresh token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId)
|
||||
{
|
||||
// TODO: Implement isRefreshTokenRevoked() method.
|
||||
}
|
||||
}
|
46
examples/src/Repositories/ScopeRepository.php
Normal file
46
examples/src/Repositories/ScopeRepository.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ScopeEntity;
|
||||
|
||||
class ScopeRepository implements ScopeRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($scopeIdentifier)
|
||||
{
|
||||
$scopes = [
|
||||
'basic' => [
|
||||
'description' => 'Basic details about you',
|
||||
],
|
||||
'email' => [
|
||||
'description' => 'Your email address',
|
||||
],
|
||||
];
|
||||
|
||||
if (array_key_exists($scopeIdentifier, $scopes) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope = new ScopeEntity();
|
||||
$scope->setIdentifier($scopeIdentifier);
|
||||
|
||||
return $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity,
|
||||
$userIdentifier = null
|
||||
) {
|
||||
return $scopes;
|
||||
}
|
||||
}
|
31
examples/src/Repositories/UserRepository.php
Normal file
31
examples/src/Repositories/UserRepository.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace OAuth2ServerExamples\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use OAuth2ServerExamples\Entities\ScopeEntity;
|
||||
use OAuth2ServerExamples\Entities\UserEntity;
|
||||
|
||||
class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity
|
||||
) {
|
||||
if ($username === 'alex' && $password === 'whisky') {
|
||||
$scope = new ScopeEntity();
|
||||
$scope->setIdentifier('email');
|
||||
$scopes[] = $scope;
|
||||
|
||||
return new UserEntity();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
@@ -1,53 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/Bootstrap.php">
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="true"
|
||||
stopOnFailure="true" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/Bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite name="Authorization Server">
|
||||
<directory suffix="Test.php">tests/authorization</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Resource Server">
|
||||
<directory suffix="Test.php">tests/resource</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Utility Methods">
|
||||
<directory suffix="Test.php">tests/util</directory>
|
||||
<testsuite name="Tests">
|
||||
<directory>./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory suffix=".php">PEAR_INSTALL_DIR</directory>
|
||||
<directory suffix=".php">PHP_LIBDIR</directory>
|
||||
<directory suffix=".php">vendor</directory>
|
||||
<directory suffix=".php">tests</directory>
|
||||
<directory suffix=".php">testing</directory>
|
||||
</blacklist>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src</directory>
|
||||
<exclude>
|
||||
<directory suffix=".php">src/ResponseTypes/DefaultTemplates</directory>
|
||||
<directory suffix=".php">src/TemplateRenderer</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-clover" target="/tmp/coverage.xml"/>
|
||||
<log type="coverage-text" target="php://stdout" showUncoveredFiles="false"/>
|
||||
<log type="coverage-text" target="php://stdout" title="thephpleague/oauth2-server" charset="UTF-8" yui="true"
|
||||
highlight="true" lowUpperBound="60" highLowerBound="90"/>
|
||||
<log type="coverage-html" target="build/coverage" title="thephpleague/oauth2-server" charset="UTF-8" yui="true"
|
||||
highlight="true" lowUpperBound="60" highLowerBound="90"/>
|
||||
</logging>
|
||||
<listeners>
|
||||
<listener class="League\PHPUnitCoverageListener\Listener">
|
||||
<arguments>
|
||||
<array>
|
||||
<element key="printer">
|
||||
<object class="League\PHPUnitCoverageListener\Printer\StdOut"/>
|
||||
</element>
|
||||
<element key="hook">
|
||||
<object class="League\PHPUnitCoverageListener\Hook\Travis"/>
|
||||
</element>
|
||||
<element key="namespace">
|
||||
<string>League\OAuth2\Server</string>
|
||||
</element>
|
||||
<element key="repo_token">
|
||||
<string>DtNuuOrBh1QBXVyRqmVldC2Au11DVti9n</string>
|
||||
</element>
|
||||
<element key="target_url">
|
||||
<string>https://coveralls.io/api/v1/jobs</string>
|
||||
</element>
|
||||
<element key="coverage_dir">
|
||||
<string>/tmp</string>
|
||||
</element>
|
||||
</array>
|
||||
</arguments>
|
||||
</listener>
|
||||
</listeners>
|
||||
</phpunit>
|
||||
|
@@ -1,95 +0,0 @@
|
||||
CREATE TABLE `oauth_clients` (
|
||||
`id` CHAR(40) NOT NULL,
|
||||
`secret` CHAR(40) NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`auto_approve` TINYINT(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oacl_clse_clid` (`secret`,`id`)
|
||||
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_client_endpoints` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` char(40) NOT NULL,
|
||||
`redirect_uri` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `i_oaclen_clid` (`client_id`),
|
||||
CONSTRAINT `f_oaclen_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_sessions` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` char(40) NOT NULL,
|
||||
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
|
||||
`owner_id` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `i_uase_clid_owty_owid` (`client_id`,`owner_type`,`owner_id`),
|
||||
CONSTRAINT `f_oase_clid` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_access_tokens` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`access_token` char(40) NOT NULL,
|
||||
`access_token_expires` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oaseacto_acto_seid` (`access_token`,`session_id`),
|
||||
KEY `f_oaseto_seid` (`session_id`),
|
||||
CONSTRAINT `f_oaseto_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_authcodes` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`auth_code` char(40) NOT NULL,
|
||||
`auth_code_expires` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `session_id` (`session_id`),
|
||||
CONSTRAINT `oauth_session_authcodes_ibfk_1` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_redirects` (
|
||||
`session_id` int(10) unsigned NOT NULL,
|
||||
`redirect_uri` varchar(255) NOT NULL,
|
||||
PRIMARY KEY (`session_id`),
|
||||
CONSTRAINT `f_oasere_seid` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_refresh_tokens` (
|
||||
`session_access_token_id` int(10) unsigned NOT NULL,
|
||||
`refresh_token` char(40) NOT NULL,
|
||||
`refresh_token_expires` int(10) unsigned NOT NULL,
|
||||
`client_id` char(40) NOT NULL,
|
||||
PRIMARY KEY (`session_access_token_id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
CONSTRAINT `oauth_session_refresh_tokens_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `oauth_clients` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `f_oasetore_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_scopes` (
|
||||
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(255) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_oasc_sc` (`scope`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_token_scopes` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_access_token_id` int(10) unsigned DEFAULT NULL,
|
||||
`scope_id` smallint(5) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `u_setosc_setoid_scid` (`session_access_token_id`,`scope_id`),
|
||||
KEY `f_oasetosc_scid` (`scope_id`),
|
||||
CONSTRAINT `f_oasetosc_scid` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
|
||||
CONSTRAINT `f_oasetosc_setoid` FOREIGN KEY (`session_access_token_id`) REFERENCES `oauth_session_access_tokens` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
CREATE TABLE `oauth_session_authcode_scopes` (
|
||||
`oauth_session_authcode_id` int(10) unsigned NOT NULL,
|
||||
`scope_id` smallint(5) unsigned NOT NULL,
|
||||
KEY `oauth_session_authcode_id` (`oauth_session_authcode_id`),
|
||||
KEY `scope_id` (`scope_id`),
|
||||
CONSTRAINT `oauth_session_authcode_scopes_ibfk_2` FOREIGN KEY (`scope_id`) REFERENCES `oauth_scopes` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `oauth_session_authcode_scopes_ibfk_1` FOREIGN KEY (`oauth_session_authcode_id`) REFERENCES `oauth_session_authcodes` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
|
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\AuthorizationValidators;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
interface AuthorizationValidatorInterface
|
||||
{
|
||||
/**
|
||||
* Determine the access token in the authorization header and append OAUth properties to the request
|
||||
* as attributes.
|
||||
*
|
||||
* @param ServerRequestInterface $request
|
||||
*
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthorization(ServerRequestInterface $request);
|
||||
}
|
66
src/AuthorizationValidators/BearerTokenValidator.php
Normal file
66
src/AuthorizationValidators/BearerTokenValidator.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\AuthorizationValidators;
|
||||
|
||||
use Lcobucci\JWT\Parser;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class BearerTokenValidator implements AuthorizationValidatorInterface
|
||||
{
|
||||
use CryptTrait;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* BearerTokenValidator constructor.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function __construct(AccessTokenRepositoryInterface $accessTokenRepository)
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateAuthorization(ServerRequestInterface $request)
|
||||
{
|
||||
if ($request->hasHeader('authorization') === false) {
|
||||
throw OAuthServerException::accessDenied('Missing "Authorization" header');
|
||||
}
|
||||
|
||||
$header = $request->getHeader('authorization');
|
||||
$jwt = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header[0]));
|
||||
|
||||
try {
|
||||
// Attempt to parse and validate the JWT
|
||||
$token = (new Parser())->parse($jwt);
|
||||
if ($token->verify(new Sha256(), $this->publicKeyPath) === false) {
|
||||
throw OAuthServerException::accessDenied('Access token could not be verified');
|
||||
}
|
||||
|
||||
// Check if token has been revoked
|
||||
if ($this->accessTokenRepository->isAccessTokenRevoked($token->getClaim('jti'))) {
|
||||
throw OAuthServerException::accessDenied('Access token has been revoked');
|
||||
}
|
||||
|
||||
// Return the request with additional attributes
|
||||
return $request
|
||||
->withAttribute('oauth_access_token_id', $token->getClaim('jti'))
|
||||
->withAttribute('oauth_client_id', $token->getClaim('aud'))
|
||||
->withAttribute('oauth_user_id', $token->getClaim('sub'))
|
||||
->withAttribute('oauth_scopes', $token->getClaim('scopes'));
|
||||
} catch (\InvalidArgumentException $exception) {
|
||||
// JWT couldn't be parsed so return the request as is
|
||||
throw OAuthServerException::accessDenied($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
122
src/CryptTrait.php
Normal file
122
src/CryptTrait.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* Public/private key encryption.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
trait CryptTrait
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $privateKeyPath;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $publicKeyPath;
|
||||
|
||||
/**
|
||||
* Set path to private key.
|
||||
*
|
||||
* @param string $privateKeyPath
|
||||
*/
|
||||
public function setPrivateKeyPath($privateKeyPath)
|
||||
{
|
||||
if (strpos($privateKeyPath, 'file://') !== 0) {
|
||||
$privateKeyPath = 'file://' . $privateKeyPath;
|
||||
}
|
||||
|
||||
$this->privateKeyPath = $privateKeyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to public key.
|
||||
*
|
||||
* @param string $publicKeyPath
|
||||
*/
|
||||
public function setPublicKeyPath($publicKeyPath)
|
||||
{
|
||||
if (strpos($publicKeyPath, 'file://') !== 0) {
|
||||
$publicKeyPath = 'file://' . $publicKeyPath;
|
||||
}
|
||||
|
||||
$this->publicKeyPath = $publicKeyPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt data with a private key.
|
||||
*
|
||||
* @param string $unencryptedData
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encrypt($unencryptedData)
|
||||
{
|
||||
$privateKey = openssl_pkey_get_private($this->privateKeyPath);
|
||||
$privateKeyDetails = @openssl_pkey_get_details($privateKey);
|
||||
if ($privateKeyDetails === null) {
|
||||
throw new \LogicException(sprintf('Could not get details of private key: %s', $this->privateKeyPath));
|
||||
}
|
||||
|
||||
$chunkSize = ceil($privateKeyDetails['bits'] / 8) - 11;
|
||||
$output = '';
|
||||
|
||||
while ($unencryptedData) {
|
||||
$chunk = substr($unencryptedData, 0, $chunkSize);
|
||||
$unencryptedData = substr($unencryptedData, $chunkSize);
|
||||
if (openssl_private_encrypt($chunk, $encrypted, $privateKey) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \LogicException('Failed to encrypt data');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$output .= $encrypted;
|
||||
}
|
||||
openssl_free_key($privateKey);
|
||||
|
||||
return base64_encode($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt data with a public key.
|
||||
*
|
||||
* @param string $encryptedData
|
||||
*
|
||||
* @throws \LogicException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function decrypt($encryptedData)
|
||||
{
|
||||
$publicKey = openssl_pkey_get_public($this->publicKeyPath);
|
||||
$publicKeyDetails = @openssl_pkey_get_details($publicKey);
|
||||
if ($publicKeyDetails === null) {
|
||||
throw new \LogicException(sprintf('Could not get details of public key: %s', $this->publicKeyPath));
|
||||
}
|
||||
|
||||
$chunkSize = ceil($publicKeyDetails['bits'] / 8);
|
||||
$output = '';
|
||||
|
||||
$encryptedData = base64_decode($encryptedData);
|
||||
|
||||
while ($encryptedData) {
|
||||
$chunk = substr($encryptedData, 0, $chunkSize);
|
||||
$encryptedData = substr($encryptedData, $chunkSize);
|
||||
if (openssl_public_decrypt($chunk, $decrypted, $publicKey/*, OPENSSL_PKCS1_OAEP_PADDING*/) === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \LogicException('Failed to decrypt data');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$output .= $decrypted;
|
||||
}
|
||||
openssl_free_key($publicKey);
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
36
src/Entities/AccessTokenEntity.php
Normal file
36
src/Entities/AccessTokenEntity.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use Lcobucci\JWT\Builder;
|
||||
use Lcobucci\JWT\Signer\Key;
|
||||
use Lcobucci\JWT\Signer\Rsa\Sha256;
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
class AccessTokenEntity implements AccessTokenEntityInterface
|
||||
{
|
||||
use EntityTrait, TokenEntityTrait;
|
||||
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
* @param string $privateKeyPath
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertToJWT($privateKeyPath)
|
||||
{
|
||||
return (new Builder())
|
||||
->setAudience($this->getClient()->getIdentifier())
|
||||
->setId($this->getIdentifier(), true)
|
||||
->setIssuedAt(time())
|
||||
->setNotBefore(time())
|
||||
->setExpiration($this->getExpiryDateTime()->getTimestamp())
|
||||
->setSubject($this->getUserIdentifier())
|
||||
->set('scopes', $this->getScopes())
|
||||
->sign(new Sha256(), new Key($privateKeyPath))
|
||||
->getToken();
|
||||
}
|
||||
}
|
33
src/Entities/AuthCodeEntity.php
Normal file
33
src/Entities/AuthCodeEntity.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\TokenEntityTrait;
|
||||
|
||||
/**
|
||||
* Class AuthCodeEntity.
|
||||
*/
|
||||
class AuthCodeEntity implements AuthCodeEntityInterface
|
||||
{
|
||||
use EntityTrait, TokenEntityTrait;
|
||||
|
||||
protected $redirectUri;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setRedirectUri($uri)
|
||||
{
|
||||
$this->redirectUri = $uri;
|
||||
}
|
||||
}
|
15
src/Entities/Interfaces/AccessTokenEntityInterface.php
Normal file
15
src/Entities/Interfaces/AccessTokenEntityInterface.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface AccessTokenEntityInterface extends TokenInterface
|
||||
{
|
||||
/**
|
||||
* Generate a JWT from the access token
|
||||
*
|
||||
* @param string $privateKeyPath
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convertToJWT($privateKeyPath);
|
||||
}
|
16
src/Entities/Interfaces/AuthCodeEntityInterface.php
Normal file
16
src/Entities/Interfaces/AuthCodeEntityInterface.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface AuthCodeEntityInterface extends TokenInterface
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri();
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
*/
|
||||
public function setRedirectUri($uri);
|
||||
}
|
48
src/Entities/Interfaces/ClientEntityInterface.php
Normal file
48
src/Entities/Interfaces/ClientEntityInterface.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface ClientEntityInterface
|
||||
{
|
||||
/**
|
||||
* Get the client's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the client's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the client's name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Set the client's name.
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name);
|
||||
|
||||
/**
|
||||
* Set the client's redirect uri.
|
||||
*
|
||||
* @param string $redirectUri
|
||||
*/
|
||||
public function setRedirectUri($redirectUri);
|
||||
|
||||
/**
|
||||
* Returns the registered redirect URI.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri();
|
||||
}
|
55
src/Entities/Interfaces/RefreshTokenEntityInterface.php
Normal file
55
src/Entities/Interfaces/RefreshTokenEntityInterface.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface RefreshTokenEntityInterface
|
||||
{
|
||||
/**
|
||||
* Get the token's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the token's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* Set the access token that the refresh token was associated with.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken);
|
||||
|
||||
/**
|
||||
* Get the access token that the refresh token was originally associated with.
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface
|
||||
*/
|
||||
public function getAccessToken();
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired();
|
||||
}
|
20
src/Entities/Interfaces/ScopeEntityInterface.php
Normal file
20
src/Entities/Interfaces/ScopeEntityInterface.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface ScopeEntityInterface extends \JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Get the scope's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the scope's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
}
|
83
src/Entities/Interfaces/TokenInterface.php
Normal file
83
src/Entities/Interfaces/TokenInterface.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface TokenInterface
|
||||
{
|
||||
/**
|
||||
* Get the token's identifier.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Set the token's identifier.
|
||||
*
|
||||
* @param $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return \DateTime
|
||||
*/
|
||||
public function getExpiryDateTime();
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param \DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(\DateTime $dateTime);
|
||||
|
||||
/**
|
||||
* Set the identifier of the user associated with the token.
|
||||
*
|
||||
* @param string|int $identifier The identifier of the user
|
||||
*/
|
||||
public function setUserIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Get the token user's identifier.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function getUserIdentifier();
|
||||
|
||||
/**
|
||||
* Get the client that the token was issued to.
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClient();
|
||||
|
||||
/**
|
||||
* Set the client that the token was issued to.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
*/
|
||||
public function setClient(ClientEntityInterface $client);
|
||||
|
||||
/**
|
||||
* Associate a scope with the token.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope
|
||||
*/
|
||||
public function addScope(ScopeEntityInterface $scope);
|
||||
|
||||
/**
|
||||
* Return an array of scopes associated with the token.
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes();
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired();
|
||||
}
|
13
src/Entities/Interfaces/UserEntityInterface.php
Normal file
13
src/Entities/Interfaces/UserEntityInterface.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Interfaces;
|
||||
|
||||
interface UserEntityInterface
|
||||
{
|
||||
/**
|
||||
* Return the user's identifier.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier();
|
||||
}
|
15
src/Entities/RefreshTokenEntity.php
Normal file
15
src/Entities/RefreshTokenEntity.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Traits\EntityTrait;
|
||||
use League\OAuth2\Server\Entities\Traits\RefreshTokenTrait;
|
||||
|
||||
/**
|
||||
* Class RefreshTokenEntity.
|
||||
*/
|
||||
class RefreshTokenEntity implements RefreshTokenEntityInterface
|
||||
{
|
||||
use EntityTrait, RefreshTokenTrait;
|
||||
}
|
27
src/Entities/Traits/EntityTrait.php
Normal file
27
src/Entities/Traits/EntityTrait.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
trait EntityTrait
|
||||
{
|
||||
/*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $identifier
|
||||
*/
|
||||
public function setIdentifier($identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
}
|
65
src/Entities/Traits/RefreshTokenTrait.php
Normal file
65
src/Entities/Traits/RefreshTokenTrait.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
use DateTime;
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
|
||||
trait RefreshTokenTrait
|
||||
{
|
||||
/**
|
||||
* @var AccessTokenEntityInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @var DateTime
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
return $this->expiryDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return (new DateTime()) > $this->getExpiryDateTime();
|
||||
}
|
||||
}
|
120
src/Entities/Traits/TokenEntityTrait.php
Normal file
120
src/Entities/Traits/TokenEntityTrait.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Entities\Traits;
|
||||
|
||||
use DateTime;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface;
|
||||
|
||||
trait TokenEntityTrait
|
||||
{
|
||||
/**
|
||||
* @var ScopeEntityInterface[]
|
||||
*/
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* @var DateTime
|
||||
*/
|
||||
protected $expiryDateTime;
|
||||
|
||||
/**
|
||||
* @var string|int
|
||||
*/
|
||||
protected $userIdentifier;
|
||||
|
||||
/**
|
||||
* @var ClientEntityInterface
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Associate a scope with the token.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface $scope
|
||||
*/
|
||||
public function addScope(ScopeEntityInterface $scope)
|
||||
{
|
||||
$this->scopes[$scope->getIdentifier()] = $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of scopes associated with the token.
|
||||
*
|
||||
* @return ScopeEntityInterface[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return array_values($this->scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token's expiry date time.
|
||||
*
|
||||
* @return DateTime
|
||||
*/
|
||||
public function getExpiryDateTime()
|
||||
{
|
||||
return $this->expiryDateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date time when the token expires.
|
||||
*
|
||||
* @param DateTime $dateTime
|
||||
*/
|
||||
public function setExpiryDateTime(DateTime $dateTime)
|
||||
{
|
||||
$this->expiryDateTime = $dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of the user associated with the token.
|
||||
*
|
||||
* @param string|int $identifier The identifier of the user
|
||||
*/
|
||||
public function setUserIdentifier($identifier)
|
||||
{
|
||||
$this->userIdentifier = $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token user's identifier.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function getUserIdentifier()
|
||||
{
|
||||
return $this->userIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client that the token was issued to.
|
||||
*
|
||||
* @return ClientEntityInterface
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client that the token was issued to.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
*/
|
||||
public function setClient(ClientEntityInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the token expired?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return (new DateTime()) > $this->getExpiryDateTime();
|
||||
}
|
||||
}
|
265
src/Exception/OAuthServerException.php
Normal file
265
src/Exception/OAuthServerException.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class OAuthServerException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $httpStatusCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $errorType;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $hint;
|
||||
|
||||
/**
|
||||
* @var null|string
|
||||
*/
|
||||
private $redirectUri;
|
||||
|
||||
/**
|
||||
* Throw a new exception.
|
||||
*
|
||||
* @param string $message Error message
|
||||
* @param int $code Error code
|
||||
* @param string $errorType Error type
|
||||
* @param int $httpStatusCode HTTP status code to send (default = 400)
|
||||
* @param null|string $hint A helper hint
|
||||
* @param null|string $redirectUri A HTTP URI to redirect the user back to
|
||||
*/
|
||||
public function __construct($message, $code, $errorType, $httpStatusCode = 400, $hint = null, $redirectUri = null)
|
||||
{
|
||||
parent::__construct($message, $code);
|
||||
$this->httpStatusCode = $httpStatusCode;
|
||||
$this->errorType = $errorType;
|
||||
$this->hint = $hint;
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported grant type error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function unsupportedGrantType()
|
||||
{
|
||||
$errorMessage = 'The authorization grant type is not supported by the authorization server.';
|
||||
$hint = 'Check the `grant_type` parameter';
|
||||
|
||||
return new static($errorMessage, 2, 'unsupported_grant_type', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid request error.
|
||||
*
|
||||
* @param string $parameter The invalid parameter
|
||||
* @param string|null $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidRequest($parameter, $hint = null)
|
||||
{
|
||||
$errorMessage = 'The request is missing a required parameter, includes an invalid parameter value, ' .
|
||||
'includes a parameter more than once, or is otherwise malformed.';
|
||||
$hint = ($hint === null) ? sprintf('Check the `%s` parameter', $parameter) : $hint;
|
||||
|
||||
return new static($errorMessage, 3, 'invalid_request', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid client error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidClient()
|
||||
{
|
||||
$errorMessage = 'Client authentication failed';
|
||||
|
||||
return new static($errorMessage, 4, 'invalid_client', 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid scope error.
|
||||
*
|
||||
* @param string $scope The bad scope
|
||||
* @param null|string $redirectUri A HTTP URI to redirect the user back to
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidScope($scope, $redirectUri = null)
|
||||
{
|
||||
$errorMessage = 'The requested scope is invalid, unknown, or malformed';
|
||||
$hint = sprintf('Check the `%s` scope', $scope);
|
||||
|
||||
return new static($errorMessage, 5, 'invalid_scope', 400, $hint, $redirectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid credentials error.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidCredentials()
|
||||
{
|
||||
return new static('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server error.
|
||||
*
|
||||
* @param $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function serverError($hint)
|
||||
{
|
||||
return new static(
|
||||
'The authorization server encountered an unexpected condition which prevented it from fulfilling'
|
||||
. ' the request: ' . $hint,
|
||||
7,
|
||||
'server_error',
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalid refresh token.
|
||||
*
|
||||
* @param string|null $hint
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function invalidRefreshToken($hint = null)
|
||||
{
|
||||
return new static('The refresh token is invalid.', 8, 'invalid_request', 400, $hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access denied.
|
||||
*
|
||||
* @param string|null $hint
|
||||
* @param string|null $redirectUri
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function accessDenied($hint = null, $redirectUri = null)
|
||||
{
|
||||
return new static(
|
||||
'The resource owner or authorization server denied the request.',
|
||||
9,
|
||||
'access_denied',
|
||||
401,
|
||||
$hint,
|
||||
$redirectUri
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorType()
|
||||
{
|
||||
return $this->errorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a HTTP response.
|
||||
*
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* @param bool $useFragment True if errors should be in the URI fragment instead of
|
||||
* query string
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response, $useFragment = false)
|
||||
{
|
||||
$headers = $this->getHttpHeaders();
|
||||
|
||||
$payload = [
|
||||
'error' => $this->getErrorType(),
|
||||
'message' => $this->getMessage(),
|
||||
];
|
||||
|
||||
if ($this->hint !== null) {
|
||||
$payload['hint'] = $this->hint;
|
||||
}
|
||||
|
||||
if ($this->redirectUri !== null) {
|
||||
if ($useFragment === true) {
|
||||
$this->redirectUri .= (strstr($this->redirectUri, '#') === false) ? '#' : '&';
|
||||
} else {
|
||||
$this->redirectUri .= (strstr($this->redirectUri, '?') === false) ? '?' : '&';
|
||||
}
|
||||
|
||||
return $response->withStatus(302)->withHeader('Location', $this->redirectUri . http_build_query($payload));
|
||||
}
|
||||
|
||||
foreach ($headers as $header => $content) {
|
||||
$response = $response->withHeader($header, $content);
|
||||
}
|
||||
|
||||
$response->getBody()->write(json_encode($payload));
|
||||
|
||||
return $response->withStatus($this->getHttpStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response.
|
||||
*
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public function getHttpHeaders()
|
||||
{
|
||||
$headers = [
|
||||
'Content-type' => 'application/json',
|
||||
];
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($this->errorType === 'invalid_client') {
|
||||
$authScheme = 'Basic';
|
||||
if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) !== false
|
||||
&& strpos($_SERVER['HTTP_AUTHORIZATION'], 'Bearer') === 0
|
||||
) {
|
||||
$authScheme = 'Bearer';
|
||||
}
|
||||
$headers[] = 'WWW-Authenticate: ' . $authScheme . ' realm="OAuth"';
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status code to send when the exceptions is output.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getHttpStatusCode()
|
||||
{
|
||||
return $this->httpStatusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getHint()
|
||||
{
|
||||
return $this->hint;
|
||||
}
|
||||
}
|
66
src/Grant/AbstractAuthorizeGrant.php
Normal file
66
src/Grant/AbstractAuthorizeGrant.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* Abstract authorization grant.
|
||||
*
|
||||
* @author Julián Gutiérrez <juliangut@gmail.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\TemplateRenderer\PlatesRenderer;
|
||||
use League\OAuth2\Server\TemplateRenderer\RendererInterface;
|
||||
use League\Plates\Engine;
|
||||
|
||||
abstract class AbstractAuthorizeGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\TemplateRenderer\RendererInterface
|
||||
*/
|
||||
protected $templateRenderer;
|
||||
|
||||
/**
|
||||
* Set the template renderer
|
||||
*
|
||||
* @param RendererInterface $templateRenderer
|
||||
*/
|
||||
public function setTemplateRenderer(RendererInterface $templateRenderer)
|
||||
{
|
||||
$this->templateRenderer = $templateRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve template renderer.
|
||||
*
|
||||
* @return \League\OAuth2\Server\TemplateRenderer\RendererInterface
|
||||
*/
|
||||
protected function getTemplateRenderer()
|
||||
{
|
||||
if (!$this->templateRenderer instanceof RendererInterface) {
|
||||
$this->templateRenderer = new PlatesRenderer(
|
||||
new Engine(__DIR__ . '/../TemplateRenderer/DefaultTemplates'),
|
||||
'login_user',
|
||||
'authorize_client'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->templateRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $uri
|
||||
* @param array $params
|
||||
* @param string $queryDelimiter
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function makeRedirectUri($uri, $params = [], $queryDelimiter = '?')
|
||||
{
|
||||
$uri .= (strstr($uri, $queryDelimiter) === false) ? $queryDelimiter : '&';
|
||||
|
||||
return $uri . http_build_query($params);
|
||||
}
|
||||
}
|
397
src/Grant/AbstractGrant.php
Normal file
397
src/Grant/AbstractGrant.php
Normal file
@@ -0,0 +1,397 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract grant.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Entities\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entities\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface;
|
||||
use League\OAuth2\Server\Entities\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Abstract grant class.
|
||||
*/
|
||||
abstract class AbstractGrant implements GrantTypeInterface
|
||||
{
|
||||
use EmitterAwareTrait, CryptTrait;
|
||||
|
||||
const SCOPE_DELIMITER_STRING = ' ';
|
||||
|
||||
/**
|
||||
* @var ServerRequestInterface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @var ClientRepositoryInterface
|
||||
*/
|
||||
protected $clientRepository;
|
||||
|
||||
/**
|
||||
* @var AccessTokenRepositoryInterface
|
||||
*/
|
||||
protected $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var ScopeRepositoryInterface
|
||||
*/
|
||||
protected $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface
|
||||
*/
|
||||
protected $authCodeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface
|
||||
*/
|
||||
protected $refreshTokenRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\UserRepositoryInterface
|
||||
*/
|
||||
protected $userRepository;
|
||||
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
protected $refreshTokenTTL;
|
||||
|
||||
/**
|
||||
* @param ClientRepositoryInterface $clientRepository
|
||||
*/
|
||||
public function setClientRepository(ClientRepositoryInterface $clientRepository)
|
||||
{
|
||||
$this->clientRepository = $clientRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository)
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ScopeRepositoryInterface $scopeRepository
|
||||
*/
|
||||
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository)
|
||||
{
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function setRefreshTokenRepository(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
$this->refreshTokenRepository = $refreshTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository
|
||||
*/
|
||||
public function setAuthCodeRepository(AuthCodeRepositoryInterface $authCodeRepository)
|
||||
{
|
||||
$this->authCodeRepository = $authCodeRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
|
||||
*/
|
||||
public function setUserRepository(UserRepositoryInterface $userRepository)
|
||||
{
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL)
|
||||
{
|
||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the client.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface
|
||||
*/
|
||||
protected function validateClient(ServerRequestInterface $request)
|
||||
{
|
||||
$clientId = $this->getRequestParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id', '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
// If the client is confidential require the client secret
|
||||
$clientSecret = $this->getRequestParameter(
|
||||
'client_secret',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_PW', $request)
|
||||
);
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier(),
|
||||
$clientSecret
|
||||
);
|
||||
|
||||
if (!$client instanceof ClientEntityInterface) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
// If a redirect URI is provided ensure it matches what is pre-registered
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if ($redirectUri !== null && (strcmp($client->getRedirectUri(), $redirectUri) !== 0)) {
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate scopes in the request.
|
||||
*
|
||||
* @param string $scopes
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $redirectUri
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[]
|
||||
*/
|
||||
public function validateScopes(
|
||||
$scopes,
|
||||
ClientEntityInterface $client,
|
||||
$redirectUri = null
|
||||
) {
|
||||
$scopesList = array_filter(
|
||||
explode(self::SCOPE_DELIMITER_STRING, trim($scopes)),
|
||||
function ($scope) {
|
||||
return !empty($scope);
|
||||
}
|
||||
);
|
||||
|
||||
$scopes = [];
|
||||
foreach ($scopesList as $scopeItem) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeItem);
|
||||
|
||||
if (($scope instanceof ScopeEntityInterface) === false) {
|
||||
throw OAuthServerException::invalidScope($scopeItem, $redirectUri);
|
||||
}
|
||||
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve request parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getRequestParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
|
||||
return isset($requestParameters[$parameter]) ? $requestParameters[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve query string parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getQueryStringParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getQueryParams()[$parameter]) ? $request->getQueryParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve cookie parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getCookieParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getCookieParams()[$parameter]) ? $request->getCookieParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve server parameter.
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function getServerParameter($parameter, ServerRequestInterface $request, $default = null)
|
||||
{
|
||||
return isset($request->getServerParams()[$parameter]) ? $request->getServerParams()[$parameter] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token.
|
||||
*
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface
|
||||
*/
|
||||
protected function issueAccessToken(
|
||||
\DateInterval $accessTokenTTL,
|
||||
ClientEntityInterface $client,
|
||||
$userIdentifier,
|
||||
array $scopes = []
|
||||
) {
|
||||
$accessToken = new AccessTokenEntity();
|
||||
$accessToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$accessToken->setExpiryDateTime((new \DateTime())->add($accessTokenTTL));
|
||||
$accessToken->setClient($client);
|
||||
$accessToken->setUserIdentifier($userIdentifier);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$accessToken->addScope($scope);
|
||||
}
|
||||
|
||||
$this->accessTokenRepository->persistNewAccessToken($accessToken);
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an auth code.
|
||||
*
|
||||
* @param \DateInterval $authCodeTTL
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
* @param string $userIdentifier
|
||||
* @param string $redirectUri
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[] $scopes
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface
|
||||
*/
|
||||
protected function issueAuthCode(
|
||||
\DateInterval $authCodeTTL,
|
||||
ClientEntityInterface $client,
|
||||
$userIdentifier,
|
||||
$redirectUri,
|
||||
array $scopes = []
|
||||
) {
|
||||
$authCode = new AuthCodeEntity();
|
||||
$authCode->setIdentifier($this->generateUniqueIdentifier());
|
||||
$authCode->setExpiryDateTime((new \DateTime())->add($authCodeTTL));
|
||||
$authCode->setClient($client);
|
||||
$authCode->setUserIdentifier($userIdentifier);
|
||||
$authCode->setRedirectUri($redirectUri);
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$authCode->addScope($scope);
|
||||
}
|
||||
|
||||
$this->authCodeRepository->persistNewAuthCode($authCode);
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface
|
||||
*/
|
||||
protected function issueRefreshToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$refreshToken = new RefreshTokenEntity();
|
||||
$refreshToken->setIdentifier($this->generateUniqueIdentifier());
|
||||
$refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL));
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
|
||||
$this->refreshTokenRepository->persistNewRefreshToken($refreshToken);
|
||||
|
||||
return $refreshToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new unique identifier.
|
||||
*
|
||||
* @param int $length
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateUniqueIdentifier($length = 40)
|
||||
{
|
||||
try {
|
||||
return bin2hex(random_bytes($length));
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\TypeError $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Error $e) {
|
||||
throw OAuthServerException::serverError('An unexpected error has occurred');
|
||||
} catch (\Exception $e) {
|
||||
// If you get this message, the CSPRNG failed hard.
|
||||
throw OAuthServerException::serverError('Could not generate a random string');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
$requestParameters = (array) $request->getParsedBody();
|
||||
|
||||
return (
|
||||
array_key_exists('grant_type', $requestParameters)
|
||||
&& $requestParameters['grant_type'] === $this->getIdentifier()
|
||||
);
|
||||
}
|
||||
}
|
350
src/Grant/AuthCodeGrant.php
Normal file
350
src/Grant/AuthCodeGrant.php
Normal file
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use DateInterval;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\HtmlResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\RedirectResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use League\OAuth2\Server\TemplateRenderer\RendererInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthCodeGrant extends AbstractAuthorizeGrant
|
||||
{
|
||||
/**
|
||||
* @var \DateInterval
|
||||
*/
|
||||
private $authCodeTTL;
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\AuthCodeRepositoryInterface $authCodeRepository
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
|
||||
* @param \DateInterval $authCodeTTL
|
||||
* @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer
|
||||
*/
|
||||
public function __construct(
|
||||
AuthCodeRepositoryInterface $authCodeRepository,
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository,
|
||||
UserRepositoryInterface $userRepository,
|
||||
\DateInterval $authCodeTTL,
|
||||
RendererInterface $templateRenderer = null
|
||||
) {
|
||||
$this->setAuthCodeRepository($authCodeRepository);
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
$this->setUserRepository($userRepository);
|
||||
$this->authCodeTTL = $authCodeTTL;
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
$this->templateRenderer = $templateRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to an authorization request.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
protected function respondToAuthorizationRequest(
|
||||
ServerRequestInterface $request
|
||||
) {
|
||||
$clientId = $this->getQueryStringParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri());
|
||||
if ($redirectUriParameter !== $client->getRedirectUri()) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
$client,
|
||||
$client->getRedirectUri()
|
||||
);
|
||||
|
||||
$postbackUri = sprintf(
|
||||
'//%s%s',
|
||||
$request->getServerParams()['HTTP_HOST'],
|
||||
$request->getServerParams()['REQUEST_URI']
|
||||
);
|
||||
|
||||
$userId = null;
|
||||
$userHasApprovedClient = null;
|
||||
if ($this->getRequestParameter('action', $request, null) !== null) {
|
||||
$userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve');
|
||||
}
|
||||
|
||||
// Check if the user has been authenticated
|
||||
$oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null);
|
||||
if ($oauthCookie !== null) {
|
||||
try {
|
||||
$oauthCookiePayload = json_decode($this->decrypt($oauthCookie));
|
||||
if (is_object($oauthCookiePayload)) {
|
||||
$userId = $oauthCookiePayload->user_id;
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::serverError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// The username + password might be available in $_POST
|
||||
$usernameParameter = $this->getRequestParameter('username', $request, null);
|
||||
$passwordParameter = $this->getRequestParameter('password', $request, null);
|
||||
|
||||
$loginError = null;
|
||||
|
||||
// Assert if the user has logged in already
|
||||
if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) {
|
||||
$userEntity = $this->userRepository->getUserEntityByUserCredentials(
|
||||
$usernameParameter,
|
||||
$passwordParameter,
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
|
||||
if ($userEntity instanceof UserEntityInterface) {
|
||||
$userId = $userEntity->getIdentifier();
|
||||
} else {
|
||||
$loginError = 'Incorrect username or password';
|
||||
}
|
||||
}
|
||||
|
||||
// The user hasn't logged in yet so show a login form
|
||||
if ($userId === null) {
|
||||
$html = $this->getTemplateRenderer()->renderLogin([
|
||||
'error' => $loginError,
|
||||
'postback_uri' => $this->makeRedirectUri(
|
||||
$postbackUri,
|
||||
$request->getQueryParams()
|
||||
),
|
||||
]);
|
||||
|
||||
$htmlResponse = new HtmlResponse($this->accessTokenRepository);
|
||||
$htmlResponse->setStatusCode(403);
|
||||
$htmlResponse->setHtml($html);
|
||||
|
||||
return $htmlResponse;
|
||||
}
|
||||
|
||||
// The user hasn't approved the client yet so show an authorize form
|
||||
if ($userId !== null && $userHasApprovedClient === null) {
|
||||
$html = $this->getTemplateRenderer()->renderAuthorize([
|
||||
'client' => $client,
|
||||
'scopes' => $scopes,
|
||||
'postback_uri' => $this->makeRedirectUri(
|
||||
$postbackUri,
|
||||
$request->getQueryParams()
|
||||
),
|
||||
]);
|
||||
|
||||
$htmlResponse = new HtmlResponse($this->accessTokenRepository);
|
||||
$htmlResponse->setStatusCode(200);
|
||||
$htmlResponse->setHtml($html);
|
||||
$htmlResponse->setHeader('set-cookie', sprintf(
|
||||
'oauth_authorize_request=%s; Expires=%s',
|
||||
urlencode($this->encrypt(
|
||||
json_encode([
|
||||
'user_id' => $userId,
|
||||
])
|
||||
)),
|
||||
(new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e')
|
||||
));
|
||||
|
||||
return $htmlResponse;
|
||||
}
|
||||
|
||||
// The user has either approved or denied the client, so redirect them back
|
||||
$redirectUri = $client->getRedirectUri();
|
||||
$redirectPayload = [];
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
if ($stateParameter !== null) {
|
||||
$redirectPayload['state'] = $stateParameter;
|
||||
}
|
||||
|
||||
// THe user approved the client, redirect them back with an auth code
|
||||
if ($userHasApprovedClient === true) {
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId);
|
||||
|
||||
$authCode = $this->issueAuthCode(
|
||||
$this->authCodeTTL,
|
||||
$client,
|
||||
$userId,
|
||||
$redirectUri,
|
||||
$scopes
|
||||
);
|
||||
|
||||
$redirectPayload['code'] = $this->encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $authCode->getClient()->getIdentifier(),
|
||||
'redirect_uri' => $authCode->getRedirectUri(),
|
||||
'auth_code_id' => $authCode->getIdentifier(),
|
||||
'scopes' => $authCode->getScopes(),
|
||||
'user_id' => $authCode->getUserIdentifier(),
|
||||
'expire_time' => (new \DateTime())->add($this->authCodeTTL)->format('U'),
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$response = new RedirectResponse($this->accessTokenRepository);
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$redirectUri,
|
||||
$redirectPayload
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to an access token request.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
|
||||
*/
|
||||
protected function respondToAccessTokenRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
DateInterval $accessTokenTTL
|
||||
) {
|
||||
// The redirect URI is required in this request
|
||||
$redirectUri = $this->getRequestParameter('redirect_uri', $request, null);
|
||||
if (is_null($redirectUri)) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri');
|
||||
}
|
||||
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$encryptedAuthCode = $this->getRequestParameter('code', $request, null);
|
||||
|
||||
if ($encryptedAuthCode === null) {
|
||||
throw OAuthServerException::invalidRequest('code');
|
||||
}
|
||||
|
||||
// Validate the authorization code
|
||||
try {
|
||||
$authCodePayload = json_decode($this->decrypt($encryptedAuthCode));
|
||||
if (time() > $authCodePayload->expire_time) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has expired');
|
||||
}
|
||||
|
||||
if ($this->authCodeRepository->isAuthCodeRevoked($authCodePayload->auth_code_id) === true) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code has been revoked');
|
||||
}
|
||||
|
||||
if ($authCodePayload->client_id !== $client->getIdentifier()) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Authorization code was not issued to this client');
|
||||
}
|
||||
|
||||
if ($authCodePayload->redirect_uri !== $redirectUri) {
|
||||
throw OAuthServerException::invalidRequest('redirect_uri', 'Invalid redirect URI');
|
||||
}
|
||||
|
||||
$scopes = [];
|
||||
foreach ($authCodePayload->scopes as $scopeId) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if (!$scope) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$scopes[] = $scope;
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::invalidRequest('code', 'Cannot decrypt the authorization code');
|
||||
}
|
||||
|
||||
// Issue and persist access + refresh tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $authCodePayload->user_id, $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
|
||||
// Inject tokens into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
if (
|
||||
array_key_exists('response_type', $request->getQueryParams())
|
||||
&& $request->getQueryParams()['response_type'] === 'code'
|
||||
) {
|
||||
return $this->respondToAuthorizationRequest($request);
|
||||
}
|
||||
|
||||
return $this->respondToAccessTokenRequest($request, $responseType, $accessTokenTTL);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return
|
||||
(
|
||||
array_key_exists('response_type', $request->getQueryParams())
|
||||
&& $request->getQueryParams()['response_type'] === 'code'
|
||||
&& isset($request->getQueryParams()['client_id'])
|
||||
)
|
||||
|| parent::canRespondToRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'authorization_code';
|
||||
}
|
||||
}
|
52
src/Grant/ClientCredentialsGrant.php
Normal file
52
src/Grant/ClientCredentialsGrant.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class.
|
||||
*/
|
||||
class ClientCredentialsGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client);
|
||||
|
||||
// Issue and persist access token
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $client->getIdentifier(), $scopes);
|
||||
|
||||
// Inject access token into response type
|
||||
$responseType->setAccessToken($accessToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'client_credentials';
|
||||
}
|
||||
}
|
102
src/Grant/GrantTypeInterface.php
Normal file
102
src/Grant/GrantTypeInterface.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Grant type interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\Event\EmitterAwareInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Grant type interface.
|
||||
*/
|
||||
interface GrantTypeInterface extends EmitterAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set refresh token TTL.
|
||||
*
|
||||
* @param \DateInterval $refreshTokenTTL
|
||||
*/
|
||||
public function setRefreshTokenTTL(\DateInterval $refreshTokenTTL);
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Respond to an incoming request.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*
|
||||
* @return \League\OAuth2\Server\ResponseTypes\ResponseTypeInterface
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
);
|
||||
|
||||
/**
|
||||
* The grant type should return true if it is able to respond to this request.
|
||||
*
|
||||
* For example most grant types will check that the $_POST['grant_type'] property matches it's identifier property.
|
||||
*
|
||||
* Some grants, such as the authorization code grant can respond to multiple requests
|
||||
* - i.e. a client requesting an authorization code and requesting an access token
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request);
|
||||
|
||||
/**
|
||||
* Set the client repository.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
|
||||
*/
|
||||
public function setClientRepository(ClientRepositoryInterface $clientRepository);
|
||||
|
||||
/**
|
||||
* Set the access token repository.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function setAccessTokenRepository(AccessTokenRepositoryInterface $accessTokenRepository);
|
||||
|
||||
/**
|
||||
* Set the scope repository.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
|
||||
*/
|
||||
public function setScopeRepository(ScopeRepositoryInterface $scopeRepository);
|
||||
|
||||
/**
|
||||
* Set the path to the private key.
|
||||
*
|
||||
* @param string $privateKeyPath
|
||||
*/
|
||||
public function setPrivateKeyPath($privateKeyPath);
|
||||
|
||||
/**
|
||||
* Set the path to the public key.
|
||||
*
|
||||
* @param string $publicKeyPath
|
||||
*/
|
||||
public function setPublicKeyPath($publicKeyPath);
|
||||
}
|
219
src/Grant/ImplicitGrant.php
Normal file
219
src/Grant/ImplicitGrant.php
Normal file
@@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\HtmlResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\RedirectResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use League\OAuth2\Server\TemplateRenderer\RendererInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ImplicitGrant extends AbstractAuthorizeGrant
|
||||
{
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
|
||||
* @param \League\OAuth2\Server\TemplateRenderer\RendererInterface|null $templateRenderer
|
||||
*/
|
||||
public function __construct(UserRepositoryInterface $userRepository, RendererInterface $templateRenderer = null)
|
||||
{
|
||||
$this->setUserRepository($userRepository);
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
$this->templateRenderer = $templateRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function canRespondToRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return (array_key_exists('response_type', $request->getQueryParams())
|
||||
&& $request->getQueryParams()['response_type'] === 'token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the grant identifier that can be used in matching up requests.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'implicit';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
$clientId = $this->getQueryStringParameter(
|
||||
'client_id',
|
||||
$request,
|
||||
$this->getServerParameter('PHP_AUTH_USER', $request)
|
||||
);
|
||||
if (is_null($clientId)) {
|
||||
throw OAuthServerException::invalidRequest('client_id');
|
||||
}
|
||||
|
||||
$client = $this->clientRepository->getClientEntity(
|
||||
$clientId,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if ($client instanceof ClientEntityInterface === false) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$redirectUriParameter = $this->getQueryStringParameter('redirect_uri', $request, $client->getRedirectUri());
|
||||
if ($redirectUriParameter !== $client->getRedirectUri()) {
|
||||
$this->getEmitter()->emit(new RequestEvent('client.authentication.failed', $request));
|
||||
throw OAuthServerException::invalidClient();
|
||||
}
|
||||
|
||||
$scopes = $this->validateScopes(
|
||||
$this->getQueryStringParameter('scope', $request),
|
||||
$client,
|
||||
$client->getRedirectUri()
|
||||
);
|
||||
|
||||
$postbackUri = sprintf(
|
||||
'//%s%s',
|
||||
$request->getServerParams()['HTTP_HOST'],
|
||||
$request->getServerParams()['REQUEST_URI']
|
||||
);
|
||||
|
||||
$userId = null;
|
||||
$userHasApprovedClient = null;
|
||||
if ($this->getRequestParameter('action', $request, null) !== null) {
|
||||
$userHasApprovedClient = ($this->getRequestParameter('action', $request) === 'approve');
|
||||
}
|
||||
|
||||
// Check if the user has been authenticated
|
||||
$oauthCookie = $this->getCookieParameter('oauth_authorize_request', $request, null);
|
||||
if ($oauthCookie !== null) {
|
||||
try {
|
||||
$oauthCookiePayload = json_decode($this->decrypt($oauthCookie));
|
||||
if (is_object($oauthCookiePayload)) {
|
||||
$userId = $oauthCookiePayload->user_id;
|
||||
}
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::serverError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// The username + password might be available in $_POST
|
||||
$usernameParameter = $this->getRequestParameter('username', $request, null);
|
||||
$passwordParameter = $this->getRequestParameter('password', $request, null);
|
||||
|
||||
$loginError = null;
|
||||
|
||||
// Assert if the user has logged in already
|
||||
if ($userId === null && $usernameParameter !== null && $passwordParameter !== null) {
|
||||
$userEntity = $this->userRepository->getUserEntityByUserCredentials(
|
||||
$usernameParameter,
|
||||
$passwordParameter,
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
|
||||
if ($userEntity instanceof UserEntityInterface) {
|
||||
$userId = $userEntity->getIdentifier();
|
||||
} else {
|
||||
$loginError = 'Incorrect username or password';
|
||||
}
|
||||
}
|
||||
|
||||
// The user hasn't logged in yet so show a login form
|
||||
if ($userId === null) {
|
||||
$html = $this->getTemplateRenderer()->renderLogin([
|
||||
'error' => $loginError,
|
||||
'postback_uri' => $this->makeRedirectUri(
|
||||
$postbackUri,
|
||||
$request->getQueryParams()
|
||||
),
|
||||
]);
|
||||
|
||||
$htmlResponse = new HtmlResponse($this->accessTokenRepository);
|
||||
$htmlResponse->setStatusCode(403);
|
||||
$htmlResponse->setHtml($html);
|
||||
|
||||
return $htmlResponse;
|
||||
}
|
||||
|
||||
// The user hasn't approved the client yet so show an authorize form
|
||||
if ($userId !== null && $userHasApprovedClient === null) {
|
||||
$html = $this->getTemplateRenderer()->renderAuthorize([
|
||||
'client' => $client,
|
||||
'scopes' => $scopes,
|
||||
'postback_uri' => $this->makeRedirectUri(
|
||||
$postbackUri,
|
||||
$request->getQueryParams()
|
||||
),
|
||||
]);
|
||||
|
||||
$htmlResponse = new HtmlResponse($this->accessTokenRepository);
|
||||
$htmlResponse->setStatusCode(200);
|
||||
$htmlResponse->setHtml($html);
|
||||
$htmlResponse->setHeader('set-cookie', sprintf(
|
||||
'oauth_authorize_request=%s; Expires=%s',
|
||||
urlencode($this->encrypt(
|
||||
json_encode([
|
||||
'user_id' => $userId,
|
||||
])
|
||||
)),
|
||||
(new \DateTime())->add(new \DateInterval('PT5M'))->format('D, d M Y H:i:s e')
|
||||
));
|
||||
|
||||
return $htmlResponse;
|
||||
}
|
||||
|
||||
// The user has either approved or denied the client, so redirect them back
|
||||
$redirectUri = $client->getRedirectUri();
|
||||
$redirectPayload = [];
|
||||
|
||||
$stateParameter = $this->getQueryStringParameter('state', $request);
|
||||
if ($stateParameter !== null) {
|
||||
$redirectPayload['state'] = $stateParameter;
|
||||
}
|
||||
|
||||
// THe user approved the client, redirect them back with an access token
|
||||
if ($userHasApprovedClient === true) {
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $userId);
|
||||
|
||||
$accessToken = $this->issueAccessToken(
|
||||
$accessTokenTTL,
|
||||
$client,
|
||||
$userId,
|
||||
$scopes
|
||||
);
|
||||
|
||||
$redirectPayload['access_token'] = (string) $accessToken->convertToJWT($this->privateKeyPath);
|
||||
$redirectPayload['token_type'] = 'bearer';
|
||||
$redirectPayload['expires_in'] = time() - $accessToken->getExpiryDateTime()->getTimestamp();
|
||||
|
||||
$response = new RedirectResponse($this->accessTokenRepository);
|
||||
$response->setRedirectUri(
|
||||
$this->makeRedirectUri(
|
||||
$redirectUri,
|
||||
$redirectPayload,
|
||||
'#'
|
||||
)
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
// The user denied the client, redirect them back with an error
|
||||
throw OAuthServerException::accessDenied('The user denied the request', (string) $redirectUri);
|
||||
}
|
||||
}
|
110
src/Grant/PasswordGrant.php
Normal file
110
src/Grant/PasswordGrant.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Password grant.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\UserEntityInterface;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\UserRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Password grant class.
|
||||
*/
|
||||
class PasswordGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\UserRepositoryInterface $userRepository
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function __construct(
|
||||
UserRepositoryInterface $userRepository,
|
||||
RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
) {
|
||||
$this->setUserRepository($userRepository);
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
|
||||
$user = $this->validateUser($request, $client);
|
||||
|
||||
// Finalize the requested scopes
|
||||
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
|
||||
|
||||
// Issue and persist new tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
|
||||
// Inject tokens into response
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $client
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface
|
||||
*/
|
||||
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
|
||||
{
|
||||
$username = $this->getRequestParameter('username', $request);
|
||||
if (is_null($username)) {
|
||||
throw OAuthServerException::invalidRequest('username', '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$password = $this->getRequestParameter('password', $request);
|
||||
if (is_null($password)) {
|
||||
throw OAuthServerException::invalidRequest('password', '`%s` parameter is missing');
|
||||
}
|
||||
|
||||
$user = $this->userRepository->getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$this->getIdentifier(),
|
||||
$client
|
||||
);
|
||||
if (!$user instanceof UserEntityInterface) {
|
||||
$this->getEmitter()->emit(new RequestEvent('user.authentication.failed', $request));
|
||||
|
||||
throw OAuthServerException::invalidCredentials();
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'password';
|
||||
}
|
||||
}
|
135
src/Grant/RefreshTokenGrant.php
Normal file
135
src/Grant/RefreshTokenGrant.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token grant.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\RequestEvent;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Refresh token grant.
|
||||
*/
|
||||
class RefreshTokenGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface $refreshTokenRepository
|
||||
*/
|
||||
public function __construct(RefreshTokenRepositoryInterface $refreshTokenRepository)
|
||||
{
|
||||
$this->setRefreshTokenRepository($refreshTokenRepository);
|
||||
|
||||
$this->refreshTokenTTL = new \DateInterval('P1M');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function respondToRequest(
|
||||
ServerRequestInterface $request,
|
||||
ResponseTypeInterface $responseType,
|
||||
\DateInterval $accessTokenTTL
|
||||
) {
|
||||
// Validate request
|
||||
$client = $this->validateClient($request);
|
||||
$oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
|
||||
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request), $client);
|
||||
|
||||
// If no new scopes are requested then give the access token the original session scopes
|
||||
if (count($scopes) === 0) {
|
||||
$scopes = array_map(function ($scopeId) use ($client) {
|
||||
$scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);
|
||||
|
||||
if (!$scope) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw OAuthServerException::invalidScope($scopeId);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $scope;
|
||||
}, $oldRefreshToken['scopes']);
|
||||
} else {
|
||||
// The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
|
||||
// the request doesn't include any new scopes
|
||||
foreach ($scopes as $scope) {
|
||||
if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) {
|
||||
throw OAuthServerException::invalidScope($scope->getIdentifier());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expire old tokens
|
||||
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
|
||||
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
|
||||
|
||||
// Issue and persist new tokens
|
||||
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
|
||||
$refreshToken = $this->issueRefreshToken($accessToken);
|
||||
|
||||
// Inject tokens into response
|
||||
$responseType->setAccessToken($accessToken);
|
||||
$responseType->setRefreshToken($refreshToken);
|
||||
|
||||
return $responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param string $clientId
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function validateOldRefreshToken(ServerRequestInterface $request, $clientId)
|
||||
{
|
||||
$encryptedRefreshToken = $this->getRequestParameter('refresh_token', $request);
|
||||
if (is_null($encryptedRefreshToken)) {
|
||||
throw OAuthServerException::invalidRequest('refresh_token');
|
||||
}
|
||||
|
||||
// Validate refresh token
|
||||
try {
|
||||
$refreshToken = $this->decrypt($encryptedRefreshToken);
|
||||
} catch (\LogicException $e) {
|
||||
throw OAuthServerException::invalidRefreshToken('Cannot parse refresh token: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$refreshTokenData = json_decode($refreshToken, true);
|
||||
if ($refreshTokenData['client_id'] !== $clientId) {
|
||||
$this->getEmitter()->emit(new RequestEvent('refresh_token.client.failed', $request));
|
||||
throw OAuthServerException::invalidRefreshToken(
|
||||
'Token is not linked to client,' .
|
||||
' got: ' . $clientId .
|
||||
' expected: ' . $refreshTokenData['client_id']
|
||||
);
|
||||
}
|
||||
|
||||
if ($refreshTokenData['expire_time'] < time()) {
|
||||
throw OAuthServerException::invalidRefreshToken('Token has expired');
|
||||
}
|
||||
|
||||
if ($this->refreshTokenRepository->isRefreshTokenRevoked($refreshTokenData['refresh_token_id']) === true) {
|
||||
throw OAuthServerException::invalidRefreshToken('Token has been revoked');
|
||||
}
|
||||
|
||||
return $refreshTokenData;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return 'refresh_token';
|
||||
}
|
||||
}
|
@@ -1,479 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Authorization Server
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use League\OAuth2\Server\Util\Request;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 authorization server class
|
||||
*/
|
||||
class Authorization
|
||||
{
|
||||
/**
|
||||
* The delimeter between scopes specified in the scope query string parameter
|
||||
*
|
||||
* The OAuth 2 specification states it should be a space but most use a comma
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeDelimeter = ' ';
|
||||
|
||||
/**
|
||||
* The TTL (time to live) of an access token in seconds (default: 3600)
|
||||
* @var integer
|
||||
*/
|
||||
protected $accessTokenTTL = 3600;
|
||||
|
||||
/**
|
||||
* The registered grant response types
|
||||
* @var array
|
||||
*/
|
||||
protected $responseTypes = array();
|
||||
|
||||
/**
|
||||
* The client, scope and session storage classes
|
||||
* @var array
|
||||
*/
|
||||
protected $storages = array();
|
||||
|
||||
/**
|
||||
* The registered grant types
|
||||
* @var array
|
||||
*/
|
||||
protected $grantTypes = array();
|
||||
|
||||
/**
|
||||
* Require the "scope" parameter to be in checkAuthoriseParams()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireScopeParam = false;
|
||||
|
||||
/**
|
||||
* Default scope(s) to be used if none is provided
|
||||
* @var string|array
|
||||
*/
|
||||
protected $defaultScope = null;
|
||||
|
||||
/**
|
||||
* Require the "state" parameter to be in checkAuthoriseParams()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireStateParam = false;
|
||||
|
||||
/**
|
||||
* The request object
|
||||
* @var Util\RequestInterface
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionCodes = array(
|
||||
0 => 'invalid_request',
|
||||
1 => 'unauthorized_client',
|
||||
2 => 'access_denied',
|
||||
3 => 'unsupported_response_type',
|
||||
4 => 'invalid_scope',
|
||||
5 => 'server_error',
|
||||
6 => 'temporarily_unavailable',
|
||||
7 => 'unsupported_grant_type',
|
||||
8 => 'invalid_client',
|
||||
9 => 'invalid_grant'
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error messages
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionMessages = array(
|
||||
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
'unauthorized_client' => 'The client is not authorized to request an access token using this method.',
|
||||
'access_denied' => 'The resource owner or authorization server denied the request.',
|
||||
'unsupported_response_type' => 'The authorization server does not support obtaining an access token using this method.',
|
||||
'invalid_scope' => 'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.',
|
||||
'server_error' => 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.',
|
||||
'temporarily_unavailable' => 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.',
|
||||
'unsupported_grant_type' => 'The authorization grant type "%s" is not supported by the authorization server',
|
||||
'invalid_client' => 'Client authentication failed',
|
||||
'invalid_grant' => 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client. Check the "%s" parameter.',
|
||||
'invalid_credentials' => 'The user credentials were incorrect.',
|
||||
'invalid_refresh' => 'The refresh token is invalid.',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error HTTP status codes
|
||||
* @var array
|
||||
*
|
||||
* RFC 6749, section 4.1.2.1.:
|
||||
* No 503 status code for 'temporarily_unavailable', because
|
||||
* "a 503 Service Unavailable HTTP status code cannot be
|
||||
* returned to the client via an HTTP redirect"
|
||||
*/
|
||||
protected static $exceptionHttpStatusCodes = array(
|
||||
'invalid_request' => 400,
|
||||
'unauthorized_client' => 400,
|
||||
'access_denied' => 401,
|
||||
'unsupported_response_type' => 400,
|
||||
'invalid_scope' => 400,
|
||||
'server_error' => 500,
|
||||
'temporarily_unavailable' => 400,
|
||||
'unsupported_grant_type' => 501,
|
||||
'invalid_client' => 401,
|
||||
'invalid_grant' => 400,
|
||||
'invalid_credentials' => 400,
|
||||
'invalid_refresh' => 400,
|
||||
);
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public static function getExceptionHttpHeaders($error)
|
||||
{
|
||||
$headers = array();
|
||||
switch (self::$exceptionHttpStatusCodes[$error]) {
|
||||
case 401:
|
||||
$headers[] = 'HTTP/1.1 401 Unauthorized';
|
||||
break;
|
||||
case 500:
|
||||
$headers[] = 'HTTP/1.1 500 Internal Server Error';
|
||||
break;
|
||||
case 501:
|
||||
$headers[] = 'HTTP/1.1 501 Not Implemented';
|
||||
break;
|
||||
case 400:
|
||||
default:
|
||||
$headers[] = 'HTTP/1.1 400 Bad Request';
|
||||
}
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($error === 'invalid_client') {
|
||||
$authScheme = null;
|
||||
$request = new Request();
|
||||
if ($request->server('PHP_AUTH_USER') !== null) {
|
||||
$authScheme = 'Basic';
|
||||
} else {
|
||||
$authHeader = $request->header('Authorization');
|
||||
if ($authHeader !== null) {
|
||||
if (strpos($authHeader, 'Bearer') === 0) {
|
||||
$authScheme = 'Bearer';
|
||||
} elseif (strpos($authHeader, 'Basic') === 0) {
|
||||
$authScheme = 'Basic';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($authScheme !== null) {
|
||||
$headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""';
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception message
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return string The error message
|
||||
*/
|
||||
public static function getExceptionMessage($error = '')
|
||||
{
|
||||
return self::$exceptionMessages[$error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception code
|
||||
*
|
||||
* @param integer $code The exception code
|
||||
* @return string The exception code type
|
||||
*/
|
||||
public static function getExceptionType($code = 0)
|
||||
{
|
||||
return self::$exceptionCodes[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OAuth2 authorization server
|
||||
*
|
||||
* @param ClientInterface $client A class which inherits from Storage/ClientInterface
|
||||
* @param SessionInterface $session A class which inherits from Storage/SessionInterface
|
||||
* @param ScopeInterface $scope A class which inherits from Storage/ScopeInterface
|
||||
*/
|
||||
public function __construct(ClientInterface $client, SessionInterface $session, ScopeInterface $scope)
|
||||
{
|
||||
$this->storages = array(
|
||||
'client' => $client,
|
||||
'session' => $session,
|
||||
'scope' => $scope
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable support for a grant
|
||||
* @param GrantTypeInterface $grantType A grant class which conforms to Interface/GrantTypeInterface
|
||||
* @param null|string $identifier An identifier for the grant (autodetected if not passed)
|
||||
*/
|
||||
public function addGrantType(GrantTypeInterface $grantType, $identifier = null)
|
||||
{
|
||||
if (is_null($identifier)) {
|
||||
$identifier = $grantType->getIdentifier();
|
||||
}
|
||||
|
||||
// Inject server into grant
|
||||
$grantType->setAuthorizationServer($this);
|
||||
|
||||
$this->grantTypes[$identifier] = $grantType;
|
||||
|
||||
if ( ! is_null($grantType->getResponseType())) {
|
||||
$this->responseTypes[] = $grantType->getResponseType();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a grant type has been enabled
|
||||
* @param string $identifier The grant type identifier
|
||||
* @return boolean Returns "true" if enabled, "false" if not
|
||||
*/
|
||||
public function hasGrantType($identifier)
|
||||
{
|
||||
return (array_key_exists($identifier, $this->grantTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response types
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getResponseTypes()
|
||||
{
|
||||
return $this->responseTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "scope" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function requireScopeParam($require = true)
|
||||
{
|
||||
$this->requireScopeParam = $require;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the scope parameter required?
|
||||
* @return bool
|
||||
*/
|
||||
public function scopeParamRequired()
|
||||
{
|
||||
return $this->requireScopeParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default scope to be used if none is provided and requireScopeParam is false
|
||||
* @param string|array $default
|
||||
*/
|
||||
public function setDefaultScope($default = null)
|
||||
{
|
||||
$this->defaultScope = $default;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default scope to be used if none is provided and requireScopeParam is false
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDefaultScope()
|
||||
{
|
||||
return $this->defaultScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function stateParamRequired()
|
||||
{
|
||||
return $this->requireStateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the "state" paremter in checkAuthoriseParams()
|
||||
* @param boolean $require
|
||||
* @return void
|
||||
*/
|
||||
public function requireStateParam($require = true)
|
||||
{
|
||||
$this->requireStateParam = $require;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scope delimeter
|
||||
*
|
||||
* @return string The scope delimiter (default: ",")
|
||||
*/
|
||||
public function getScopeDelimeter()
|
||||
{
|
||||
return $this->scopeDelimeter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scope delimiter
|
||||
*
|
||||
* @param string $scopeDelimeter
|
||||
*/
|
||||
public function setScopeDelimeter($scopeDelimeter = ' ')
|
||||
{
|
||||
$this->scopeDelimeter = $scopeDelimeter;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TTL for an access token
|
||||
* @return int The TTL
|
||||
*/
|
||||
public function getAccessTokenTTL()
|
||||
{
|
||||
return $this->accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TTL for an access token
|
||||
* @param int $accessTokenTTL The new TTL
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL = 3600)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Request Object
|
||||
*
|
||||
* @param Util\RequestInterface The Request Object
|
||||
*/
|
||||
public function setRequest(Util\RequestInterface $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Request object. It will create one from the globals if one is not set.
|
||||
*
|
||||
* @return Util\RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->request = Request::buildFromGlobals();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a storage class
|
||||
* @param string $obj The class required
|
||||
* @return Storage\ClientInterface|Storage\ScopeInterface|Storage\SessionInterface
|
||||
*/
|
||||
public function getStorage($obj)
|
||||
{
|
||||
return $this->storages[$obj];
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
*
|
||||
* @param array $inputParams Optional array of parsed $_POST keys
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function issueAccessToken($inputParams = array())
|
||||
{
|
||||
$grantType = $this->getParam('grant_type', 'post', $inputParams);
|
||||
|
||||
if (is_null($grantType)) {
|
||||
throw new Exception\ClientException(sprintf(self::$exceptionMessages['invalid_request'], 'grant_type'), 0);
|
||||
}
|
||||
|
||||
// Ensure grant type is one that is recognised and is enabled
|
||||
if ( ! in_array($grantType, array_keys($this->grantTypes))) {
|
||||
throw new Exception\ClientException(sprintf(self::$exceptionMessages['unsupported_grant_type'], $grantType), 7);
|
||||
}
|
||||
|
||||
// Complete the flow
|
||||
return $this->getGrantType($grantType)->completeFlow($inputParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a grant type class
|
||||
* @param string $grantType The grant type identifer
|
||||
* @return Grant\AuthCode|Grant\ClientCredentials|Grant\Implict|Grant\Password|Grant\RefreshToken
|
||||
*/
|
||||
public function getGrantType($grantType)
|
||||
{
|
||||
if (isset($this->grantTypes[$grantType])) {
|
||||
return $this->grantTypes[$grantType];
|
||||
}
|
||||
|
||||
throw new Exception\InvalidGrantTypeException(sprintf(self::$exceptionMessages['unsupported_grant_type'], $grantType), 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a parameter from passed input parameters or the Request class
|
||||
* @param string|array $param Required parameter
|
||||
* @param string $method Get/put/post/delete
|
||||
* @param array $inputParams Passed input parameters
|
||||
* @return mixed 'Null' if parameter is missing
|
||||
*/
|
||||
public function getParam($param = '', $method = 'get', $inputParams = array(), $default = null)
|
||||
{
|
||||
if (is_string($param)) {
|
||||
if (isset($inputParams[$param])) {
|
||||
return $inputParams[$param];
|
||||
} elseif ($param === 'client_id' && ! is_null($clientId = $this->getRequest()->server('PHP_AUTH_USER'))) {
|
||||
return $clientId;
|
||||
} elseif ($param === 'client_secret' && ! is_null($clientSecret = $this->getRequest()->server('PHP_AUTH_PW'))) {
|
||||
return $clientSecret;
|
||||
} else {
|
||||
return $this->getRequest()->{$method}($param, $default);
|
||||
}
|
||||
} else {
|
||||
$response = array();
|
||||
foreach ($param as $p) {
|
||||
$response[$p] = $this->getParam($p, $method, $inputParams);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* ClientException Exception
|
||||
*/
|
||||
class ClientException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Insufficient Scope Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InsufficientScope Exception
|
||||
*/
|
||||
class InsufficientScopeException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Access Token Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InvalidAccessToken Exception
|
||||
*/
|
||||
class InvalidAccessTokenException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Grant Type Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* InvalidGrantTypeException Exception
|
||||
*/
|
||||
class InvalidGrantTypeException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Missing Access Token Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* MissingAccessToken Exception
|
||||
*/
|
||||
class MissingAccessTokenException extends OAuth2Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Base Exception
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class OAuth2Exception extends \Exception
|
||||
{
|
||||
|
||||
}
|
@@ -1,259 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Auth code grant class
|
||||
*/
|
||||
class AuthCode implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'authorization_code';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = 'code';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* The TTL of the auth token
|
||||
* @var integer
|
||||
*/
|
||||
protected $authTokenTTL = 600;
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $authTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setAuthTokenTTL($authTokenTTL)
|
||||
{
|
||||
$this->authTokenTTL = $authTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check authorise parameters
|
||||
*
|
||||
* @param array $inputParams Optional array of parsed $_GET keys
|
||||
* @throws \OAuth2\Exception\ClientException
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function checkAuthoriseParams($inputParams = array())
|
||||
{
|
||||
// Auth params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'redirect_uri', 'response_type', 'scope', 'state'), 'get', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['redirect_uri'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'redirect_uri'), 0);
|
||||
}
|
||||
|
||||
if ($this->authServer->stateParamRequired() === true && is_null($authParams['state'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'state'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], null, $authParams['redirect_uri'], $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['response_type'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'response_type'), 0);
|
||||
}
|
||||
|
||||
// Ensure response type is one that is recognised
|
||||
if ( ! in_array($authParams['response_type'], $this->authServer->getResponseTypes())) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('unsupported_response_type'), 3);
|
||||
}
|
||||
|
||||
// Validate scopes
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
return $authParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a new authorise request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authParams The authorise request $_GET parameters
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
public function newAuthoriseRequest($type, $typeId, $authParams = array())
|
||||
{
|
||||
// Generate an auth code
|
||||
$authCode = SecureKey::make();
|
||||
|
||||
// Remove any old sessions the user might have
|
||||
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], $type, $typeId);
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], $type, $typeId);
|
||||
|
||||
// Associate a redirect URI
|
||||
$this->authServer->getStorage('session')->associateRedirectUri($sessionId, $authParams['redirect_uri']);
|
||||
|
||||
// Associate the auth code
|
||||
$authCodeId = $this->authServer->getStorage('session')->associateAuthCode($sessionId, $authCode, time() + $this->authTokenTTL);
|
||||
|
||||
// Associate the scopes to the auth code
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateAuthCodeScope($authCodeId, $scope['id']);
|
||||
}
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the auth code grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'redirect_uri', 'code'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['redirect_uri'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'redirect_uri'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], $authParams['redirect_uri'], $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
// Validate the authorization code
|
||||
if (is_null($authParams['code'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'code'), 0);
|
||||
}
|
||||
|
||||
// Verify the authorization code matches the client_id and the request_uri
|
||||
$authCodeDetails = $this->authServer->getStorage('session')->validateAuthCode($authParams['client_id'], $authParams['redirect_uri'], $authParams['code']);
|
||||
|
||||
if ( ! $authCodeDetails) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_grant'), 'code'), 9);
|
||||
}
|
||||
|
||||
// Get any associated scopes
|
||||
$scopes = $this->authServer->getStorage('session')->getAuthCodeScopes($authCodeDetails['authcode_id']);
|
||||
|
||||
// A session ID was returned so update it with an access token and remove the authorisation code
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Remove the auth code
|
||||
$this->authServer->getStorage('session')->removeAuthCode($authCodeDetails['session_id']);
|
||||
|
||||
// Create an access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($authCodeDetails['session_id'], $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
if (count($scopes) > 0) {
|
||||
foreach ($scopes as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['scope_id']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->authServer->hasGrantType('refresh_token')) {
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL();
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']);
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@@ -1,166 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class
|
||||
*/
|
||||
class ClientCredentials implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'client_credentials';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response type
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseType()
|
||||
{
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $accessTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the client credentials grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf(Authorization::getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf(Authorization::getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException(Authorization::getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scope = $this->authServer->getParam('scope', 'post', $inputParams, '');
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $scope);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'client', $authParams['client_id']);
|
||||
|
||||
// Add the access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the new session
|
||||
foreach ($authParams['scopes'] as $scope)
|
||||
{
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Authorization;
|
||||
|
||||
trait GrantTrait {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param Authorization $authServer Authorization server instance
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Authorization $authServer = null)
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($authServer instanceof Authorization) {
|
||||
trigger_error(
|
||||
'Server is now automatically injected into grant as of v3.1 of this library',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
} // @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier
|
||||
* @param string $identifier
|
||||
* @return self
|
||||
*/
|
||||
public function setIdentifier($identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response type
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseType()
|
||||
{
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default access token expire time
|
||||
* @param int $accessTokenTTL
|
||||
* @return self
|
||||
*/
|
||||
public function setAccessTokenTTL($accessTokenTTL)
|
||||
{
|
||||
$this->accessTokenTTL = $accessTokenTTL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject the authorization server into the grant
|
||||
* @param Authorization $authServer The authorization server instance
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthorizationServer(Authorization $authServer)
|
||||
{
|
||||
$this->authServer = $authServer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Grant type interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
interface GrantTypeInterface
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Authorization $authServer = null);
|
||||
|
||||
/**
|
||||
* Complete the grant flow
|
||||
*
|
||||
* Example response:
|
||||
* <code>
|
||||
* array(
|
||||
* 'access_token' => (string), // The access token
|
||||
* 'refresh_token' => (string), // The refresh token (only set if the refresh token grant is enabled)
|
||||
* 'token_type' => 'bearer', // Almost always "bearer" (exceptions: JWT, SAML)
|
||||
* 'expires' => (int), // The timestamp of when the access token will expire
|
||||
* 'expires_in' => (int) // The number of seconds before the access token will expire
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param null|array $inputParams Null unless the input parameters have been manually set
|
||||
* @return array An array of parameters to be passed back to the client
|
||||
*/
|
||||
public function completeFlow($inputParams = null);
|
||||
}
|
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 implicit grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Client credentials grant class
|
||||
*/
|
||||
class Implicit implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'implicit';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = 'token';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Complete the client credentials grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($authParams = null)
|
||||
{
|
||||
// Remove any old sessions the user might have
|
||||
$this->authServer->getStorage('session')->deleteSession($authParams['client_id'], 'user', $authParams['user_id']);
|
||||
|
||||
// Generate a new access token
|
||||
$accessToken = SecureKey::make();
|
||||
|
||||
// Compute expiry time
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $authParams['user_id']);
|
||||
|
||||
// Create an access token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn,
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@@ -1,189 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Password grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Password grant class
|
||||
*/
|
||||
class Password implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'password';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* Callback to authenticate a user's name and password
|
||||
* @var function
|
||||
*/
|
||||
protected $callback = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Set the callback to verify a user's username and password
|
||||
* @param callable $callback The callback function
|
||||
* @return void
|
||||
*/
|
||||
public function setVerifyCredentialsCallback($callback)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the callback function
|
||||
* @return callable
|
||||
*/
|
||||
protected function getVerifyCredentialsCallback()
|
||||
{
|
||||
if (is_null($this->callback) || ! is_callable($this->callback)) {
|
||||
throw new Exception\InvalidGrantTypeException('Null or non-callable callback set');
|
||||
}
|
||||
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the password grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'username', 'password'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client credentials
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['username'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'username'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['password'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'password'), 0);
|
||||
}
|
||||
|
||||
// Check if user's username and password are correct
|
||||
$userId = call_user_func($this->getVerifyCredentialsCallback(), $authParams['username'], $authParams['password']);
|
||||
|
||||
if ($userId === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_credentials'), 0);
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scope = $this->authServer->getParam('scope', 'post', $inputParams, '');
|
||||
$scopes = explode($this->authServer->getScopeDelimeter(), $scope);
|
||||
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
if ($scopes[$i] === '') unset($scopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
if ($this->authServer->scopeParamRequired() === true && $this->authServer->getDefaultScope() === null && count($scopes) === 0) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
} elseif (count($scopes) === 0 && $this->authServer->getDefaultScope() !== null) {
|
||||
if (is_array($this->authServer->getDefaultScope())) {
|
||||
$scopes = $this->authServer->getDefaultScope();
|
||||
} else {
|
||||
$scopes = array($this->authServer->getDefaultScope());
|
||||
}
|
||||
}
|
||||
|
||||
$authParams['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($scope, $authParams['client_id'], $this->identifier);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_scope'), $scope), 4);
|
||||
}
|
||||
|
||||
$authParams['scopes'][] = $scopeDetails;
|
||||
}
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->authServer->getStorage('session')->createSession($authParams['client_id'], 'user', $userId);
|
||||
|
||||
// Associate an access token with the session
|
||||
$accessTokenId = $this->authServer->getStorage('session')->associateAccessToken($sessionId, $accessToken, $accessTokenExpires);
|
||||
|
||||
// Associate scopes with the access token
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($accessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->authServer->hasGrantType('refresh_token')) {
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenTTL = time() + $this->authServer->getGrantType('refresh_token')->getRefreshTokenTTL();
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($accessTokenId, $refreshToken, $refreshTokenTTL, $authParams['client_id']);
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@@ -1,207 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token grant
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Grant;
|
||||
|
||||
use League\OAuth2\Server\Request;
|
||||
use League\OAuth2\Server\Authorization;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
/**
|
||||
* Referesh token grant
|
||||
*/
|
||||
class RefreshToken implements GrantTypeInterface {
|
||||
|
||||
use GrantTrait;
|
||||
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'refresh_token';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $authServer = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Refresh token TTL
|
||||
* @var integer
|
||||
*/
|
||||
protected $refreshTokenTTL = 604800;
|
||||
|
||||
/**
|
||||
* Rotate refresh tokens
|
||||
* @var boolean
|
||||
*/
|
||||
protected $rotateRefreshTokens = false;
|
||||
|
||||
/**
|
||||
* Set the TTL of the refresh token
|
||||
* @param int $refreshTokenTTL
|
||||
* @return void
|
||||
*/
|
||||
public function setRefreshTokenTTL($refreshTokenTTL)
|
||||
{
|
||||
$this->refreshTokenTTL = $refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TTL of the refresh token
|
||||
* @return int
|
||||
*/
|
||||
public function getRefreshTokenTTL()
|
||||
{
|
||||
return $this->refreshTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a new access is token, expire the refresh token used and issue a new one.
|
||||
* @param boolean $rotateRefreshTokens Set to true to enable (default = false)
|
||||
* @return void
|
||||
*/
|
||||
public function rotateRefreshTokens($rotateRefreshTokens = false)
|
||||
{
|
||||
$this->rotateRefreshTokens = $rotateRefreshTokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the refresh token grant
|
||||
* @param null|array $inputParams
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow($inputParams = null)
|
||||
{
|
||||
// Get the required params
|
||||
$authParams = $this->authServer->getParam(array('client_id', 'client_secret', 'refresh_token', 'scope'), 'post', $inputParams);
|
||||
|
||||
if (is_null($authParams['client_id'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_id'), 0);
|
||||
}
|
||||
|
||||
if (is_null($authParams['client_secret'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'client_secret'), 0);
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$clientDetails = $this->authServer->getStorage('client')->getClient($authParams['client_id'], $authParams['client_secret'], null, $this->identifier);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_client'), 8);
|
||||
}
|
||||
|
||||
$authParams['client_details'] = $clientDetails;
|
||||
|
||||
if (is_null($authParams['refresh_token'])) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'refresh_token'), 0);
|
||||
}
|
||||
|
||||
// Validate refresh token
|
||||
$accessTokenId = $this->authServer->getStorage('session')->validateRefreshToken($authParams['refresh_token'], $authParams['client_id']);
|
||||
|
||||
if ($accessTokenId === false) {
|
||||
throw new Exception\ClientException($this->authServer->getExceptionMessage('invalid_refresh'), 0);
|
||||
}
|
||||
|
||||
// Get the existing access token
|
||||
$accessTokenDetails = $this->authServer->getStorage('session')->getAccessToken($accessTokenId);
|
||||
|
||||
// Get the scopes for the existing access token
|
||||
$scopes = $this->authServer->getStorage('session')->getScopes($accessTokenDetails['access_token']);
|
||||
|
||||
// Generate new tokens and associate them to the session
|
||||
$accessToken = SecureKey::make();
|
||||
$accessTokenExpiresIn = ($this->accessTokenTTL !== null) ? $this->accessTokenTTL : $this->authServer->getAccessTokenTTL();
|
||||
$accessTokenExpires = time() + $accessTokenExpiresIn;
|
||||
|
||||
// Associate the new access token with the session
|
||||
$newAccessTokenId = $this->authServer->getStorage('session')->associateAccessToken($accessTokenDetails['session_id'], $accessToken, $accessTokenExpires);
|
||||
|
||||
if ($this->rotateRefreshTokens === true) {
|
||||
|
||||
// Generate a new refresh token
|
||||
$refreshToken = SecureKey::make();
|
||||
$refreshTokenExpires = time() + $this->getRefreshTokenTTL();
|
||||
|
||||
// Revoke the old refresh token
|
||||
$this->authServer->getStorage('session')->removeRefreshToken($authParams['refresh_token']);
|
||||
|
||||
// Associate the new refresh token with the new access token
|
||||
$this->authServer->getStorage('session')->associateRefreshToken($newAccessTokenId, $refreshToken, $refreshTokenExpires, $authParams['client_id']);
|
||||
}
|
||||
|
||||
// There isn't a request for reduced scopes so assign the original ones (or we're not rotating scopes)
|
||||
if ( ! isset($authParams['scope'])) {
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scope['id']);
|
||||
}
|
||||
|
||||
} elseif ( isset($authParams['scope']) && $this->rotateRefreshTokens === true) {
|
||||
|
||||
// The request is asking for reduced scopes and rotate tokens is enabled
|
||||
$reqestedScopes = explode($this->authServer->getScopeDelimeter(), $authParams['scope']);
|
||||
|
||||
for ($i = 0; $i < count($reqestedScopes); $i++) {
|
||||
$reqestedScopes[$i] = trim($reqestedScopes[$i]);
|
||||
if ($reqestedScopes[$i] === '') unset($reqestedScopes[$i]); // Remove any junk scopes
|
||||
}
|
||||
|
||||
// Check that there aren't any new scopes being included
|
||||
$existingScopes = array();
|
||||
foreach ($scopes as $s) {
|
||||
$existingScopes[] = $s['scope'];
|
||||
}
|
||||
|
||||
foreach ($reqestedScopes as $reqScope) {
|
||||
if ( ! in_array($reqScope, $existingScopes)) {
|
||||
throw new Exception\ClientException(sprintf($this->authServer->getExceptionMessage('invalid_request'), 'scope'), 0);
|
||||
}
|
||||
|
||||
// Associate with the new access token
|
||||
$scopeDetails = $this->authServer->getStorage('scope')->getScope($reqScope, $authParams['client_id'], $this->identifier);
|
||||
$this->authServer->getStorage('session')->associateScope($newAccessTokenId, $scopeDetails['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'Bearer',
|
||||
'expires' => $accessTokenExpires,
|
||||
'expires_in' => $accessTokenExpiresIn
|
||||
);
|
||||
|
||||
if ($this->rotateRefreshTokens === true) {
|
||||
$response['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
@@ -1,395 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @author Woody Gilk <woody@shadowhand.me>
|
||||
* @copyright Copyright (c) 2013-2014 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Util\RequestInterface;
|
||||
use League\OAuth2\Server\Util\Request;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*/
|
||||
class Resource
|
||||
{
|
||||
/**
|
||||
* The access token
|
||||
* @var string
|
||||
*/
|
||||
protected $accessToken = null;
|
||||
|
||||
/**
|
||||
* The session ID
|
||||
* @var string
|
||||
*/
|
||||
protected $sessionId = null;
|
||||
|
||||
/**
|
||||
* The type of the owner of the access token
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerType = null;
|
||||
|
||||
/**
|
||||
* The ID of the owner of the access token
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerId = null;
|
||||
|
||||
/**
|
||||
* The scopes associated with the access token
|
||||
* @var array
|
||||
*/
|
||||
protected $sessionScopes = array();
|
||||
|
||||
/**
|
||||
* The client, scope and session storage classes
|
||||
* @var array
|
||||
*/
|
||||
protected $storages = array();
|
||||
|
||||
/**
|
||||
* The request object
|
||||
* @var Util\RequestInterface
|
||||
*/
|
||||
protected $request = null;
|
||||
|
||||
/**
|
||||
* The query string key which is used by clients to present the access token (default: access_token)
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenKey = 'access_token';
|
||||
|
||||
/**
|
||||
* The client ID
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId = null;
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionCodes = array(
|
||||
0 => 'invalid_request',
|
||||
1 => 'invalid_token',
|
||||
2 => 'insufficient_scope',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error messages
|
||||
* @var array
|
||||
*/
|
||||
protected static $exceptionMessages = array(
|
||||
'invalid_request' => 'The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the "%s" parameter.',
|
||||
'invalid_token' => 'The access token provided is expired, revoked, malformed, or invalid for other reasons.',
|
||||
'insufficient_scope' => 'The request requires higher privileges than provided by the access token. Required scopes are: %s.',
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error HTTP status codes
|
||||
* @var array
|
||||
*
|
||||
* RFC 6750, section 3.1:
|
||||
* When a request fails, the resource server responds using the
|
||||
* appropriate HTTP status code (typically, 400, 401, 403, or 405) and
|
||||
* includes one of the following error codes in the response:
|
||||
*/
|
||||
protected static $exceptionHttpStatusCodes = array(
|
||||
'invalid_request' => 400,
|
||||
'invalid_token' => 401,
|
||||
'insufficient_scope' => 403,
|
||||
);
|
||||
|
||||
/**
|
||||
* Get an exception message
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return string The error message
|
||||
*/
|
||||
public static function getExceptionMessage($error = '')
|
||||
{
|
||||
return self::$exceptionMessages[$error];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an exception code
|
||||
*
|
||||
* @param integer $code The exception code
|
||||
* @return string The exception code type
|
||||
*/
|
||||
public static function getExceptionType($code = 0)
|
||||
{
|
||||
return self::$exceptionCodes[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
*
|
||||
* @param string $error The error message key
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public static function getExceptionHttpHeaders($error)
|
||||
{
|
||||
$headers = array();
|
||||
switch (self::$exceptionHttpStatusCodes[$error]) {
|
||||
case 401:
|
||||
$headers[] = 'HTTP/1.1 401 Unauthorized';
|
||||
break;
|
||||
case 403:
|
||||
$headers[] = 'HTTP/1.1 403 Forbidden';
|
||||
break;
|
||||
case 400:
|
||||
default:
|
||||
$headers[] = 'HTTP/1.1 400 Bad Request';
|
||||
}
|
||||
|
||||
// Add "WWW-Authenticate" header
|
||||
//
|
||||
// RFC 6749, section 5.2.:
|
||||
// "If the client attempted to authenticate via the 'Authorization'
|
||||
// request header field, the authorization server MUST
|
||||
// respond with an HTTP 401 (Unauthorized) status code and
|
||||
// include the "WWW-Authenticate" response header field
|
||||
// matching the authentication scheme used by the client.
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($error === 'insufficient_scope') {
|
||||
$authScheme = null;
|
||||
$request = new Request();
|
||||
if ($request->server('PHP_AUTH_USER') !== null) {
|
||||
$authScheme = 'Basic';
|
||||
} else {
|
||||
$authHeader = $request->header('Authorization');
|
||||
if ($authHeader !== null) {
|
||||
if (strpos($authHeader, 'Bearer') === 0) {
|
||||
$authScheme = 'Bearer';
|
||||
} elseif (strpos($authHeader, 'Basic') === 0) {
|
||||
$authScheme = 'Basic';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($authScheme !== null) {
|
||||
$headers[] = 'WWW-Authenticate: '.$authScheme.' realm=""';
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the Resource
|
||||
*
|
||||
* @param SessionInterface The Session Storage Object
|
||||
*/
|
||||
public function __construct(SessionInterface $session)
|
||||
{
|
||||
$this->storages['session'] = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Request Object
|
||||
*
|
||||
* @param RequestInterface The Request Object
|
||||
*/
|
||||
public function setRequest(RequestInterface $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Request object. It will create one from the globals if one is not set.
|
||||
*
|
||||
* @return Util\RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->request = Request::buildFromGlobals();
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query string key for the access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTokenKey()
|
||||
{
|
||||
return $this->tokenKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query string key for the access token.
|
||||
*
|
||||
* @param $key The new query string key
|
||||
*/
|
||||
public function setTokenKey($key)
|
||||
{
|
||||
$this->tokenKey = $key;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the access token owner ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerId()
|
||||
{
|
||||
return $this->ownerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the owner type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerType()
|
||||
{
|
||||
return $this->ownerType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client ID that created the session
|
||||
* @return string
|
||||
*/
|
||||
public function getClientId()
|
||||
{
|
||||
return $this->clientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the access token is valid or not.
|
||||
*
|
||||
* @param $headersOnly Limit Access Token to Authorization header only
|
||||
* @throws Exception\InvalidAccessTokenException Thrown if the presented access token is not valid
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($headersOnly = false)
|
||||
{
|
||||
$accessToken = $this->determineAccessToken($headersOnly);
|
||||
|
||||
$result = $this->storages['session']->validateAccessToken($accessToken);
|
||||
|
||||
if (! $result) {
|
||||
throw new Exception\InvalidAccessTokenException(self::$exceptionMessages['invalid_token'], 1);
|
||||
}
|
||||
|
||||
$this->accessToken = $accessToken;
|
||||
$this->sessionId = $result['session_id'];
|
||||
$this->clientId = $result['client_id'];
|
||||
$this->ownerType = $result['owner_type'];
|
||||
$this->ownerId = $result['owner_id'];
|
||||
|
||||
$sessionScopes = $this->storages['session']->getScopes($this->accessToken);
|
||||
foreach ($sessionScopes as $scope) {
|
||||
$this->sessionScopes[] = $scope['scope'];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the session scopes
|
||||
* @return array
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
return $this->sessionScopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the presented access token has the given scope(s).
|
||||
*
|
||||
* @param array|string An array of scopes or a single scope as a string
|
||||
* @param bool If scopes are required, missing scope will trigger an exception
|
||||
* @throws Exception\InsufficientScopeException Thrown if the any of the given scopes are not in the session
|
||||
* @return bool Returns bool if all scopes are found, false if any fail
|
||||
*/
|
||||
public function hasScope($scopes, $required = false)
|
||||
{
|
||||
if (!is_array($scopes)) {
|
||||
$scopes = array($scopes);
|
||||
}
|
||||
|
||||
$missing = array_diff($scopes, $this->sessionScopes);
|
||||
|
||||
if ($missing) {
|
||||
if ($required) {
|
||||
$missing = implode(', ', $missing);
|
||||
throw new Exception\InsufficientScopeException(sprintf(self::$exceptionMessages['insufficient_scope'], $missing), 3);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in the access token from the headers.
|
||||
*
|
||||
* @param $headersOnly Limit Access Token to Authorization header only
|
||||
* @throws Exception\MissingAccessTokenException Thrown if there is no access token presented
|
||||
* @return string
|
||||
*/
|
||||
public function determineAccessToken($headersOnly = false)
|
||||
{
|
||||
// Try to get it directly from a header
|
||||
if (! $header = $this->getRequest()->header('Authorization')) {
|
||||
|
||||
// Failing that try getting it from a server variable
|
||||
$header = $this->getRequest()->server('HTTP_AUTHORIZATION');
|
||||
}
|
||||
|
||||
// One of them worked
|
||||
if ($header) {
|
||||
// Check for special case, because cURL sometimes does an
|
||||
// internal second request and doubles the authorization header,
|
||||
// which always resulted in an error.
|
||||
//
|
||||
// 1st request: Authorization: Bearer XXX
|
||||
// 2nd request: Authorization: Bearer XXX, Bearer XXX
|
||||
if (strpos($header, ',') !== false) {
|
||||
$headerPart = explode(',', $header);
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $headerPart[0]));
|
||||
} else {
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header));
|
||||
}
|
||||
$accessToken = ($accessToken === 'Bearer') ? '' : $accessToken;
|
||||
} elseif ($headersOnly === false) {
|
||||
$method = $this->getRequest()->server('REQUEST_METHOD');
|
||||
$accessToken = $this->getRequest()->{$method}($this->tokenKey);
|
||||
}
|
||||
|
||||
if (empty($accessToken)) {
|
||||
throw new Exception\MissingAccessTokenException(self::$exceptionMessages['invalid_request'], 0);
|
||||
}
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
}
|
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface ClientInterface
|
||||
{
|
||||
/**
|
||||
* Validate a client
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* # Client ID + redirect URI
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_client_endpoints.redirect_uri, oauth_clients.name,
|
||||
* oauth_clients.auto_approve
|
||||
* FROM oauth_clients LEFT JOIN oauth_client_endpoints ON oauth_client_endpoints.client_id = oauth_clients.id
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_client_endpoints.redirect_uri = :redirectUri
|
||||
*
|
||||
* # Client ID + client secret
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_clients.name, oauth_clients.auto_approve FROM oauth_clients
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_clients.secret = :clientSecret
|
||||
*
|
||||
* # Client ID + client secret + redirect URI
|
||||
* SELECT oauth_clients.id, oauth_clients.secret, oauth_client_endpoints.redirect_uri, oauth_clients.name,
|
||||
* oauth_clients.auto_approve FROM oauth_clients LEFT JOIN oauth_client_endpoints
|
||||
* ON oauth_client_endpoints.client_id = oauth_clients.id
|
||||
* WHERE oauth_clients.id = :clientId AND oauth_clients.secret = :clientSecret AND
|
||||
* oauth_client_endpoints.redirect_uri = :redirectUri
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [client_id] => (string) The client ID
|
||||
* [client secret] => (string) The client secret
|
||||
* [redirect_uri] => (string) The redirect URI used in this request
|
||||
* [name] => (string) The name of the client
|
||||
* [auto_approve] => (bool) Whether the client should auto approve
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client's ID
|
||||
* @param string $clientSecret The client's secret (default = "null")
|
||||
* @param string $redirectUri The client's redirect URI (default = "null")
|
||||
* @param string $grantType The grant type used in the request (default = "null")
|
||||
* @return bool|array Returns false if the validation fails, array on success
|
||||
*/
|
||||
public function getClient($clientId, $clientSecret = null, $redirectUri = null, $grantType = null);
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Scope storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface ScopeInterface
|
||||
{
|
||||
/**
|
||||
* Return information about a scope
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM oauth_scopes WHERE scope = :scope
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The scope's ID
|
||||
* [scope] => (string) The scope itself
|
||||
* [name] => (string) The scope's name
|
||||
* [description] => (string) The scope's description
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $scope The scope
|
||||
* @param string $clientId The client ID (default = "null")
|
||||
* @param string $grantType The grant type used in the request (default = "null")
|
||||
* @return bool|array If the scope doesn't exist return false
|
||||
*/
|
||||
public function getScope($scope, $clientId = null, $grantType = null);
|
||||
}
|
@@ -1,332 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Session storage interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
interface SessionInterface
|
||||
{
|
||||
/**
|
||||
* Create a new session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_sessions (client_id, owner_type, owner_id)
|
||||
* VALUE (:clientId, :ownerType, :ownerId)
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $ownerType The type of the session owner (e.g. "user")
|
||||
* @param string $ownerId The ID of the session owner (e.g. "123")
|
||||
* @return int The session ID
|
||||
*/
|
||||
public function createSession($clientId, $ownerType, $ownerId);
|
||||
|
||||
/**
|
||||
* Delete a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM oauth_sessions WHERE client_id = :clientId AND owner_type = :type AND owner_id = :typeId
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $ownerType The type of the session owner (e.g. "user")
|
||||
* @param string $ownerId The ID of the session owner (e.g. "123")
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSession($clientId, $ownerType, $ownerId);
|
||||
|
||||
/**
|
||||
* Associate a redirect URI with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_redirects (session_id, redirect_uri) VALUE (:sessionId, :redirectUri)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @return void
|
||||
*/
|
||||
public function associateRedirectUri($sessionId, $redirectUri);
|
||||
|
||||
/**
|
||||
* Associate an access token with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_access_tokens (session_id, access_token, access_token_expires)
|
||||
* VALUE (:sessionId, :accessToken, :accessTokenExpire)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $accessToken The access token
|
||||
* @param int $expireTime Unix timestamp of the access token expiry time
|
||||
* @return int The access token ID
|
||||
*/
|
||||
public function associateAccessToken($sessionId, $accessToken, $expireTime);
|
||||
|
||||
/**
|
||||
* Associate a refresh token with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_refresh_tokens (session_access_token_id, refresh_token, refresh_token_expires,
|
||||
* client_id) VALUE (:accessTokenId, :refreshToken, :expireTime, :clientId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The access token ID
|
||||
* @param string $refreshToken The refresh token
|
||||
* @param int $expireTime Unix timestamp of the refresh token expiry time
|
||||
* @param string $clientId The client ID
|
||||
* @return void
|
||||
*/
|
||||
public function associateRefreshToken($accessTokenId, $refreshToken, $expireTime, $clientId);
|
||||
|
||||
/**
|
||||
* Assocate an authorization code with a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_authcodes (session_id, auth_code, auth_code_expires)
|
||||
* VALUE (:sessionId, :authCode, :authCodeExpires)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $authCode The authorization code
|
||||
* @param int $expireTime Unix timestamp of the access token expiry time
|
||||
* @return int The auth code ID
|
||||
*/
|
||||
public function associateAuthCode($sessionId, $authCode, $expireTime);
|
||||
|
||||
/**
|
||||
* Remove an associated authorization token from a session
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM oauth_session_authcodes WHERE session_id = :sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @return void
|
||||
*/
|
||||
public function removeAuthCode($sessionId);
|
||||
|
||||
/**
|
||||
* Validate an authorization code
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT oauth_sessions.id AS session_id, oauth_session_authcodes.id AS authcode_id FROM oauth_sessions
|
||||
* JOIN oauth_session_authcodes ON oauth_session_authcodes.`session_id` = oauth_sessions.id
|
||||
* JOIN oauth_session_redirects ON oauth_session_redirects.`session_id` = oauth_sessions.id WHERE
|
||||
* oauth_sessions.client_id = :clientId AND oauth_session_authcodes.`auth_code` = :authCode
|
||||
* AND `oauth_session_authcodes`.`auth_code_expires` >= :time AND
|
||||
* `oauth_session_redirects`.`redirect_uri` = :redirectUri
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'session_id' => (int)
|
||||
* 'authcode_id' => (int)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $authCode The authorization code
|
||||
* @return array|bool False if invalid or array as above
|
||||
*/
|
||||
public function validateAuthCode($clientId, $redirectUri, $authCode);
|
||||
|
||||
/**
|
||||
* Validate an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT session_id, oauth_sessions.`client_id`, oauth_sessions.`owner_id`, oauth_sessions.`owner_type`
|
||||
* FROM `oauth_session_access_tokens` JOIN oauth_sessions ON oauth_sessions.`id` = session_id WHERE
|
||||
* access_token = :accessToken AND access_token_expires >= UNIX_TIMESTAMP(NOW())
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'session_id' => (int),
|
||||
* 'client_id' => (string),
|
||||
* 'owner_id' => (string),
|
||||
* 'owner_type' => (string)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array|bool False if invalid or an array as above
|
||||
*/
|
||||
public function validateAccessToken($accessToken);
|
||||
|
||||
/**
|
||||
* Removes a refresh token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* DELETE FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken
|
||||
* </code>
|
||||
*
|
||||
* @param string $refreshToken The refresh token to be removed
|
||||
* @return void
|
||||
*/
|
||||
public function removeRefreshToken($refreshToken);
|
||||
|
||||
/**
|
||||
* Validate a refresh token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT session_access_token_id FROM `oauth_session_refresh_tokens` WHERE refresh_token = :refreshToken
|
||||
* AND refresh_token_expires >= UNIX_TIMESTAMP(NOW()) AND client_id = :clientId
|
||||
* </code>
|
||||
*
|
||||
* @param string $refreshToken The refresh token
|
||||
* @param string $clientId The client ID
|
||||
* @return int|bool The ID of the access token the refresh token is linked to (or false if invalid)
|
||||
*/
|
||||
public function validateRefreshToken($refreshToken, $clientId);
|
||||
|
||||
/**
|
||||
* Get an access token by ID
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM `oauth_session_access_tokens` WHERE `id` = :accessTokenId
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'id' => (int),
|
||||
* 'session_id' => (int),
|
||||
* 'access_token' => (string),
|
||||
* 'access_token_expires' => (int)
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The access token ID
|
||||
* @return array
|
||||
*/
|
||||
public function getAccessToken($accessTokenId);
|
||||
|
||||
/**
|
||||
* Associate scopes with an auth code (bound to the session)
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO `oauth_session_authcode_scopes` (`oauth_session_authcode_id`, `scope_id`) VALUES
|
||||
* (:authCodeId, :scopeId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $authCodeId The auth code ID
|
||||
* @param int $scopeId The scope ID
|
||||
* @return void
|
||||
*/
|
||||
public function associateAuthCodeScope($authCodeId, $scopeId);
|
||||
|
||||
/**
|
||||
* Get the scopes associated with an auth code
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT scope_id FROM `oauth_session_authcode_scopes` WHERE oauth_session_authcode_id = :authCodeId
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* array(
|
||||
* 'scope_id' => (int)
|
||||
* ),
|
||||
* array(
|
||||
* 'scope_id' => (int)
|
||||
* ),
|
||||
* ...
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param int $oauthSessionAuthCodeId The session ID
|
||||
* @return array
|
||||
*/
|
||||
public function getAuthCodeScopes($oauthSessionAuthCodeId);
|
||||
|
||||
/**
|
||||
* Associate a scope with an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO `oauth_session_token_scopes` (`session_access_token_id`, `scope_id`) VALUE (:accessTokenId, :scopeId)
|
||||
* </code>
|
||||
*
|
||||
* @param int $accessTokenId The ID of the access token
|
||||
* @param int $scopeId The ID of the scope
|
||||
* @return void
|
||||
*/
|
||||
public function associateScope($accessTokenId, $scopeId);
|
||||
|
||||
/**
|
||||
* Get all associated access tokens for an access token
|
||||
*
|
||||
* Example SQL query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT oauth_scopes.* FROM oauth_session_token_scopes JOIN oauth_session_access_tokens
|
||||
* ON oauth_session_access_tokens.`id` = `oauth_session_token_scopes`.`session_access_token_id`
|
||||
* JOIN oauth_scopes ON oauth_scopes.id = `oauth_session_token_scopes`.`scope_id`
|
||||
* WHERE access_token = :accessToken
|
||||
* </code>
|
||||
*
|
||||
* Expected response:
|
||||
*
|
||||
* <code>
|
||||
* array (
|
||||
* array(
|
||||
* 'id' => (int),
|
||||
* 'scope' => (string),
|
||||
* 'name' => (string),
|
||||
* 'description' => (string)
|
||||
* ),
|
||||
* ...
|
||||
* ...
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array
|
||||
*/
|
||||
public function getScopes($accessToken);
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key default algorithm
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util\KeyAlgorithm;
|
||||
|
||||
|
||||
class DefaultAlgorithm implements KeyAlgorithmInterface
|
||||
{
|
||||
/**
|
||||
* @param int $len
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function make($len = 40)
|
||||
{
|
||||
// We generate twice as many bytes here because we want to ensure we have
|
||||
// enough after we base64 encode it to get the length we need because we
|
||||
// take out the "/", "+", and "=" characters.
|
||||
$bytes = openssl_random_pseudo_bytes($len * 2, $strong);
|
||||
|
||||
// We want to stop execution if the key fails because, well, that is bad.
|
||||
if ($bytes === false || $strong === false) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Exception('Error Generating Key');
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return substr(str_replace(array('/', '+', '='), '', base64_encode($bytes)), 0, $len);
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Key algorithm interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util\KeyAlgorithm;
|
||||
|
||||
|
||||
interface KeyAlgorithmInterface
|
||||
{
|
||||
public function make($len = 40);
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Redirect URI generator
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
/**
|
||||
* RedirectUri class
|
||||
*/
|
||||
class RedirectUri
|
||||
{
|
||||
/**
|
||||
* Generate a new redirect uri
|
||||
* @param string $uri The base URI
|
||||
* @param array $params The query string parameters
|
||||
* @param string $queryDelimeter The query string delimeter (default: "?")
|
||||
* @return string The updated URI
|
||||
*/
|
||||
public static function make($uri, $params = array(), $queryDelimeter = '?')
|
||||
{
|
||||
$uri .= (strstr($uri, $queryDelimeter) === false) ? $queryDelimeter : '&';
|
||||
return $uri.http_build_query($params);
|
||||
}
|
||||
}
|
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Request class
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
use OutOfBoundsException;
|
||||
use InvalidMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
protected $get = array();
|
||||
protected $post = array();
|
||||
protected $cookies = array();
|
||||
protected $files = array();
|
||||
protected $server = array();
|
||||
protected $headers = array();
|
||||
|
||||
public static function buildFromGlobals()
|
||||
{
|
||||
return new static($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
|
||||
}
|
||||
|
||||
public function __construct(array $get = array(), array $post = array(), array $cookies = array(), array $files = array(), array $server = array(), $headers = array())
|
||||
{
|
||||
$this->get = $get;
|
||||
$this->post = $post;
|
||||
$this->cookies = $cookies;
|
||||
$this->files = $files;
|
||||
$this->server = $server;
|
||||
|
||||
if (empty($headers)) {
|
||||
$this->headers = $this->readHeaders();
|
||||
} else {
|
||||
$this->headers = $this->normalizeHeaders($headers);
|
||||
}
|
||||
}
|
||||
|
||||
public function get($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('get', $index, $default);
|
||||
}
|
||||
|
||||
public function post($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('post', $index, $default);
|
||||
}
|
||||
|
||||
public function file($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('files', $index, $default);
|
||||
}
|
||||
|
||||
public function cookie($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('cookies', $index, $default);
|
||||
}
|
||||
|
||||
public function server($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('server', $index, $default);
|
||||
}
|
||||
|
||||
public function header($index = null, $default = null)
|
||||
{
|
||||
return $this->getPropertyValue('headers', $index, $default);
|
||||
}
|
||||
|
||||
protected function readHeaders()
|
||||
{
|
||||
if (function_exists('getallheaders')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$headers = getallheaders();
|
||||
} else {
|
||||
// @codeCoverageIgnoreEnd
|
||||
$headers = array();
|
||||
foreach ($this->server() as $name => $value) {
|
||||
if (substr($name, 0, 5) == 'HTTP_') {
|
||||
$name = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
|
||||
$headers[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->normalizeHeaders($headers);
|
||||
}
|
||||
|
||||
protected function getPropertyValue($property, $index = null, $default = null)
|
||||
{
|
||||
if ( ! isset($this->{$property})) {
|
||||
throw new InvalidArgumentException("Property '$property' does not exist.");
|
||||
}
|
||||
if (is_null($index)) {
|
||||
return $this->{$property};
|
||||
}
|
||||
|
||||
if ( ! array_key_exists($index, $this->{$property})) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return $this->{$property}[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes all of the headers and normalizes them in a canonical form.
|
||||
*
|
||||
* @param array $headers The request headers.
|
||||
* @return array An arry of headers with the header name normalized
|
||||
*/
|
||||
protected function normalizeHeaders(array $headers)
|
||||
{
|
||||
$normalized = array();
|
||||
foreach ($headers as $key => $value) {
|
||||
$normalized[ucfirst($this->normalizeKey($key))] = $value;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform header name into canonical form
|
||||
*
|
||||
* Taken from the Slim codebase...
|
||||
*
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function normalizeKey($key)
|
||||
{
|
||||
$key = strtolower($key);
|
||||
$key = str_replace(array('-', '_'), ' ', $key);
|
||||
$key = preg_replace('#^http #', '', $key);
|
||||
$key = ucwords($key);
|
||||
$key = str_replace(' ', '-', $key);
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Request class interface
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
interface RequestInterface
|
||||
{
|
||||
|
||||
public function get($index = null);
|
||||
|
||||
public function post($index = null);
|
||||
|
||||
public function cookie($index = null);
|
||||
|
||||
public function file($index = null);
|
||||
|
||||
public function server($index = null);
|
||||
|
||||
public function header($index = null);
|
||||
|
||||
}
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key generator
|
||||
*
|
||||
* @package php-loep/oauth2-server
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) 2013 PHP League of Extraordinary Packages
|
||||
* @license http://mit-license.org/
|
||||
* @link http://github.com/php-loep/oauth2-server
|
||||
*/
|
||||
|
||||
namespace League\OAuth2\Server\Util;
|
||||
|
||||
use League\OAuth2\Server\Util\KeyAlgorithm\DefaultAlgorithm;
|
||||
use League\OAuth2\Server\Util\KeyAlgorithm\KeyAlgorithmInterface;
|
||||
|
||||
/**
|
||||
* SecureKey class
|
||||
*/
|
||||
class SecureKey
|
||||
{
|
||||
protected static $algorithm;
|
||||
|
||||
/**
|
||||
* Generate a new unique code
|
||||
* @param integer $len Length of the generated code
|
||||
* @return string
|
||||
*/
|
||||
public static function make($len = 40)
|
||||
{
|
||||
return self::getAlgorithm()->make($len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param KeyAlgorithmInterface $algorithm
|
||||
*/
|
||||
public static function setAlgorithm(KeyAlgorithmInterface $algorithm)
|
||||
{
|
||||
self::$algorithm = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return KeyAlgorithmInterface
|
||||
*/
|
||||
public static function getAlgorithm()
|
||||
{
|
||||
if (!self::$algorithm) {
|
||||
|
||||
self::$algorithm = new DefaultAlgorithm();
|
||||
}
|
||||
|
||||
return self::$algorithm;
|
||||
}
|
||||
}
|
51
src/Middleware/AuthenticationServerMiddleware.php
Normal file
51
src/Middleware/AuthenticationServerMiddleware.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Middleware;
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class AuthenticationServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* AuthenticationServerMiddleware constructor.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Server $server
|
||||
*/
|
||||
public function __construct(Server $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* @param callable $next
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
|
||||
{
|
||||
try {
|
||||
$response = $this->server->respondToRequest($request, $response);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// Pass the request and response on to the next responder in the chain
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
51
src/Middleware/ResourceServerMiddleware.php
Normal file
51
src/Middleware/ResourceServerMiddleware.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Middleware;
|
||||
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Server;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class ResourceServerMiddleware
|
||||
{
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Server
|
||||
*/
|
||||
private $server;
|
||||
|
||||
/**
|
||||
* ResourceServerMiddleware constructor.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Server $server
|
||||
*/
|
||||
public function __construct(Server $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
* @param \Psr\Http\Message\ResponseInterface $response
|
||||
* @param callable $next
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next)
|
||||
{
|
||||
try {
|
||||
$request = $this->server->validateAuthenticatedRequest($request);
|
||||
} catch (OAuthServerException $exception) {
|
||||
return $exception->generateHttpResponse($response);
|
||||
// @codeCoverageIgnoreStart
|
||||
} catch (\Exception $exception) {
|
||||
$response->getBody()->write($exception->getMessage());
|
||||
|
||||
return $response->withStatus(500);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
// Pass the request and response on to the next responder in the chain
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
42
src/Repositories/AccessTokenRepositoryInterface.php
Normal file
42
src/Repositories/AccessTokenRepositoryInterface.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Access token storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
|
||||
/**
|
||||
* Access token interface.
|
||||
*/
|
||||
interface AccessTokenRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Persists a new access token to permanent storage.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessTokenEntity
|
||||
*/
|
||||
public function persistNewAccessToken(AccessTokenEntityInterface $accessTokenEntity);
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeAccessToken($tokenId);
|
||||
|
||||
/**
|
||||
* Check if the access token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isAccessTokenRevoked($tokenId);
|
||||
}
|
42
src/Repositories/AuthCodeRepositoryInterface.php
Normal file
42
src/Repositories/AuthCodeRepositoryInterface.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface;
|
||||
|
||||
/**
|
||||
* Auth code storage interface.
|
||||
*/
|
||||
interface AuthCodeRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Persists a new auth code to permanent storage.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AuthCodeEntityInterface $authCodeEntity
|
||||
*/
|
||||
public function persistNewAuthCode(AuthCodeEntityInterface $authCodeEntity);
|
||||
|
||||
/**
|
||||
* Revoke an auth code.
|
||||
*
|
||||
* @param string $codeId
|
||||
*/
|
||||
public function revokeAuthCode($codeId);
|
||||
|
||||
/**
|
||||
* Check if the auth code has been revoked.
|
||||
*
|
||||
* @param string $codeId
|
||||
*
|
||||
* @return bool Return true if this code has been revoked
|
||||
*/
|
||||
public function isAuthCodeRevoked($codeId);
|
||||
}
|
28
src/Repositories/ClientRepositoryInterface.php
Normal file
28
src/Repositories/ClientRepositoryInterface.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
/**
|
||||
* Client storage interface.
|
||||
*/
|
||||
interface ClientRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get a client.
|
||||
*
|
||||
* @param string $clientIdentifier The client's identifier
|
||||
* @param string $grantType The grant type used
|
||||
* @param null|string $clientSecret The client's secret (if sent)
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface
|
||||
*/
|
||||
public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null);
|
||||
}
|
36
src/Repositories/MacTokenInterface.php
Normal file
36
src/Repositories/MacTokenInterface.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 MAC Token Interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Storage;
|
||||
|
||||
use League\OAuth2\Server\Repositories\RepositoryInterface;
|
||||
|
||||
/**
|
||||
* MacTokenInterface.
|
||||
*/
|
||||
interface MacTokenInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a MAC key linked to an access token.
|
||||
*
|
||||
* @param string $macKey
|
||||
* @param string $accessToken
|
||||
*/
|
||||
public function persistMacTokenEntity($macKey, $accessToken);
|
||||
|
||||
/**
|
||||
* Get a MAC key by access token.
|
||||
*
|
||||
* @param string $accessToken
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMacKeyByAccessTokenString($accessToken);
|
||||
}
|
42
src/Repositories/RefreshTokenRepositoryInterface.php
Normal file
42
src/Repositories/RefreshTokenRepositoryInterface.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
|
||||
/**
|
||||
* Refresh token interface.
|
||||
*/
|
||||
interface RefreshTokenRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new refresh token_name.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshTokenEntity
|
||||
*/
|
||||
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntity);
|
||||
|
||||
/**
|
||||
* Revoke the refresh token.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*/
|
||||
public function revokeRefreshToken($tokenId);
|
||||
|
||||
/**
|
||||
* Check if the refresh token has been revoked.
|
||||
*
|
||||
* @param string $tokenId
|
||||
*
|
||||
* @return bool Return true if this token has been revoked
|
||||
*/
|
||||
public function isRefreshTokenRevoked($tokenId);
|
||||
}
|
18
src/Repositories/RepositoryInterface.php
Normal file
18
src/Repositories/RepositoryInterface.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Repository interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
/**
|
||||
* Repository interface.
|
||||
*/
|
||||
interface RepositoryInterface
|
||||
{
|
||||
}
|
47
src/Repositories/ScopeRepositoryInterface.php
Normal file
47
src/Repositories/ScopeRepositoryInterface.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Scope storage interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface;
|
||||
|
||||
/**
|
||||
* Scope interface.
|
||||
*/
|
||||
interface ScopeRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return information about a scope.
|
||||
*
|
||||
* @param string $identifier The scope identifier
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface
|
||||
*/
|
||||
public function getScopeEntityByIdentifier($identifier);
|
||||
|
||||
/**
|
||||
* Given a client, grant type and optional user identifier validate the set of scopes requested are valid and optionally
|
||||
* append additional scopes or remove requested scopes.
|
||||
*
|
||||
* @param ScopeEntityInterface[] $scopes
|
||||
* @param string $grantType
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity
|
||||
* @param null|string $userIdentifier
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\ScopeEntityInterface[]
|
||||
*/
|
||||
public function finalizeScopes(
|
||||
array $scopes,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity,
|
||||
$userIdentifier = null
|
||||
);
|
||||
}
|
25
src/Repositories/UserRepositoryInterface.php
Normal file
25
src/Repositories/UserRepositoryInterface.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\Repositories;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface;
|
||||
|
||||
interface UserRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get a user entity.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $grantType The grant type used
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\ClientEntityInterface $clientEntity
|
||||
*
|
||||
* @return \League\OAuth2\Server\Entities\Interfaces\UserEntityInterface
|
||||
*/
|
||||
public function getUserEntityByUserCredentials(
|
||||
$username,
|
||||
$password,
|
||||
$grantType,
|
||||
ClientEntityInterface $clientEntity
|
||||
);
|
||||
}
|
34
src/RequestEvent.php
Normal file
34
src/RequestEvent.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use League\Event\Event;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class RequestEvent extends Event
|
||||
{
|
||||
/**
|
||||
* @var \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* RequestEvent constructor.
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*/
|
||||
public function __construct($name, ServerRequestInterface $request)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ServerRequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
60
src/ResponseTypes/AbstractResponseType.php
Normal file
60
src/ResponseTypes/AbstractResponseType.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract Response Type.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use League\OAuth2\Server\CryptTrait;
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
|
||||
abstract class AbstractResponseType implements ResponseTypeInterface
|
||||
{
|
||||
use CryptTrait;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface
|
||||
*/
|
||||
protected $refreshToken;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
|
||||
*/
|
||||
protected $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
*/
|
||||
public function __construct(AccessTokenRepositoryInterface $accessTokenRepository)
|
||||
{
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setRefreshToken(RefreshTokenEntityInterface $refreshToken)
|
||||
{
|
||||
$this->refreshToken = $refreshToken;
|
||||
}
|
||||
}
|
60
src/ResponseTypes/BearerTokenResponse.php
Normal file
60
src/ResponseTypes/BearerTokenResponse.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Bearer Token Type.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class BearerTokenResponse extends AbstractResponseType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response)
|
||||
{
|
||||
$expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp();
|
||||
|
||||
$jwtAccessToken = $this->accessToken->convertToJWT($this->privateKeyPath);
|
||||
|
||||
$responseParams = [
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => $expireDateTime - (new \DateTime())->getTimestamp(),
|
||||
'access_token' => (string) $jwtAccessToken,
|
||||
];
|
||||
|
||||
if ($this->refreshToken instanceof RefreshTokenEntityInterface) {
|
||||
$refreshToken = $this->encrypt(
|
||||
json_encode(
|
||||
[
|
||||
'client_id' => $this->accessToken->getClient()->getIdentifier(),
|
||||
'refresh_token_id' => $this->refreshToken->getIdentifier(),
|
||||
'access_token_id' => $this->accessToken->getIdentifier(),
|
||||
'scopes' => $this->accessToken->getScopes(),
|
||||
'user_id' => $this->accessToken->getUserIdentifier(),
|
||||
'expire_time' => $expireDateTime,
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
$responseParams['refresh_token'] = $refreshToken;
|
||||
}
|
||||
|
||||
$response = $response
|
||||
->withStatus(200)
|
||||
->withHeader('pragma', 'no-cache')
|
||||
->withHeader('cache-control', 'no-store')
|
||||
->withHeader('content-type', 'application/json; charset=UTF-8');
|
||||
|
||||
$response->getBody()->write(json_encode($responseParams));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
66
src/ResponseTypes/HtmlResponse.php
Normal file
66
src/ResponseTypes/HtmlResponse.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class HtmlResponse extends AbstractResponseType
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $html = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $statusCode = 200;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $headers = [];
|
||||
|
||||
/**
|
||||
* @param string $html
|
||||
*/
|
||||
public function setHtml($html)
|
||||
{
|
||||
$this->html = $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $statusCode
|
||||
*/
|
||||
public function setStatusCode($statusCode = 200)
|
||||
{
|
||||
$this->statusCode = $statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response)
|
||||
{
|
||||
$response->getBody()->write($this->html);
|
||||
|
||||
foreach ($this->headers as $key => $value) {
|
||||
$response = $response->withHeader($key, $value);
|
||||
}
|
||||
|
||||
return $response
|
||||
->withStatus($this->statusCode)
|
||||
->withHeader('content-type', 'text/html');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
public function setHeader($key, $value)
|
||||
{
|
||||
$this->headers[$key] = $value;
|
||||
}
|
||||
}
|
31
src/ResponseTypes/RedirectResponse.php
Normal file
31
src/ResponseTypes/RedirectResponse.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class RedirectResponse extends AbstractResponseType
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $redirectUri;
|
||||
|
||||
/**
|
||||
* @param string $redirectUri
|
||||
*/
|
||||
public function setRedirectUri($redirectUri)
|
||||
{
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response)
|
||||
{
|
||||
return $response->withStatus(302)->withHeader('location', $this->redirectUri);
|
||||
}
|
||||
}
|
35
src/ResponseTypes/ResponseTypeInterface.php
Normal file
35
src/ResponseTypes/ResponseTypeInterface.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Response Type Interface.
|
||||
*
|
||||
* @author Alex Bilbie <hello@alexbilbie.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\ResponseTypes;
|
||||
|
||||
use League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface;
|
||||
use League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface ResponseTypeInterface
|
||||
{
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\AccessTokenEntityInterface $accessToken
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntityInterface $accessToken);
|
||||
|
||||
/**
|
||||
* @param \League\OAuth2\Server\Entities\Interfaces\RefreshTokenEntityInterface $refreshToken
|
||||
*/
|
||||
public function setRefreshToken(RefreshTokenEntityInterface $refreshToken);
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function generateHttpResponse(ResponseInterface $response);
|
||||
}
|
194
src/Server.php
Normal file
194
src/Server.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace League\OAuth2\Server;
|
||||
|
||||
use DateInterval;
|
||||
use League\Event\EmitterAwareInterface;
|
||||
use League\Event\EmitterAwareTrait;
|
||||
use League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface;
|
||||
use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator;
|
||||
use League\OAuth2\Server\Exception\OAuthServerException;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ClientRepositoryInterface;
|
||||
use League\OAuth2\Server\Repositories\ScopeRepositoryInterface;
|
||||
use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
|
||||
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
class Server implements EmitterAwareInterface
|
||||
{
|
||||
use EmitterAwareTrait;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Grant\GrantTypeInterface[]
|
||||
*/
|
||||
protected $enabledGrantTypes = [];
|
||||
|
||||
/**
|
||||
* @var \DateInterval[]
|
||||
*/
|
||||
protected $grantTypeAccessTokenTTL = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $privateKeyPath;
|
||||
|
||||
/**
|
||||
* @var ResponseTypeInterface
|
||||
*/
|
||||
protected $responseType;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $publicKeyPath;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\ClientRepositoryInterface
|
||||
*/
|
||||
private $clientRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface
|
||||
*/
|
||||
private $accessTokenRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\Repositories\ScopeRepositoryInterface
|
||||
*/
|
||||
private $scopeRepository;
|
||||
|
||||
/**
|
||||
* @var \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface
|
||||
*/
|
||||
private $authorizationValidator;
|
||||
|
||||
/**
|
||||
* New server instance.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Repositories\ClientRepositoryInterface $clientRepository
|
||||
* @param \League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface $accessTokenRepository
|
||||
* @param \League\OAuth2\Server\Repositories\ScopeRepositoryInterface $scopeRepository
|
||||
* @param string $privateKeyPath
|
||||
* @param string $publicKeyPath
|
||||
* @param null|\League\OAuth2\Server\ResponseTypes\ResponseTypeInterface $responseType
|
||||
* @param null|\League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface $authorizationValidator
|
||||
*/
|
||||
public function __construct(
|
||||
ClientRepositoryInterface $clientRepository,
|
||||
AccessTokenRepositoryInterface $accessTokenRepository,
|
||||
ScopeRepositoryInterface $scopeRepository,
|
||||
$privateKeyPath,
|
||||
$publicKeyPath,
|
||||
ResponseTypeInterface $responseType = null,
|
||||
AuthorizationValidatorInterface $authorizationValidator = null
|
||||
) {
|
||||
$this->clientRepository = $clientRepository;
|
||||
$this->accessTokenRepository = $accessTokenRepository;
|
||||
$this->scopeRepository = $scopeRepository;
|
||||
$this->privateKeyPath = $privateKeyPath;
|
||||
$this->publicKeyPath = $publicKeyPath;
|
||||
$this->responseType = $responseType;
|
||||
$this->authorizationValidator = $authorizationValidator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a grant type on the server.
|
||||
*
|
||||
* @param \League\OAuth2\Server\Grant\GrantTypeInterface $grantType
|
||||
* @param \DateInterval $accessTokenTTL
|
||||
*/
|
||||
public function enableGrantType(GrantTypeInterface $grantType, DateInterval $accessTokenTTL)
|
||||
{
|
||||
$grantType->setAccessTokenRepository($this->accessTokenRepository);
|
||||
$grantType->setClientRepository($this->clientRepository);
|
||||
$grantType->setScopeRepository($this->scopeRepository);
|
||||
$grantType->setPrivateKeyPath($this->privateKeyPath);
|
||||
$grantType->setPublicKeyPath($this->publicKeyPath);
|
||||
$grantType->setEmitter($this->getEmitter());
|
||||
|
||||
$this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
|
||||
|
||||
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an access token response.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface|null $request
|
||||
* @param \Psr\Http\Message\ResponseInterface|null $response
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function respondToRequest(ServerRequestInterface $request, ResponseInterface $response)
|
||||
{
|
||||
$tokenResponse = null;
|
||||
while ($tokenResponse === null && $grantType = array_shift($this->enabledGrantTypes)) {
|
||||
/** @var \League\OAuth2\Server\Grant\GrantTypeInterface $grantType */
|
||||
if ($grantType->canRespondToRequest($request)) {
|
||||
$tokenResponse = $grantType->respondToRequest(
|
||||
$request,
|
||||
$this->getResponseType(),
|
||||
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($tokenResponse instanceof ResponseTypeInterface) {
|
||||
return $tokenResponse->generateHttpResponse($response);
|
||||
}
|
||||
|
||||
throw OAuthServerException::unsupportedGrantType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token validity.
|
||||
*
|
||||
* @param \Psr\Http\Message\ServerRequestInterface $request
|
||||
*
|
||||
* @throws \League\OAuth2\Server\Exception\OAuthServerException
|
||||
*
|
||||
* @return \Psr\Http\Message\ServerRequestInterface
|
||||
*/
|
||||
public function validateAuthenticatedRequest(ServerRequestInterface $request)
|
||||
{
|
||||
return $this->getAuthorizationValidator()->validateAuthorization($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token type that grants will return in the HTTP response.
|
||||
*
|
||||
* @return ResponseTypeInterface
|
||||
*/
|
||||
protected function getResponseType()
|
||||
{
|
||||
if (!$this->responseType instanceof ResponseTypeInterface) {
|
||||
$this->responseType = new BearerTokenResponse($this->accessTokenRepository);
|
||||
}
|
||||
|
||||
$this->responseType->setPublicKeyPath($this->publicKeyPath);
|
||||
$this->responseType->setPrivateKeyPath($this->privateKeyPath);
|
||||
|
||||
return $this->responseType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \League\OAuth2\Server\AuthorizationValidators\AuthorizationValidatorInterface
|
||||
*/
|
||||
protected function getAuthorizationValidator()
|
||||
{
|
||||
if (!$this->authorizationValidator instanceof AuthorizationValidatorInterface) {
|
||||
$this->authorizationValidator = new BearerTokenValidator($this->accessTokenRepository);
|
||||
}
|
||||
|
||||
$this->authorizationValidator->setPublicKeyPath($this->publicKeyPath);
|
||||
$this->authorizationValidator->setPrivateKeyPath($this->privateKeyPath);
|
||||
|
||||
return $this->authorizationValidator;
|
||||
}
|
||||
}
|
70
src/TemplateRenderer/AbstractRenderer.php
Normal file
70
src/TemplateRenderer/AbstractRenderer.php
Normal file
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Base template renderer.
|
||||
*
|
||||
* @author Julián Gutiérrez <juliangut@gmail.com>
|
||||
* @copyright Copyright (c) Alex Bilbie
|
||||
* @license http://mit-license.org/
|
||||
*
|
||||
* @link https://github.com/thephpleague/oauth2-server
|
||||
*/
|
||||
namespace League\OAuth2\Server\TemplateRenderer;
|
||||
|
||||
abstract class AbstractRenderer implements RendererInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $loginTemplate;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $authorizeTemplate;
|
||||
|
||||
/**
|
||||
* PlatesRenderer constructor.
|
||||
*
|
||||
* @param string $loginTemplate
|
||||
* @param string $authorizeTemplate
|
||||
*/
|
||||
public function __construct($loginTemplate, $authorizeTemplate)
|
||||
{
|
||||
$this->loginTemplate = $loginTemplate;
|
||||
$this->authorizeTemplate = $authorizeTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render login template.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renderLogin(array $data = [])
|
||||
{
|
||||
return $this->render($this->loginTemplate, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render authorize template.
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function renderAuthorize(array $data = [])
|
||||
{
|
||||
return $this->render($this->authorizeTemplate, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render template.
|
||||
*
|
||||
* @param string $template
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function render($template, array $data = []);
|
||||
}
|
35
src/TemplateRenderer/DefaultTemplates/authorize_client.php
Normal file
35
src/TemplateRenderer/DefaultTemplates/authorize_client.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Authorize <?=$this->e($client->getName())?></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Authorize <?=$this->e($client->getName())?>
|
||||
</h1>
|
||||
|
||||
<p>
|
||||
Do you want to authorize <?=$this->e($client->getName())?> to access the following data?
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<?php foreach ($scopes as $scope): ?>
|
||||
<li><?=$scope->getIdentifier()?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<form method="POST">
|
||||
<input type="hidden" value="approve" name="action">
|
||||
<button type="submit">Approve</button>
|
||||
</form>
|
||||
|
||||
<form method="POST">
|
||||
<input type="hidden" value="deny" name="action">
|
||||
<button type="submit">Deny</button>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user