mirror of
https://github.com/elyby/oauth2-server.git
synced 2025-05-31 14:12:07 +05:30
Compare commits
973 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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 | ||
|
4362f17fd6 | ||
|
6d81c1e57e | ||
|
1a88d3f4c5 | ||
|
0a3215be8e | ||
|
954f29f879 | ||
|
4480aa3456 | ||
|
44db2b295f | ||
|
33f4f5b7ab | ||
|
e61782975a | ||
|
d7c1c50269 | ||
|
f2b5967f10 | ||
|
92779ad078 | ||
|
83c7dea1cc | ||
|
4486b7120f | ||
|
687e794ce3 | ||
|
c7dfc42d57 | ||
|
33c68a2103 | ||
|
92639fbbd6 | ||
|
9af1d2a201 | ||
|
f24d1be3e9 | ||
|
80802e5df4 | ||
|
6aa52adb3e | ||
|
cd767c07fa | ||
|
0b1edadaa7 | ||
|
c1269a97d6 | ||
|
5e4cd98706 | ||
|
4ebf3f838f | ||
|
11c4c93398 | ||
|
cf32b5dd1b | ||
|
8e164f4b99 | ||
|
400d4d8f1e | ||
|
5ffbe6ac37 | ||
|
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 | ||
|
ba5f2840fb | ||
|
e8aeaf0777 | ||
|
fcc1388aeb | ||
|
d7ddfe6452 | ||
|
785d3bd21f | ||
|
5893ba4e8e | ||
|
b2c07aa68f | ||
|
ac29fc4a62 | ||
|
f78bb954d0 | ||
|
29b0389a75 | ||
|
2aa318cfd7 | ||
|
82f7c7abaf | ||
|
2d90540531 | ||
|
de681b1ebf | ||
|
b5217271b0 | ||
|
cc1e78e1ff | ||
|
b12a1d84df | ||
|
901aab9deb | ||
|
9ac56ad547 | ||
|
c60b29d201 | ||
|
2a524efff5 | ||
|
c8c69829f0 | ||
|
22794d49d1 | ||
|
4e37d9bb61 | ||
|
af06f9f3ea | ||
|
aef86227da | ||
|
54ffa58e7b | ||
|
5f7c14789b | ||
|
0bc16c04d9 | ||
|
8a2922697f | ||
|
1045c70bac | ||
|
3c9fd6be27 | ||
|
f83a9a7fa4 | ||
|
d10cc5040d | ||
|
d314c1efd9 | ||
|
468acbc369 | ||
|
013b1b53b4 | ||
|
5254c9d225 | ||
|
e07e0dba78 | ||
|
8556f616d3 | ||
|
064d4d967c | ||
|
a85feb1a32 | ||
|
8e7a975f1a | ||
|
5829781b38 | ||
|
895a379ed3 | ||
|
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 | ||
|
25332be3d1 | ||
|
13b15dfa3a | ||
|
7c1b913e49 | ||
|
9e5bd4cd67 | ||
|
427ae50704 | ||
|
449ba5005c | ||
|
b86d1f1406 | ||
|
f563a59ce8 | ||
|
324a3f0cdc | ||
|
f07d169336 | ||
|
227707c5dc | ||
|
6d7887dc36 | ||
|
5870368e33 | ||
|
9b9cf79f39 | ||
|
619d755008 | ||
|
2adefdf4c8 | ||
|
b5854215a7 | ||
|
302026d437 | ||
|
8d17049877 | ||
|
1f523c3a08 | ||
|
924066166c | ||
|
0dcda992c7 | ||
|
70aafb7521 | ||
|
f59213499c | ||
|
d9917a57e1 | ||
|
dba976d6ac | ||
|
8fe3ed7eb5 | ||
|
9099173db2 | ||
|
c6ac1de26b | ||
|
e55ca5bc05 | ||
|
4febb90210 | ||
|
75482c9e20 | ||
|
0db8850e81 | ||
|
9a224bd847 | ||
|
0c36045913 | ||
|
262ce23fb9 | ||
|
1419ba8cdc | ||
|
b55b73c1e8 | ||
|
e95ae977cc | ||
|
572e6935a6 | ||
|
dd88426323 | ||
|
14683bc65e | ||
|
1d3bc85423 | ||
|
10a4bf41ed | ||
|
041104e2b1 | ||
|
031cf3064a | ||
|
954ff19823 | ||
|
5bb1359ad7 | ||
|
2bd61f040b | ||
|
bacc9ce316 | ||
|
5ec2c24b5c | ||
|
ec9a08af63 | ||
|
6cade987a2 | ||
|
44408b873f | ||
|
b4bfa69c88 | ||
|
9c3c70a5fb | ||
|
556e9cc9ab | ||
|
d3158a830b | ||
|
4a71c376b8 | ||
|
ed427cba37 | ||
|
a358835522 | ||
|
23627c659e | ||
|
bee71c1e83 | ||
|
ad97273455 | ||
|
0b55dc4c01 | ||
|
4985770d07 | ||
|
a2bf4e0dfb | ||
|
cfbb037e07 | ||
|
6c28fea213 | ||
|
e5dc3001c4 | ||
|
69531c3eb5 | ||
|
89f3446b98 | ||
|
69710a5909 | ||
|
85353c5844 | ||
|
879d98abfb | ||
|
f612e105bd | ||
|
56f63bb4c0 | ||
|
8a42bc796f | ||
|
8fa7b303fa | ||
|
55b86e26ad | ||
|
e1f09db6af | ||
|
1e28faabb9 | ||
|
9a3a91760a | ||
|
78d65e102a | ||
|
701010b129 | ||
|
84afff9ad2 | ||
|
cfc61147e1 | ||
|
66ddba808f | ||
|
6324a97118 | ||
|
4170f4e841 | ||
|
5c21370691 | ||
|
c176c1cddc | ||
|
71b6f2c2bc | ||
|
f1567df802 | ||
|
307964d571 | ||
|
a1ca904255 | ||
|
6e045afa26 | ||
|
8f15158d1c | ||
|
ca4e749986 | ||
|
cc0ab4905a | ||
|
e5a48c929b | ||
|
829cef936a | ||
|
f78e05cb08 | ||
|
0999bf4de3 | ||
|
e442253e26 | ||
|
4c4155fdac | ||
|
d901e90602 | ||
|
32a7ed38a9 | ||
|
9dec6c4bfe | ||
|
bcfb9ec475 | ||
|
98be9ab252 | ||
|
e0f4ccb775 | ||
|
dca0898c2f | ||
|
7da9e1a9d7 | ||
|
a4a8f6e661 | ||
|
a9ecca92fc | ||
|
47c24e3181 | ||
|
4d36ebd3e7 | ||
|
0b3a9dc888 | ||
|
1fcdbf45b2 | ||
|
94a064e2f4 | ||
|
92b6ce3335 | ||
|
ee9549287e | ||
|
4b3e0bf668 | ||
|
05d4b68586 | ||
|
ec9c39c108 | ||
|
5d0b295a82 | ||
|
9ec5442f90 | ||
|
4112913813 | ||
|
5eb4227709 | ||
|
f5251a6080 | ||
|
86fb02d218 | ||
|
ef4a138237 | ||
|
d531a37412 | ||
|
ca599437f6 | ||
|
252afddbd3 | ||
|
c57c4b1b4f | ||
|
ba2dc90f3b | ||
|
7373f312da | ||
|
a01810d8fa | ||
|
3ea3eb5ebd | ||
|
11022e16ef | ||
|
8d06a7b685 | ||
|
c66c8092f9 | ||
|
591139f44d | ||
|
410ad09b5c | ||
|
51138f8738 | ||
|
aa8d38108f | ||
|
9372cc85d0 | ||
|
accb80289f | ||
|
e591fbb25c | ||
|
fdb89fb5e4 | ||
|
ce51821043 | ||
|
eac33d50b3 | ||
|
2552b73b17 | ||
|
8c4019693b | ||
|
b88ef82563 | ||
|
3e5b4a1735 | ||
|
41a7125370 | ||
|
c40484abb1 | ||
|
f4bcfee687 | ||
|
6d8eb9d05e | ||
|
76f2f6a5e1 | ||
|
d677b765b2 | ||
|
7035792325 | ||
|
351c2e97ea | ||
|
ddefb2ee16 | ||
|
c3b41a5e8a | ||
|
b16c58bfe1 | ||
|
e6d0a19e8f | ||
|
2296d09e92 | ||
|
69af252844 | ||
|
d9c598af3c | ||
|
3cb79fc2b5 | ||
|
39379fe5b6 | ||
|
1375f91e15 | ||
|
08a7055679 | ||
|
9f9a828294 | ||
|
77fbb2a851 | ||
|
c0683586e2 | ||
|
86a483f288 | ||
|
3617a3b37d | ||
|
24634aabd7 | ||
|
ffc286c9f9 | ||
|
7064442a4c | ||
|
68a64e9498 | ||
|
b04240b9e7 | ||
|
196a5aea13 | ||
|
f2f99b429f | ||
|
561bda71a9 | ||
|
6b686a96e7 | ||
|
dbe21cc5a7 | ||
|
8b154054c3 | ||
|
972e517280 | ||
|
ca9760cd36 | ||
|
75894fd5bc | ||
|
083a44df2e | ||
|
1e57533127 | ||
|
92e217d0ac | ||
|
707354348a | ||
|
f0d493b064 | ||
|
46f0e6c84d | ||
|
1dd768545a | ||
|
787c8c566f | ||
|
fd10861065 | ||
|
0812ca2927 | ||
|
a8a375ed1f | ||
|
f4b32a2bc6 | ||
|
e2350a65b1 | ||
|
437833cd32 | ||
|
1df524ae6e | ||
|
9d1693cf78 | ||
|
5524e9b9c8 | ||
|
2d6cc3c98e | ||
|
f4b955ccff | ||
|
850473ce40 | ||
|
22d900def1 | ||
|
41eef0c3e2 | ||
|
037fd6e4f7 | ||
|
0b927ddfbb | ||
|
56b8b7c64e | ||
|
0407dbb09b | ||
|
d6932cbb5e | ||
|
c77484e97b | ||
|
9f90cd2635 | ||
|
8fd9e3f312 | ||
|
5df1338046 | ||
|
5d7e0d67cc | ||
|
fdebbac2df | ||
|
a561a9d98a | ||
|
3ac6690ac9 | ||
|
e1f83a50ae | ||
|
8cdc273dba | ||
|
eada9053ad | ||
|
5867774bee | ||
|
18151d9a8e | ||
|
f207a1909f | ||
|
e713d0df9c | ||
|
1ca8a4f4c3 | ||
|
9349425ecd | ||
|
38f6be2aa0 | ||
|
d0abd8c295 | ||
|
9be23cf222 | ||
|
90508a191d | ||
|
10d7d3cb3d | ||
|
89850420f6 | ||
|
9b73eab07c | ||
|
6897e233d4 | ||
|
acfadc8993 | ||
|
cc81e20206 | ||
|
92303c7b26 | ||
|
2866185349 | ||
|
b9570ac6b0 | ||
|
2a3ae641ab | ||
|
d149490c78 | ||
|
c0d8a2c4fb | ||
|
5b03859467 | ||
|
a661634194 | ||
|
c73d45fc07 | ||
|
85a53d7470 | ||
|
18eea191ed | ||
|
14cff9ea44 | ||
|
1696903b8b | ||
|
13c67c9a40 | ||
|
2dcb81d93c | ||
|
b39a9a5edc | ||
|
325242e3aa | ||
|
757d2a4fd9 | ||
|
725ab74e5c | ||
|
b7ca5d330b | ||
|
4034bea6d1 | ||
|
6751c4d2fe | ||
|
53a55d4946 | ||
|
79338d0d75 | ||
|
17bc6a1512 | ||
|
6543ebcd4d | ||
|
351bec6019 | ||
|
a4715bfc3b | ||
|
4ef8030a93 | ||
|
7bfbe81f61 | ||
|
81d6bcf00a | ||
|
a93a039df3 | ||
|
d0d0d2a7c3 | ||
|
6f71439edd | ||
|
b0d3ba7e70 | ||
|
a265b027cc | ||
|
859e6720bf | ||
|
b7bae1120b | ||
|
4727a83d84 | ||
|
67641acdff | ||
|
09b74aa61d | ||
|
d75d266376 | ||
|
645d412c02 | ||
|
5f1609577e | ||
|
351580d9d8 | ||
|
9c9db978c6 | ||
|
a18b4184f5 | ||
|
a7b4f7d66b | ||
|
18933d5075 | ||
|
d53abc661c | ||
|
3481ec8aa2 | ||
|
e563230f10 | ||
|
28f85e3bea | ||
|
4cb4d5ba21 | ||
|
be478561b6 | ||
|
608fdb3ac3 | ||
|
74d9946db3 | ||
|
521e5b22aa | ||
|
85312f6995 | ||
|
f463eb9db1 | ||
|
f4cdfa91c1 | ||
|
fe6ecb1dcf | ||
|
0bf2a5333a | ||
|
105a5b2a31 | ||
|
ecf2f2b9ea | ||
|
493834fcbf | ||
|
fb518715ce | ||
|
fce24aa74d | ||
|
0c30b9ca66 | ||
|
03aa81450e | ||
|
6c34535155 | ||
|
5bd62fe942 | ||
|
26781d2c38 | ||
|
18e1bb33de | ||
|
3a6468897f | ||
|
97484eea6a | ||
|
a2f87f20b7 | ||
|
b6ba08813d | ||
|
3341728eb2 | ||
|
6b172d4c27 | ||
|
4962762c28 | ||
|
56b559894c | ||
|
a9a68a5cc8 | ||
|
542ca52d49 | ||
|
7d0c075b36 | ||
|
c056be3e48 | ||
|
f3e6f99696 | ||
|
3ad4010526 | ||
|
07c07ccb5e | ||
|
6a8f8bf7b7 | ||
|
4917bc228c | ||
|
b58082b536 | ||
|
f70c039275 | ||
|
f102b4fb68 | ||
|
c003f699c7 | ||
|
ad78ec838b | ||
|
34a7d14557 | ||
|
f5b6b43bef | ||
|
3be3794311 | ||
|
710c65aa42 | ||
|
7d3712a4b1 | ||
|
d6955922e9 | ||
|
352d49ec5a | ||
|
88616853c4 | ||
|
8eb7dc0d76 | ||
|
4cc3f97569 | ||
|
e6545f9dca | ||
|
7b1b5e94cb | ||
|
eceb84b978 | ||
|
ffac434bcc | ||
|
e74e5061d8 | ||
|
cb523e7e34 | ||
|
da12c09fda | ||
|
e04e6d2fae | ||
|
e555f67c8d | ||
|
822669fc0c | ||
|
828bc299b2 | ||
|
d22e489626 | ||
|
ab8bc44849 | ||
|
4f832e1eb1 | ||
|
9add9edcc1 | ||
|
59e23fb32a | ||
|
22dcef33da | ||
|
866c598809 | ||
|
b6d99abcb0 | ||
|
c692ac8bab | ||
|
43d064733f | ||
|
6c00aea91d | ||
|
ddff5f923d | ||
|
17e72e0cf4 | ||
|
c25be195f9 | ||
|
d842d395d0 | ||
|
6b2f5944ef | ||
|
9afa707d54 | ||
|
33a725606d | ||
|
e3f13bf545 | ||
|
dbc80a4360 | ||
|
4b63c20a58 | ||
|
8fc0cadae4 | ||
|
52bdc79f79 | ||
|
4c46dd222e | ||
|
6a81bcbefc | ||
|
f42f45e42e | ||
|
333ce37c97 | ||
|
645fc7210e | ||
|
ff37850fea | ||
|
57c24953be | ||
|
92d9435bba | ||
|
9f6bd64100 | ||
|
e86d5cb3f1 | ||
|
f818bdf40e | ||
|
246732153c | ||
|
92ce378a93 | ||
|
4506037bda | ||
|
d99002ef2f | ||
|
a98dcea6fe | ||
|
1e2d2b3d25 | ||
|
0f4546db47 | ||
|
d0b1034f35 | ||
|
1cfe10105a | ||
|
7739923273 | ||
|
e771099568 | ||
|
a361fbab14 | ||
|
61d1685e84 | ||
|
d2267dbd24 | ||
|
87186d73b7 | ||
|
e76111c2b7 | ||
|
60b2caf41d | ||
|
89f3c35466 | ||
|
55d68bd105 | ||
|
7293d47234 | ||
|
49e0088f72 | ||
|
37331c4dc8 | ||
|
562c257596 | ||
|
f481a9baeb | ||
|
322eb15bb5 | ||
|
6b4e51b3a3 | ||
|
daa352d126 | ||
|
e903cbee68 | ||
|
920fd9344f | ||
|
463803f74d | ||
|
7a646d3a84 | ||
|
14a7142ad7 | ||
|
66bea97e8c | ||
|
7214101cfc | ||
|
81f3dc9a2b | ||
|
c7e9235db3 | ||
|
2f010584ef | ||
|
4a50af333d | ||
|
c89a2346a8 | ||
|
22f793a16f | ||
|
6edd486b4c | ||
|
8a6823b78d | ||
|
d80b2935fc | ||
|
d5ae471d94 | ||
|
9a265f7956 | ||
|
04b8394009 | ||
|
6ae4db460e | ||
|
768dfb369c | ||
|
0d173d4c35 | ||
|
4b8bc76622 | ||
|
1a1bfd9348 | ||
|
91bf8cc241 | ||
|
3c7fe00130 | ||
|
5f8ca89772 | ||
|
f855b572e8 | ||
|
5e365bb974 | ||
|
85c42db355 | ||
|
a81c486e0e | ||
|
e8d43f2087 | ||
|
5abb84eda0 | ||
|
9fd7ccc137 | ||
|
a3a617171a | ||
|
47731ce901 | ||
|
fcf57abbb2 | ||
|
3aa8465640 | ||
|
2a8688b54e | ||
|
aec9aa908c | ||
|
8de2cdb1d9 | ||
|
2c1dedfe8a | ||
|
d732778f65 | ||
|
6eb5db0239 | ||
|
7a851084c6 | ||
|
9b6a92c506 | ||
|
781bf985c3 | ||
|
87a142cc30 | ||
|
4fa37bb356 | ||
|
514aabb838 | ||
|
3cb53448c5 | ||
|
8ae0dbcf46 | ||
|
ffcad85d95 | ||
|
14b680f6be | ||
|
74f48d28a4 | ||
|
cab721923a | ||
|
dcd1026a98 | ||
|
31c3b495bf | ||
|
a8b6389092 | ||
|
5e91b95cb3 | ||
|
1ed4c27420 | ||
|
57f825b0a8 | ||
|
846a008c76 | ||
|
a189156f26 | ||
|
d63c0ea262 | ||
|
f74a35074a | ||
|
9a41ab8bfc | ||
|
e415e0051a | ||
|
945d60bd5d | ||
|
892ae3a0d3 | ||
|
2727ba0078 | ||
|
c12472857b | ||
|
385111a1f2 | ||
|
608bcb767b | ||
|
89e89a73dc | ||
|
2fecadd2a6 | ||
|
373ddf9f34 | ||
|
a3fd22b3dd | ||
|
e5e132f67a | ||
|
b4e8c27618 | ||
|
d65cdaf028 | ||
|
5f1779c4e7 | ||
|
b10613c5e3 | ||
|
1c3b319aa6 | ||
|
1069507ab4 | ||
|
5ca63c921a | ||
|
943fc1cc82 | ||
|
a158883aed | ||
|
8aba2b29b8 | ||
|
b5e8f9206b | ||
|
755a753cb5 | ||
|
e99211db31 | ||
|
1142f8d86b | ||
|
5772a2f12f | ||
|
f351cea442 | ||
|
2e1f1c05cf | ||
|
7279c8675b | ||
|
94945ec49e | ||
|
2b8a27ef47 | ||
|
7d1aa28087 | ||
|
31b36f23e7 | ||
|
0fcbeb8158 | ||
|
0876fd9ad3 | ||
|
2545ea7dc1 | ||
|
6eeb7e13e4 | ||
|
38c50c00b0 | ||
|
df85c98e53 | ||
|
0f30b2a803 | ||
|
f2dc89cdf3 | ||
|
c676ba9857 | ||
|
d99e871e11 | ||
|
0f6f5e2939 | ||
|
9fd6f309df | ||
|
41d8a1efa3 | ||
|
4928221b49 | ||
|
8131d5be90 | ||
|
a948335e45 | ||
|
aa978d3581 | ||
|
b1d91f33cf | ||
|
1be25955d6 | ||
|
3365953257 | ||
|
302bf1f70d | ||
|
6553fb3f22 | ||
|
fdfe80289a | ||
|
0ed6674ceb | ||
|
912cd3fa25 | ||
|
1b29c0f1a0 | ||
|
a5b83c00bd | ||
|
129c9a7b7a | ||
|
958eab33a7 | ||
|
fead044830 | ||
|
21f48c0491 | ||
|
ac990b609a | ||
|
e5bbd41570 | ||
|
99f54d1a02 | ||
|
b2188514d9 | ||
|
0897e6226c | ||
|
3ee9175a5d | ||
|
cca5ae6229 | ||
|
b1082ecb41 | ||
|
af83b1e80e | ||
|
92ace5c6e5 | ||
|
5ed4a8a2c4 | ||
|
4fdfb63128 | ||
|
ddfb355280 | ||
|
ac3743027b | ||
|
ed5c33008d | ||
|
0ce0459cfe | ||
|
a76fbcd23d | ||
|
bef7a212e3 | ||
|
ec191cffe1 | ||
|
5c13c3ee54 | ||
|
52bd18a2b4 | ||
|
74338bca6c | ||
|
6d1702a15d | ||
|
500640c56c | ||
|
7d50b8e812 | ||
|
43ce218cbb | ||
|
5b870a84f8 | ||
|
7e009a2d02 | ||
|
602bc85121 | ||
|
e567866a01 | ||
|
3c2720ece4 | ||
|
1440a5e46c | ||
|
0db10063ac | ||
|
9844613b2d | ||
|
ed2cabc5b6 | ||
|
926034c824 | ||
|
e965bfdeb5 | ||
|
085f849855 | ||
|
6ea2f6480d | ||
|
f75fef179a | ||
|
a6cfd40b0f | ||
|
3f3b987fb1 | ||
|
bdbf9072f6 | ||
|
c993a0cdc0 | ||
|
9dfa485bcb | ||
|
c760667448 | ||
|
0298f6fb7d | ||
|
17b7bf7d1d | ||
|
ed6301a497 | ||
|
c423ef810f | ||
|
485a3772b6 | ||
|
6f03eec814 | ||
|
0a5455642f | ||
|
8fdcb02740 | ||
|
153bb962c5 | ||
|
3ee5f22a55 | ||
|
c09663f2b8 | ||
|
6a41ae5254 | ||
|
dd5fc7dc24 | ||
|
11415bea0b | ||
|
eb5010a3f8 | ||
|
da329b6b37 | ||
|
248b09641d | ||
|
0af98224dd | ||
|
88185320a8 | ||
|
a1e5fdddda | ||
|
58d0a988a9 | ||
|
a9b6cd3e12 | ||
|
44666402dd | ||
|
4c82648a9a |
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
tests/ export-ignore
|
||||
phpunit.xml export-ignore
|
||||
build.xml export-ignore
|
||||
test export-ignore
|
||||
.travis.yml export-ignore
|
17
.gitignore
vendored
17
.gitignore
vendored
@@ -1,5 +1,14 @@
|
||||
/vendor/
|
||||
/vendor
|
||||
/composer.lock
|
||||
/docs/build/
|
||||
/build/logs/
|
||||
/build/coverage/
|
||||
/build
|
||||
/docs
|
||||
/testing
|
||||
/examples/relational/vendor
|
||||
/examples/relational/config/oauth2.sqlite3
|
||||
/examples/nosql/vendor
|
||||
/examples/nosql/config/oauth2.sqlite3
|
||||
/examples/relational/composer.lock
|
||||
/tests/codecept/tests/_log
|
||||
oauth2-server.paw
|
||||
/output_*/
|
||||
/_site
|
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]
|
19
.travis.yml
Normal file
19
.travis.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- hhvm
|
||||
|
||||
before_script:
|
||||
- travis_retry composer self-update
|
||||
- travis_retry composer install --no-interaction --prefer-source --dev
|
||||
|
||||
script:
|
||||
- mkdir -p build/logs
|
||||
- phpunit --coverage-text --verbose --coverage-clover=coverage.clover
|
||||
|
||||
after_script:
|
||||
- wget https://scrutinizer-ci.com/ocular.phar
|
||||
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
|
129
CHANGELOG.md
Normal file
129
CHANGELOG.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Changelog
|
||||
|
||||
## 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)
|
||||
|
||||
## 3.1.2 (released 2014-02-26)
|
||||
|
||||
* Support Authorization being an environment variable. [See more](http://fortrabbit.com/docs/essentials/quirks-and-constraints#authorization-header)
|
||||
|
||||
## 3.1.1 (released 2013-12-05)
|
||||
|
||||
* Normalize headers when `getallheaders()` is available (Issues #108 and #114)
|
||||
|
||||
## 3.1.0 (released 2013-12-05)
|
||||
|
||||
* No longer necessary to inject the authorisation server into a grant, the server will inject itself
|
||||
* Added test for 1419ba8cdcf18dd034c8db9f7de86a2594b68605
|
||||
|
||||
## 3.0.1 (released 2013-12-02)
|
||||
|
||||
* Forgot to tell TravisCI from testing PHP 5.3
|
||||
|
||||
## 3.0.0 (released 2013-12-02)
|
||||
|
||||
* Fixed spelling of Implicit grant class (Issue #84)
|
||||
* Travis CI now tests for PHP 5.5
|
||||
* Fixes for checking headers for resource server (Issues #79 and #)
|
||||
* The word "bearer" now has a capital "B" in JSON output to match OAuth 2.0 spec
|
||||
* All grants no longer remove old sessions by default
|
||||
* All grants now support custom access token TTL (Issue #92)
|
||||
* All methods which didn't before return a value now return `$this` to support method chaining
|
||||
* Removed the build in DB providers - these will be put in their own repos to remove baggage in the main repository
|
||||
* Removed support for PHP 5.3 because this library now uses traits and will use other modern PHP features going forward
|
||||
* Moved some grant related functions into a trait to reduce duplicate code
|
||||
|
||||
## 2.1.1 (released 2013-06-02)
|
||||
|
||||
* Added conditional `isValid()` flag to check for Authorization header only (thanks @alexmcroberts)
|
||||
* Fixed semantic meaning of `requireScopeParam()` and `requireStateParam()` by changing their default value to true
|
||||
* Updated some duff docblocks
|
||||
* Corrected array key call in Resource.php (Issue #63)
|
||||
|
||||
## 2.1 (released 2013-05-10)
|
||||
|
||||
* Moved zetacomponents/database to "suggest" in composer.json. If you rely on this feature you now need to include " zetacomponents/database" into "require" key in your own composer.json. (Issue #51)
|
||||
* New method in Refresh grant called `rotateRefreshTokens()`. Pass in `true` to issue a new refresh token each time an access token is refreshed. This parameter needs to be set to true in order to request reduced scopes with the new access token. (Issue #47)
|
||||
* Rename `key` column in oauth_scopes table to `scope` as `key` is a reserved SQL word. (Issue #45)
|
||||
* The `scope` parameter is no longer required by default as per the RFC. (Issue #43)
|
||||
* You can now set multiple default scopes by passing an array into `setDefaultScope()`. (Issue #42)
|
||||
* The password and client credentials grants now allow for multiple sessions per user. (Issue #32)
|
||||
* Scopes associated to authorization codes are not held in their own table (Issue #44)
|
||||
* Database schema updates.
|
||||
|
||||
## 2.0.5 (released 2013-05-09)
|
||||
|
||||
* Fixed `oauth_session_token_scopes` table primary key
|
||||
* Removed `DEFAULT ''` that has slipped into some tables
|
||||
* Fixed docblock for `SessionInterface::associateRefreshToken()`
|
||||
|
||||
## 2.0.4 (released 2013-05-09)
|
||||
|
||||
* Renamed primary key in oauth_client_endpoints table
|
||||
* Adding missing column to oauth_session_authcodes
|
||||
* SECURITY FIX: A refresh token should be bound to a client ID
|
||||
|
||||
## 2.0.3 (released 2013-05-08)
|
||||
|
||||
* Fixed a link to code in composer.json
|
||||
|
||||
## 2.0.2 (released 2013-05-08)
|
||||
|
||||
* Updated README with wiki guides
|
||||
* Removed `null` as default parameters in some methods in the storage interfaces
|
||||
* Fixed license copyright
|
||||
|
||||
## 2.0.0 (released 2013-05-08)
|
||||
|
||||
**If you're upgrading from v1.0.8 there are lots of breaking changes**
|
||||
|
||||
* Rewrote the session storage interface from scratch so methods are more obvious
|
||||
* 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
|
||||
* 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
|
||||
|
||||
## 1.0.8 (released 2013-03-18)
|
||||
|
||||
* Fixed check for required state parameter
|
||||
* Fixed check that user's credentials are correct in Password grant
|
||||
|
||||
## 1.0.7 (released 2013-03-04)
|
||||
|
||||
* Added method `requireStateParam()`
|
||||
* Added method `requireScopeParam()`
|
||||
|
||||
## 1.0.6 (released 2013-02-22)
|
||||
|
||||
* Added links to tutorials in the README
|
||||
* Added missing `state` parameter request to the `checkAuthoriseParams()` method.
|
||||
|
||||
## 1.0.5 (released 2013-02-21)
|
||||
|
||||
* Fixed the SQL example for SessionInterface::getScopes()
|
||||
|
||||
## 1.0.3 (released 2013-02-20)
|
||||
|
||||
* Changed all instances of the "authentication server" to "authorization server"
|
||||
|
||||
## 1.0.2 (released 2013-02-20)
|
||||
|
||||
* Fixed MySQL create table order
|
||||
* Fixed version number in composer.json
|
||||
|
||||
## 1.0.1 (released 2013-02-19)
|
||||
|
||||
* Updated AuthServer.php to use `self::getParam()`
|
||||
|
||||
## 1.0.0 (released 2013-02-15)
|
||||
|
||||
* First major release
|
15
CONTRIBUTING.md
Normal file
15
CONTRIBUTING.md
Normal file
@@ -0,0 +1,15 @@
|
||||
Thanks for contributing to this project.
|
||||
|
||||
|
||||
**Please submit your pull request against the `develop` branch only.**
|
||||
|
||||
|
||||
Please ensure that you run `phpunit` from the project root after you've made any changes.
|
||||
|
||||
If you've added something new please create a new unit test, if you've changed something please update any unit tests as appropritate.
|
||||
|
||||
We're trying to ensure there is **100%** test code coverage (including testing PHP errors and exceptions) so please ensure any new/updated tests cover all of your changes.
|
||||
|
||||
Thank you,
|
||||
|
||||
@alexbilbie
|
97
README.md
97
README.md
@@ -1,43 +1,72 @@
|
||||
# PHP OAuth Framework
|
||||
# PHP OAuth 2.0 Server by [@alexbilbie](https://twitter.com/alexbilbie)
|
||||
|
||||
The goal of this project is to develop a standards compliant [OAuth 2](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authentication server, resource server and client library with support for a major OAuth 2 providers.
|
||||
|
||||
## Package Installation
|
||||
|
||||
The framework is provided as a Composer package which can be installed by adding the package to your composer.json file:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"require": {
|
||||
"lncd\Oauth2": "*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Package Integration
|
||||
|
||||
Check out the [wiki](https://github.com/lncd/OAuth2/wiki)
|
||||
|
||||
## Current Features
|
||||
|
||||
### Authentication Server
|
||||
|
||||
The authentication server is a flexible class that supports the standard authorization code grant.
|
||||
|
||||
### 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 permission to access resources.
|
||||
[](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)
|
||||
|
||||
|
||||
A standards compliant [OAuth 2.0](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-v2/) authorization server and resource 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.
|
||||
|
||||
It supports out of the box the following grants:
|
||||
|
||||
* Authorization code grant
|
||||
* Client credentials grant
|
||||
* Resource owner password credentials grant
|
||||
* Refresh grant
|
||||
|
||||
You can also define your own grants.
|
||||
|
||||
In addition it supports the following token types:
|
||||
|
||||
* Bearer tokens
|
||||
* MAC tokens (coming soon)
|
||||
* JSON web tokens (coming soon)
|
||||
|
||||
|
||||
## Future Goals
|
||||
## Requirements
|
||||
|
||||
### Authentication Server
|
||||
The following versions of PHP are supported:
|
||||
|
||||
* Support for [JSON web tokens](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-json-web-token/).
|
||||
* Support for [SAML assertions](http://tools.ietf.org/wg/oauth/draft-ietf-oauth-saml2-bearer/).
|
||||
* PHP 5.4
|
||||
* PHP 5.5
|
||||
* PHP 5.6
|
||||
* HHVM
|
||||
|
||||
---
|
||||
## Documentation
|
||||
|
||||
This code will be developed as part of the [Linkey](http://linkey.blogs.lincoln.ac.uk) project which has been funded by [JISC](http://jisc.ac.uk) under the Access and Identity Management programme.
|
||||
This library has [full documentation](http://oauth2.thephpleague.com), powered by [Jekyll](http://jekyllrb.com/).
|
||||
|
||||
Contribute to this documentation in the [gh-pages branch](https://github.com/thephpleague/oauth2-server/tree/gh-pages/).
|
||||
|
||||
## Changelog
|
||||
|
||||
[See the project releases page](https://github.com/thephpleague/oauth2-server/releases)
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-server/blob/master/CONTRIBUTING.md) for details.
|
||||
|
||||
## Support
|
||||
|
||||
Bugs and feature request are tracked on [GitHub](https://github.com/thephpleague/oauth2-server/issues)
|
||||
|
||||
## License
|
||||
|
||||
This package is released under the MIT License. See the bundled [LICENSE](https://github.com/thephpleague/oauth2-server/blob/master/LICENSE) file for details.
|
||||
|
||||
## Credits
|
||||
|
||||
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)
|
||||
|
||||
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.
|
||||
|
142
build.xml
142
build.xml
@@ -1,142 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="PHP OAuth 2.0 Server" default="build">
|
||||
|
||||
<target name="build" depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,composer,phpunit,phpdox,phpcb"/>
|
||||
|
||||
<target name="build-parallel" depends="prepare,lint,tools-parallel,phpcb"/>
|
||||
|
||||
<target name="minimal" depends="prepare,lint,phploc,pdepend,phpcpd,composer,phpunit,phpdox,phpcb" />
|
||||
|
||||
<target name="tools-parallel" description="Run tools in parallel">
|
||||
<parallel threadCount="2">
|
||||
<sequential>
|
||||
<antcall target="pdepend"/>
|
||||
<antcall target="phpmd-ci"/>
|
||||
</sequential>
|
||||
<antcall target="phpcpd"/>
|
||||
<antcall target="phpcs-ci"/>
|
||||
<antcall target="phploc"/>
|
||||
<antcall target="phpdox"/>
|
||||
</parallel>
|
||||
</target>
|
||||
|
||||
<target name="clean" description="Cleanup build artifacts">
|
||||
<delete dir="${basedir}/build/api"/>
|
||||
<delete dir="${basedir}/build/code-browser"/>
|
||||
<delete dir="${basedir}/build/coverage"/>
|
||||
<delete dir="${basedir}/build/logs"/>
|
||||
<delete dir="${basedir}/build/pdepend"/>
|
||||
</target>
|
||||
|
||||
<target name="prepare" depends="clean" description="Prepare for build">
|
||||
<mkdir dir="${basedir}/build/api"/>
|
||||
<mkdir dir="${basedir}/build/code-browser"/>
|
||||
<mkdir dir="${basedir}/build/coverage"/>
|
||||
<mkdir dir="${basedir}/build/logs"/>
|
||||
<mkdir dir="${basedir}/build/pdepend"/>
|
||||
<mkdir dir="${basedir}/build/phpdox"/>
|
||||
</target>
|
||||
|
||||
<target name="lint">
|
||||
<apply executable="php" failonerror="true">
|
||||
<arg value="-l" />
|
||||
|
||||
<fileset dir="${basedir}/src">
|
||||
<include name="**/*.php" />
|
||||
<modified />
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<target name="phploc" description="Measure project size using PHPLOC">
|
||||
<exec executable="phploc">
|
||||
<arg value="--log-csv" />
|
||||
<arg value="${basedir}/build/logs/phploc.csv" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="pdepend" description="Calculate software metrics using PHP_Depend">
|
||||
<exec executable="pdepend">
|
||||
<arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
|
||||
<arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
|
||||
<arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpmd" description="Perform project mess detection using PHPMD and print human readable output. Intended for usage on the command line before committing.">
|
||||
<exec executable="phpmd">
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="text" />
|
||||
<arg value="${basedir}/build/phpmd.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpmd-ci" description="Perform project mess detection using PHPMD creating a log file for the continuous integration server">
|
||||
<exec executable="phpmd">
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="xml" />
|
||||
<arg value="${basedir}/build/phpmd.xml" />
|
||||
<arg value="--reportfile" />
|
||||
<arg value="${basedir}/build/logs/pmd.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcs" description="Find coding standard violations using PHP_CodeSniffer and print human readable output. Intended for usage on the command line before committing.">
|
||||
<exec executable="phpcs">
|
||||
<arg value="--standard=${basedir}/build/phpcs.xml" />
|
||||
<arg value="--extensions=php" />
|
||||
<arg value="--ignore=third_party/CIUnit" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcs-ci" description="Find coding standard violations using PHP_CodeSniffer creating a log file for the continuous integration server">
|
||||
<exec executable="phpcs" output="/dev/null">
|
||||
<arg value="--report=checkstyle" />
|
||||
<arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
|
||||
<arg value="--standard=${basedir}/build/phpcs.xml" />
|
||||
<arg value="--extensions=php" />
|
||||
<arg value="--ignore=third_party/CIUnit" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpcpd" description="Find duplicate code using PHPCPD">
|
||||
<exec executable="phpcpd">
|
||||
<arg value="--log-pmd" />
|
||||
<arg value="${basedir}/build/logs/pmd-cpd.xml" />
|
||||
<arg path="${basedir}/src" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="composer" description="Install Composer requirements">
|
||||
<exec executable="composer.phar" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg value="--dev" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpunit" description="Run unit tests with PHPUnit">
|
||||
<exec executable="${basedir}/vendor/bin/phpunit" failonerror="true">
|
||||
<arg value="--configuration" />
|
||||
<arg value="${basedir}/build/phpunit.xml" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="phpdox" description="Generate API documentation using phpDox">
|
||||
<exec executable="phpdox"/>
|
||||
</target>
|
||||
|
||||
<target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
|
||||
<exec executable="phpcb">
|
||||
<arg value="--log" />
|
||||
<arg path="${basedir}/build/logs" />
|
||||
<arg value="--source" />
|
||||
<arg path="${basedir}/src" />
|
||||
<arg value="--output" />
|
||||
<arg path="${basedir}/build/code-browser" />
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<ruleset name="PHP_CodeSniffer">
|
||||
|
||||
<description>PHP_CodeSniffer configuration</description>
|
||||
|
||||
<rule ref="PSR2"/>
|
||||
|
||||
</ruleset>
|
@@ -1,14 +0,0 @@
|
||||
<ruleset name="OAuth 2.0 Server"
|
||||
xmlns="http://pmd.sf.net/ruleset/1.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0
|
||||
http://pmd.sf.net/ruleset_xml_schema.xsd"
|
||||
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
|
||||
|
||||
<description>
|
||||
Ruleset for OAuth 2.0 server
|
||||
</description>
|
||||
|
||||
<!-- Import the entire unused code rule set -->
|
||||
<rule ref="rulesets/unusedcode.xml" />
|
||||
</ruleset>
|
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="false" stopOnFailure="false" stopOnIncomplete="false" stopOnSkipped="false">
|
||||
<testsuites>
|
||||
<testsuite name="Authentication Server">
|
||||
<directory suffix="test.php">../tests/authentication</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Resource Server">
|
||||
<directory suffix="test.php">../tests/resource</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<blacklist>
|
||||
<directory suffix=".php">PEAR_INSTALL_DIR</directory>
|
||||
<directory suffix=".php">PHP_LIBDIR</directory>
|
||||
<directory suffix=".php">../vendor/composer</directory>
|
||||
</blacklist>
|
||||
</filter>
|
||||
<logging>
|
||||
<log type="coverage-html" target="coverage" title="lncd/OAuth" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
|
||||
<log type="coverage-clover" target="logs/clover.xml"/>
|
||||
<log type="junit" target="logs/junit.xml" logIncompleteSkipped="false"/>
|
||||
</logging>
|
||||
</phpunit>
|
@@ -1,40 +1,64 @@
|
||||
{
|
||||
"name": "lncd/Oauth2",
|
||||
"description": "OAuth 2.0 Framework",
|
||||
"version": "0.2",
|
||||
"homepage": "https://github.com/lncd/OAuth2",
|
||||
"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.3.0"
|
||||
"php": ">=5.4.0",
|
||||
"symfony/http-foundation": "~2.5",
|
||||
"league/event": "1.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"EHER/PHPUnit": "*"
|
||||
"phpunit/phpunit": "4.3.*",
|
||||
"mockery/mockery": "0.9.*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/lncd/OAuth2"
|
||||
"url": "https://github.com/thephpleague/oauth2-server.git"
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"oauth",
|
||||
"oauth2",
|
||||
"oauth 2",
|
||||
"oauth 2.0",
|
||||
"server",
|
||||
"auth",
|
||||
"authorization",
|
||||
"authorisation",
|
||||
"authentication",
|
||||
"resource"
|
||||
"resource",
|
||||
"api",
|
||||
"auth",
|
||||
"protect",
|
||||
"secure"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alex Bilbie",
|
||||
"email": "oauth2server@alexbilbie.com",
|
||||
"homepage": "http://www.httpster.org",
|
||||
"email": "hello@alexbilbie.com",
|
||||
"homepage": "http://www.alexbilbie.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"replace": {
|
||||
"lncd/oauth2": "*",
|
||||
"league/oauth2server": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Oauth2": "src/"
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"LeagueTests\\": "tests/unit/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-develop": "4.0.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
examples/relational/Model/Users.php
Normal file
25
examples/relational/Model/Users.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Model;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class Users
|
||||
{
|
||||
public function get($username = null)
|
||||
{
|
||||
$query = Capsule::table('users')->select(['username', 'password', 'name', 'email', 'photo']);
|
||||
|
||||
if ($username !== null) {
|
||||
$query->where('username', '=', $username);
|
||||
}
|
||||
|
||||
$result = $query->get();
|
||||
|
||||
if (count($result) > 0) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
96
examples/relational/Storage/AccessTokenStorage.php
Normal file
96
examples/relational/Storage/AccessTokenStorage.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AbstractTokenEntity;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class AccessTokenStorage extends Adapter implements AccessTokenInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($token)
|
||||
{
|
||||
$result = Capsule::table('oauth_access_tokens')
|
||||
->where('access_token', $token)
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$token = (new AccessTokenEntity($this->server))
|
||||
->setId($result[0]['access_token'])
|
||||
->setExpireTime($result[0]['expire_time']);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopes(AbstractTokenEntity $token)
|
||||
{
|
||||
$result = Capsule::table('oauth_access_token_scopes')
|
||||
->select(['oauth_scopes.id', 'oauth_scopes.description'])
|
||||
->join('oauth_scopes', 'oauth_access_token_scopes.scope', '=', 'oauth_scopes.id')
|
||||
->where('access_token', $token->getId())
|
||||
->get();
|
||||
|
||||
$response = [];
|
||||
|
||||
if (count($result) > 0) {
|
||||
foreach ($result as $row) {
|
||||
$scope = (new ScopeEntity($this->server))->hydrate([
|
||||
'id' => $row['id'],
|
||||
'description' => $row['description']
|
||||
]);
|
||||
$response[] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create($token, $expireTime, $sessionId)
|
||||
{
|
||||
Capsule::table('oauth_access_tokens')
|
||||
->insert([
|
||||
'access_token' => $token,
|
||||
'session_id' => $sessionId,
|
||||
'expire_time' => $expireTime
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function associateScope(AbstractTokenEntity $token, ScopeEntity $scope)
|
||||
{
|
||||
Capsule::table('oauth_access_token_scopes')
|
||||
->insert([
|
||||
'access_token' => $token->getId(),
|
||||
'scope' => $scope->getId()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(AbstractTokenEntity $token)
|
||||
{
|
||||
Capsule::table('oauth_access_token_scopes')
|
||||
->where('access_token', $token->getId())
|
||||
->delete();
|
||||
}
|
||||
}
|
92
examples/relational/Storage/AuthCodeStorage.php
Normal file
92
examples/relational/Storage/AuthCodeStorage.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\AuthCodeInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class AuthCodeStorage extends Adapter implements AuthCodeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($code)
|
||||
{
|
||||
$result = Capsule::table('oauth_auth_codes')
|
||||
->where('auth_code', $code)
|
||||
->where('expire_time', '>=', time())
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$token = new AuthCodeEntity($this->server);
|
||||
$token->setId($result[0]['auth_code']);
|
||||
$token->setRedirectUri($result[0]['client_redirect_uri']);
|
||||
return $token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function create($token, $expireTime, $sessionId, $redirectUri)
|
||||
{
|
||||
Capsule::table('oauth_auth_codes')
|
||||
->insert([
|
||||
'auth_code' => $token,
|
||||
'client_redirect_uri' => $redirectUri,
|
||||
'session_id' => $sessionId,
|
||||
'expire_time' => $expireTime
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopes(AuthCodeEntity $token)
|
||||
{
|
||||
$result = Capsule::table('oauth_auth_code_scopes')
|
||||
->select(['oauth_scopes.id', 'oauth_scopes.description'])
|
||||
->join('oauth_scopes', 'oauth_auth_code_scopes.scope', '=', 'oauth_scopes.id')
|
||||
->where('auth_code', $token->getId())
|
||||
->get();
|
||||
|
||||
$response = [];
|
||||
|
||||
if (count($result) > 0) {
|
||||
foreach ($result as $row) {
|
||||
$scope = (new ScopeEntity($this->server))->hydrate([
|
||||
'id' => $row['id'],
|
||||
'description' => $row['description']
|
||||
]);
|
||||
$response[] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function associateScope(AuthCodeEntity $token, ScopeEntity $scope)
|
||||
{
|
||||
Capsule::table('oauth_auth_code_scopes')
|
||||
->insert([
|
||||
'auth_code' => $token->getId(),
|
||||
'scope' => $scope->getId()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(AuthCodeEntity $token)
|
||||
{
|
||||
Capsule::table('oauth_auth_codes')
|
||||
->where('auth_code', $token->getId())
|
||||
->delete();
|
||||
}
|
||||
}
|
71
examples/relational/Storage/ClientStorage.php
Normal file
71
examples/relational/Storage/ClientStorage.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class ClientStorage extends Adapter implements ClientInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($clientId, $clientSecret = null, $redirectUri = null, $grantType = null)
|
||||
{
|
||||
$query = Capsule::table('oauth_clients')
|
||||
->select('oauth_clients.*')
|
||||
->where('oauth_clients.id', $clientId);
|
||||
|
||||
if ($clientSecret !== null) {
|
||||
$query->where('oauth_clients.secret', $clientSecret);
|
||||
}
|
||||
|
||||
if ($redirectUri) {
|
||||
$query->join('oauth_client_redirect_uris', 'oauth_clients.id', '=', 'oauth_client_redirect_uris.client_id')
|
||||
->select(['oauth_clients.*', 'oauth_client_redirect_uris.*'])
|
||||
->where('oauth_client_redirect_uris.redirect_uri', $redirectUri);
|
||||
}
|
||||
|
||||
$result = $query->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$client = new ClientEntity($this->server);
|
||||
$client->hydrate([
|
||||
'id' => $result[0]['id'],
|
||||
'name' => $result[0]['name']
|
||||
]);
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBySession(SessionEntity $session)
|
||||
{
|
||||
$result = Capsule::table('oauth_clients')
|
||||
->select(['oauth_clients.id', 'oauth_clients.name'])
|
||||
->join('oauth_sessions', 'oauth_clients.id', '=', 'oauth_sessions.client_id')
|
||||
->where('oauth_sessions.id', $session->getId())
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$client = new ClientEntity($this->server);
|
||||
$client->hydrate([
|
||||
'id' => $result[0]['id'],
|
||||
'name' => $result[0]['name']
|
||||
]);
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
57
examples/relational/Storage/RefreshTokenStorage.php
Normal file
57
examples/relational/Storage/RefreshTokenStorage.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class RefreshTokenStorage extends Adapter implements RefreshTokenInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($token)
|
||||
{
|
||||
$result = Capsule::table('oauth_refresh_tokens')
|
||||
->where('refresh_token', $token)
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$token = (new RefreshTokenEntity($this->server))
|
||||
->setId($result[0]['refresh_token'])
|
||||
->setExpireTime($result[0]['expire_time'])
|
||||
->setAccessTokenId($result[0]['access_token']);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create($token, $expireTime, $accessToken)
|
||||
{
|
||||
Capsule::table('oauth_refresh_tokens')
|
||||
->insert([
|
||||
'refresh_token' => $token,
|
||||
'access_token' => $accessToken,
|
||||
'expire_time' => $expireTime
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function delete(RefreshTokenEntity $token)
|
||||
{
|
||||
Capsule::table('oauth_refresh_tokens')
|
||||
->where('refresh_token', $token->getId())
|
||||
->delete();
|
||||
}
|
||||
|
||||
}
|
31
examples/relational/Storage/ScopeStorage.php
Normal file
31
examples/relational/Storage/ScopeStorage.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class ScopeStorage extends Adapter implements ScopeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($scope, $grantType = null, $clientId = null)
|
||||
{
|
||||
$result = Capsule::table('oauth_scopes')
|
||||
->where('id', $scope)
|
||||
->get();
|
||||
|
||||
if (count($result) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (new ScopeEntity($this->server))->hydrate([
|
||||
'id' => $result[0]['id'],
|
||||
'description' => $result[0]['description']
|
||||
]);
|
||||
}
|
||||
}
|
110
examples/relational/Storage/SessionStorage.php
Normal file
110
examples/relational/Storage/SessionStorage.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Storage;
|
||||
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\Adapter;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
class SessionStorage extends Adapter implements SessionInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getByAccessToken(AccessTokenEntity $accessToken)
|
||||
{
|
||||
$result = Capsule::table('oauth_sessions')
|
||||
->select(['oauth_sessions.id', 'oauth_sessions.owner_type', 'oauth_sessions.owner_id', 'oauth_sessions.client_id', 'oauth_sessions.client_redirect_uri'])
|
||||
->join('oauth_access_tokens', 'oauth_access_tokens.session_id', '=', 'oauth_sessions.id')
|
||||
->where('oauth_access_tokens.access_token', $accessToken->getId())
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setId($result[0]['id']);
|
||||
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getByAuthCode(AuthCodeEntity $authCode)
|
||||
{
|
||||
$result = Capsule::table('oauth_sessions')
|
||||
->select(['oauth_sessions.id', 'oauth_sessions.owner_type', 'oauth_sessions.owner_id', 'oauth_sessions.client_id', 'oauth_sessions.client_redirect_uri'])
|
||||
->join('oauth_auth_codes', 'oauth_auth_codes.session_id', '=', 'oauth_sessions.id')
|
||||
->where('oauth_auth_codes.auth_code', $authCode->getId())
|
||||
->get();
|
||||
|
||||
if (count($result) === 1) {
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setId($result[0]['id']);
|
||||
$session->setOwner($result[0]['owner_type'], $result[0]['owner_id']);
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopes(SessionEntity $session)
|
||||
{
|
||||
$result = Capsule::table('oauth_sessions')
|
||||
->select('oauth_scopes.*')
|
||||
->join('oauth_session_scopes', 'oauth_sessions.id', '=', 'oauth_session_scopes.session_id')
|
||||
->join('oauth_scopes', 'oauth_scopes.id', '=', 'oauth_session_scopes.scope')
|
||||
->where('oauth_sessions.id', $session->getId())
|
||||
->get();
|
||||
|
||||
$scopes = [];
|
||||
|
||||
foreach ($result as $scope) {
|
||||
$scopes[] = (new ScopeEntity($this->server))->hydrate([
|
||||
'id' => $scope['id'],
|
||||
'description' => $scope['description']
|
||||
]);
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function create($ownerType, $ownerId, $clientId, $clientRedirectUri = null)
|
||||
{
|
||||
$id = Capsule::table('oauth_sessions')
|
||||
->insertGetId([
|
||||
'owner_type' => $ownerType,
|
||||
'owner_id' => $ownerId,
|
||||
'client_id' => $clientId
|
||||
]);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function associateScope(SessionEntity $session, ScopeEntity $scope)
|
||||
{
|
||||
Capsule::table('oauth_session_scopes')
|
||||
->insert([
|
||||
'session_id' => $session->getId(),
|
||||
'scope' => $scope->getId()
|
||||
]);
|
||||
}
|
||||
}
|
145
examples/relational/api.php
Normal file
145
examples/relational/api.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
use \Orno\Http\Request;
|
||||
use \Orno\Http\Response;
|
||||
use \Orno\Http\JsonResponse;
|
||||
use \Orno\Http\Exception\NotFoundException;
|
||||
use \League\OAuth2\Server\ResourceServer;
|
||||
use \RelationalExample\Storage;
|
||||
use \RelationalExample\Model;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use \League\Event\Emitter;
|
||||
|
||||
include __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
|
||||
|
||||
// Set up the OAuth 2.0 resource server
|
||||
$sessionStorage = new Storage\SessionStorage();
|
||||
$accessTokenStorage = new Storage\AccessTokenStorage();
|
||||
$clientStorage = new Storage\ClientStorage();
|
||||
$scopeStorage = new Storage\ScopeStorage();
|
||||
|
||||
$server = new ResourceServer(
|
||||
$sessionStorage,
|
||||
$accessTokenStorage,
|
||||
$clientStorage,
|
||||
$scopeStorage
|
||||
);
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
|
||||
// GET /tokeninfo
|
||||
$router->get('/tokeninfo', function (Request $request) use ($server) {
|
||||
|
||||
$token = [
|
||||
'owner_id' => $server->getOwnerId(),
|
||||
'owner_type' => $server->getOwnerType(),
|
||||
'access_token' => $server->getAccessToken(),
|
||||
'client_id' => $server->getClientId(),
|
||||
'scopes' => $server->getScopes()
|
||||
];
|
||||
|
||||
return new Response(json_encode($token));
|
||||
|
||||
});
|
||||
|
||||
// GET /users
|
||||
$router->get('/users', function (Request $request) use ($server) {
|
||||
|
||||
$results = (new Model\Users())->get();
|
||||
|
||||
$users = [];
|
||||
|
||||
foreach ($results as $result) {
|
||||
$user = [
|
||||
'username' => $result['username'],
|
||||
'name' => $result['name']
|
||||
];
|
||||
|
||||
if ($server->hasScope('email')) {
|
||||
$user['email'] = $result['email'];
|
||||
}
|
||||
|
||||
if ($server->hasScope('photo')) {
|
||||
$user['photo'] = $result['photo'];
|
||||
}
|
||||
|
||||
$users[] = $user;
|
||||
}
|
||||
|
||||
return new Response(json_encode($users));
|
||||
});
|
||||
|
||||
// GET /users/{username}
|
||||
$router->get('/users/{username}', function (Request $request, $args) use ($server) {
|
||||
|
||||
$result = (new Model\Users())->get($args['username']);
|
||||
|
||||
if (count($result) === 0) {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
$user = [
|
||||
'username' => $result[0]['username'],
|
||||
'name' => $result[0]['name']
|
||||
];
|
||||
|
||||
if ($server->hasScope('email')) {
|
||||
$user['email'] = $result[0]['email'];
|
||||
}
|
||||
|
||||
if ($server->hasScope('photo')) {
|
||||
$user['photo'] = $result[0]['photo'];
|
||||
}
|
||||
|
||||
return new Response(json_encode($user));
|
||||
});
|
||||
|
||||
$dispatcher = $router->getDispatcher();
|
||||
|
||||
try {
|
||||
|
||||
// Check that access token is present
|
||||
$server->isValidRequest(false);
|
||||
|
||||
// A successful response
|
||||
$response = $dispatcher->dispatch(
|
||||
$request->getMethod(),
|
||||
$request->getPathInfo()
|
||||
);
|
||||
|
||||
} catch (\Orno\Http\Exception $e) {
|
||||
|
||||
// A failed response
|
||||
$response = $e->getJsonResponse();
|
||||
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
|
||||
|
||||
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
|
||||
|
||||
$response = new Response(json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]), $e->httpStatusCode);
|
||||
|
||||
foreach ($e->getHttpHeaders() as $header) {
|
||||
$response->headers($header);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$response = new Orno\Http\Response;
|
||||
$response->setStatusCode(500);
|
||||
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
|
||||
|
||||
} finally {
|
||||
|
||||
// Return the response
|
||||
$response->headers->set('Content-type', 'application/json');
|
||||
$response->send();
|
||||
|
||||
}
|
139
examples/relational/authcode_grant.php
Normal file
139
examples/relational/authcode_grant.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
use \Orno\Http\Request;
|
||||
use \Orno\Http\Response;
|
||||
use \Orno\Http\JsonResponse;
|
||||
use \Orno\Http\Exception\NotFoundException;
|
||||
use \League\OAuth2\Server\ResourceServer;
|
||||
use \RelationalExample\Storage;
|
||||
use \RelationalExample\Model;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use \League\Event\Emitter;
|
||||
|
||||
include __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
|
||||
|
||||
// Set up the OAuth 2.0 authorization server
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
|
||||
|
||||
$authCodeGrant = new \League\OAuth2\Server\Grant\AuthCodeGrant();
|
||||
$server->addGrantType($authCodeGrant);
|
||||
|
||||
$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
|
||||
$server->addGrantType($refrehTokenGrant);
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
|
||||
$router->get('/authorize', function (Request $request) use ($server) {
|
||||
|
||||
// First ensure the parameters in the query string are correct
|
||||
|
||||
try {
|
||||
|
||||
$authParams = $server->getGrantType('authorization_code')->checkAuthorizeParams();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Normally at this point you would show the user a sign-in screen and ask them to authorize the requested scopes
|
||||
|
||||
// ...
|
||||
|
||||
// ...
|
||||
|
||||
// ...
|
||||
|
||||
// Create a new authorize request which will respond with a redirect URI that the user will be redirected to
|
||||
|
||||
$redirectUri = $server->getGrantType('authorization_code')->newAuthorizeRequest('user', 1, $authParams);
|
||||
|
||||
$response = new Response('', 200, [
|
||||
'Location' => $redirectUri
|
||||
]);
|
||||
|
||||
return $response;
|
||||
});
|
||||
|
||||
$router->post('/access_token', function (Request $request) use ($server) {
|
||||
|
||||
try {
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
return new Response(json_encode($response), 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$dispatcher = $router->getDispatcher();
|
||||
|
||||
try {
|
||||
|
||||
// A successful response
|
||||
$response = $dispatcher->dispatch(
|
||||
$request->getMethod(),
|
||||
$request->getPathInfo()
|
||||
);
|
||||
|
||||
} catch (\Orno\Http\Exception $e) {
|
||||
|
||||
// A failed response
|
||||
$response = $e->getJsonResponse();
|
||||
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
|
||||
|
||||
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
|
||||
|
||||
$response = new Response(json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]), $e->httpStatusCode);
|
||||
|
||||
foreach ($e->getHttpHeaders() as $header) {
|
||||
$response->headers($header);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$response = new Orno\Http\Response;
|
||||
$response->setStatusCode(500);
|
||||
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
|
||||
|
||||
} finally {
|
||||
|
||||
// Return the response
|
||||
$response->headers->set('Content-type', 'application/json');
|
||||
$response->send();
|
||||
|
||||
}
|
17
examples/relational/composer.json
Normal file
17
examples/relational/composer.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"require": {
|
||||
"illuminate/database": "4.1.*",
|
||||
"orno/route": "1.*",
|
||||
"ircmaxell/password-compat": "1.0.2",
|
||||
"league/event": "0.2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\OAuth2\\Server\\": "../../src/",
|
||||
"RelationalExample\\": "."
|
||||
},
|
||||
"files": [
|
||||
"config/db.php"
|
||||
]
|
||||
}
|
||||
}
|
18
examples/relational/config/db.php
Normal file
18
examples/relational/config/db.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Config;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
include __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$capsule = new Capsule;
|
||||
|
||||
$capsule->addConnection([
|
||||
'driver' => 'sqlite',
|
||||
'database' => __DIR__.'/oauth2.sqlite3',
|
||||
'charset' => 'utf8',
|
||||
'collation' => 'utf8_unicode_ci'
|
||||
]);
|
||||
|
||||
$capsule->setAsGlobal();
|
249
examples/relational/config/init.php
Normal file
249
examples/relational/config/init.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace RelationalExample\Config;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
|
||||
include __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
@unlink(__DIR__.'/oauth2.sqlite3');
|
||||
touch(__DIR__.'/oauth2.sqlite3');
|
||||
|
||||
Capsule::statement('PRAGMA foreign_keys = ON');
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating users table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('users', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('username');
|
||||
$table->string('password');
|
||||
$table->string('name');
|
||||
$table->string('email');
|
||||
$table->string('photo');
|
||||
});
|
||||
|
||||
Capsule::table('users')->insert([
|
||||
'username' => 'alexbilbie',
|
||||
'password' => password_hash('whisky', PASSWORD_DEFAULT),
|
||||
'name' => 'Alex Bilbie',
|
||||
'email' => 'hello@alexbilbie.com',
|
||||
'photo' => 'https://s.gravatar.com/avatar/14902eb1dac66b8458ebbb481d80f0a3'
|
||||
]);
|
||||
|
||||
Capsule::table('users')->insert([
|
||||
'username' => 'philsturgeon',
|
||||
'password' => password_hash('cider', PASSWORD_DEFAULT),
|
||||
'name' => 'Phil Sturgeon',
|
||||
'email' => 'email@philsturgeon.co.uk',
|
||||
'photo' => 'https://s.gravatar.com/avatar/14df293d6c5cd6f05996dfc606a6a951'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating clients table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_clients', function ($table) {
|
||||
$table->string('id');
|
||||
$table->string('secret');
|
||||
$table->string('name');
|
||||
$table->primary('id');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_clients')->insert([
|
||||
'id' => 'testclient',
|
||||
'secret' => 'secret',
|
||||
'name' => 'Test Client'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating client redirect uris table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_client_redirect_uris', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('client_id');
|
||||
$table->string('redirect_uri');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_client_redirect_uris')->insert([
|
||||
'client_id' => 'testclient',
|
||||
'redirect_uri' => 'http://example.com/redirect'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_scopes', function ($table) {
|
||||
$table->string('id');
|
||||
$table->string('description');
|
||||
$table->primary('id');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_scopes')->insert([
|
||||
'id' => 'basic',
|
||||
'description' => 'Basic details about your account'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_scopes')->insert([
|
||||
'id' => 'email',
|
||||
'description' => 'Your email address'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_scopes')->insert([
|
||||
'id' => 'photo',
|
||||
'description' => 'Your photo'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating sessions table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_sessions', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('owner_type');
|
||||
$table->string('owner_id');
|
||||
$table->string('client_id');
|
||||
$table->string('client_redirect_uri')->nullable();
|
||||
|
||||
$table->foreign('client_id')->references('id')->on('oauth_clients')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_sessions')->insert([
|
||||
'owner_type' => 'client',
|
||||
'owner_id' => 'testclient',
|
||||
'client_id' => 'testclient'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_sessions')->insert([
|
||||
'owner_type' => 'user',
|
||||
'owner_id' => '1',
|
||||
'client_id' => 'testclient'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_sessions')->insert([
|
||||
'owner_type' => 'user',
|
||||
'owner_id' => '2',
|
||||
'client_id' => 'testclient'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating access tokens table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_access_tokens', function ($table) {
|
||||
$table->string('access_token')->primary();
|
||||
$table->integer('session_id');
|
||||
$table->integer('expire_time');
|
||||
|
||||
$table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_access_tokens')->insert([
|
||||
'access_token' => 'iamgod',
|
||||
'session_id' => '1',
|
||||
'expire_time' => time() + 86400
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_tokens')->insert([
|
||||
'access_token' => 'iamalex',
|
||||
'session_id' => '2',
|
||||
'expire_time' => time() + 86400
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_tokens')->insert([
|
||||
'access_token' => 'iamphil',
|
||||
'session_id' => '3',
|
||||
'expire_time' => time() + 86400
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating refresh tokens table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_refresh_tokens', function ($table) {
|
||||
$table->string('refresh_token')->primary();
|
||||
$table->integer('expire_time');
|
||||
$table->string('access_token');
|
||||
|
||||
$table->foreign('access_token')->references('id')->on('oauth_access_tokens')->onDelete('cascade');
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating auth codes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_auth_codes', function ($table) {
|
||||
$table->string('auth_code')->primary();
|
||||
$table->integer('session_id');
|
||||
$table->integer('expire_time');
|
||||
$table->string('client_redirect_uri');
|
||||
|
||||
$table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade');
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating oauth access token scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_access_token_scopes', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('access_token');
|
||||
$table->string('scope');
|
||||
|
||||
$table->foreign('access_token')->references('access_token')->on('oauth_access_tokens')->onDelete('cascade');
|
||||
$table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Capsule::table('oauth_access_token_scopes')->insert([
|
||||
'access_token' => 'iamgod',
|
||||
'scope' => 'basic'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_token_scopes')->insert([
|
||||
'access_token' => 'iamgod',
|
||||
'scope' => 'email'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_token_scopes')->insert([
|
||||
'access_token' => 'iamgod',
|
||||
'scope' => 'photo'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_token_scopes')->insert([
|
||||
'access_token' => 'iamphil',
|
||||
'scope' => 'email'
|
||||
]);
|
||||
|
||||
Capsule::table('oauth_access_token_scopes')->insert([
|
||||
'access_token' => 'iamalex',
|
||||
'scope' => 'photo'
|
||||
]);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating oauth auth code scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_auth_code_scopes', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('auth_code');
|
||||
$table->string('scope');
|
||||
|
||||
$table->foreign('auth_code')->references('auth_code')->on('oauth_auth_codes')->onDelete('cascade');
|
||||
$table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade');
|
||||
});
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
print 'Creating oauth session scopes table'.PHP_EOL;
|
||||
|
||||
Capsule::schema()->create('oauth_session_scopes', function ($table) {
|
||||
$table->increments('id');
|
||||
$table->string('session_id');
|
||||
$table->string('scope');
|
||||
|
||||
$table->foreign('session_id')->references('id')->on('oauth_sessions')->onDelete('cascade');
|
||||
$table->foreign('scope')->references('id')->on('oauth_scopes')->onDelete('cascade');
|
||||
});
|
114
examples/relational/other_grants.php
Normal file
114
examples/relational/other_grants.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
use \Orno\Http\Request;
|
||||
use \Orno\Http\Response;
|
||||
use \Orno\Http\JsonResponse;
|
||||
use \Orno\Http\Exception\NotFoundException;
|
||||
use \League\OAuth2\Server\ResourceServer;
|
||||
use \RelationalExample\Storage;
|
||||
use \RelationalExample\Model;
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
use \League\Event\Emitter;
|
||||
|
||||
include __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
$router->setStrategy(\Orno\Route\RouteStrategyInterface::RESTFUL_STRATEGY);
|
||||
|
||||
// Set up the OAuth 2.0 authorization server
|
||||
$server = new \League\OAuth2\Server\AuthorizationServer;
|
||||
$server->setSessionStorage(new Storage\SessionStorage);
|
||||
$server->setAccessTokenStorage(new Storage\AccessTokenStorage);
|
||||
$server->setRefreshTokenStorage(new Storage\RefreshTokenStorage);
|
||||
$server->setClientStorage(new Storage\ClientStorage);
|
||||
$server->setScopeStorage(new Storage\ScopeStorage);
|
||||
$server->setAuthCodeStorage(new Storage\AuthCodeStorage);
|
||||
|
||||
$clientCredentials = new \League\OAuth2\Server\Grant\ClientCredentialsGrant();
|
||||
$server->addGrantType($clientCredentials);
|
||||
|
||||
$passwordGrant = new \League\OAuth2\Server\Grant\PasswordGrant();
|
||||
$passwordGrant->setVerifyCredentialsCallback(function ($username, $password) {
|
||||
$result = (new Model\Users())->get($username);
|
||||
if (count($result) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password_verify($password, $result[0]['password'])) {
|
||||
return $username;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
$server->addGrantType($passwordGrant);
|
||||
|
||||
$refrehTokenGrant = new \League\OAuth2\Server\Grant\RefreshTokenGrant();
|
||||
$server->addGrantType($refrehTokenGrant);
|
||||
|
||||
// Routing setup
|
||||
$request = (new Request)->createFromGlobals();
|
||||
$router = new \Orno\Route\RouteCollection;
|
||||
|
||||
$router->post('/access_token', function (Request $request) use ($server) {
|
||||
|
||||
try {
|
||||
|
||||
$response = $server->issueAccessToken();
|
||||
return new Response(json_encode($response), 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
return new Response(
|
||||
json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]),
|
||||
$e->httpStatusCode,
|
||||
$e->getHttpHeaders()
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$dispatcher = $router->getDispatcher();
|
||||
|
||||
try {
|
||||
|
||||
// A successful response
|
||||
$response = $dispatcher->dispatch(
|
||||
$request->getMethod(),
|
||||
$request->getPathInfo()
|
||||
);
|
||||
|
||||
} catch (\Orno\Http\Exception $e) {
|
||||
|
||||
// A failed response
|
||||
$response = $e->getJsonResponse();
|
||||
$response->setContent(json_encode(['status_code' => $e->getStatusCode(), 'message' => $e->getMessage()]));
|
||||
|
||||
} catch (\League\OAuth2\Server\Exception\OAuthException $e) {
|
||||
|
||||
$response = new Response(json_encode([
|
||||
'error' => $e->errorType,
|
||||
'message' => $e->getMessage()
|
||||
]), $e->httpStatusCode);
|
||||
|
||||
foreach ($e->getHttpHeaders() as $header) {
|
||||
$response->headers($header);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$response = new Orno\Http\Response;
|
||||
$response->setStatusCode(500);
|
||||
$response->setContent(json_encode(['status_code' => 500, 'message' => $e->getMessage()]));
|
||||
|
||||
} finally {
|
||||
|
||||
// Return the response
|
||||
$response->headers->set('Content-type', 'application/json');
|
||||
$response->send();
|
||||
|
||||
}
|
18
license.txt
18
license.txt
@@ -1,20 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2012 University of Lincoln
|
||||
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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
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
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
17
phpunit.xml
Normal file
17
phpunit.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit colors="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnError="true" stopOnFailure="true" stopOnIncomplete="false" stopOnSkipped="false" bootstrap="tests/unit/Bootstrap.php">
|
||||
<testsuites>
|
||||
<testsuite name="Tests">
|
||||
<directory>./tests/unit/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist addUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<logging>
|
||||
<!-- <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>
|
||||
</phpunit>
|
302
src/AbstractServer.php
Normal file
302
src/AbstractServer.php
Normal file
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract Server
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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;
|
||||
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\TokenType\TokenTypeInterface;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||
use League\OAuth2\Server\Storage\AuthCodeInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use League\Event\Emitter;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*/
|
||||
|
||||
abstract class AbstractServer
|
||||
{
|
||||
/**
|
||||
* The request object
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Session storage
|
||||
* @var \League\OAuth2\Server\Storage\SessionInterface
|
||||
*/
|
||||
protected $sessionStorage;
|
||||
|
||||
/**
|
||||
* Access token storage
|
||||
* @var \League\OAuth2\Server\Storage\AccessTokenInterface
|
||||
*/
|
||||
protected $accessTokenStorage;
|
||||
|
||||
/**
|
||||
* Refresh token storage
|
||||
* @var \League\OAuth2\Server\Storage\RefreshTokenInterface
|
||||
*/
|
||||
protected $refreshTokenStorage;
|
||||
|
||||
/**
|
||||
* Auth code storage
|
||||
* @var \League\OAuth2\Server\Storage\AuthCodeInterface
|
||||
*/
|
||||
protected $authCodeStorage;
|
||||
|
||||
/**
|
||||
* Scope storage
|
||||
* @var \League\OAuth2\Server\Storage\ScopeInterface
|
||||
*/
|
||||
protected $scopeStorage;
|
||||
|
||||
/**
|
||||
* Client storage
|
||||
* @var \League\OAuth2\Server\Storage\ClientInterface
|
||||
*/
|
||||
protected $clientStorage;
|
||||
|
||||
/**
|
||||
* Token type
|
||||
* @var \League\OAuth2\Server\TokenType\TokenTypeInterface
|
||||
*/
|
||||
protected $tokenType;
|
||||
|
||||
/**
|
||||
* Event emitter
|
||||
* @var \League\Event\Emitter
|
||||
*/
|
||||
protected $eventEmitter;
|
||||
|
||||
/**
|
||||
* Abstract server constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setEventEmitter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an event emitter
|
||||
* @param object $emitter Event emitter object
|
||||
*/
|
||||
public function setEventEmitter($emitter = null)
|
||||
{
|
||||
if ($emitter === null) {
|
||||
$this->eventEmitter = new Emitter;
|
||||
} else {
|
||||
$this->eventEmitter = $emitter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an event listener to the event emitter
|
||||
* @param string $eventName Event name
|
||||
* @param callable $listener Callable function or method
|
||||
*/
|
||||
public function addEventListener($eventName, callable $listener)
|
||||
{
|
||||
$this->eventEmitter->addListener($eventName, $listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event emitter
|
||||
* @return \League\Event\Emitter
|
||||
*/
|
||||
public function getEventEmitter()
|
||||
{
|
||||
return $this->eventEmitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Request Object
|
||||
* @param \Symfony\Component\HttpFoundation\Request The Request Object
|
||||
* @return self
|
||||
*/
|
||||
public function setRequest($request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Request object. It will create one from the globals if one is not set.
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
if ($this->request === null) {
|
||||
$this->request = Request::createFromGlobals();
|
||||
}
|
||||
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the client storage
|
||||
* @param \League\OAuth2\Server\Storage\ClientInterface $storage
|
||||
* @return self
|
||||
*/
|
||||
public function setClientStorage(ClientInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->clientStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session storage
|
||||
* @param \League\OAuth2\Server\Storage\SessionInterface $storage
|
||||
* @return self
|
||||
*/
|
||||
public function setSessionStorage(SessionInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->sessionStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the access token storage
|
||||
* @param \League\OAuth2\Server\Storage\AccessTokenInterface $storage
|
||||
* @return self
|
||||
*/
|
||||
public function setAccessTokenStorage(AccessTokenInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->accessTokenStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the refresh token storage
|
||||
* @param \League\OAuth2\Server\Storage\RefreshTokenInteface $storage
|
||||
* @return self
|
||||
*/
|
||||
public function setRefreshTokenStorage(RefreshTokenInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->refreshTokenStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the auth code storage
|
||||
* @param \League\OAuth2\Server\Storage\AuthCodeInterface $authCode
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthCodeStorage(AuthCodeInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->authCodeStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scope storage
|
||||
* @param \League\OAuth2\Server\Storage\ScopeInterface $storage
|
||||
* @return self
|
||||
*/
|
||||
public function setScopeStorage(ScopeInterface $storage)
|
||||
{
|
||||
$storage->setServer($this);
|
||||
$this->scopeStorage = $storage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client storage
|
||||
* @return \League\OAuth2\Server\Storage\ClientInterface
|
||||
*/
|
||||
public function getClientStorage()
|
||||
{
|
||||
return $this->clientStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scope storage
|
||||
* @return \League\OAuth2\Server\Storage\ScopeInterface
|
||||
*/
|
||||
public function getScopeStorage()
|
||||
{
|
||||
return $this->scopeStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session storage
|
||||
* @return \League\OAuth2\Server\Storage\SessionInterface
|
||||
*/
|
||||
public function getSessionStorage()
|
||||
{
|
||||
return $this->sessionStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the refresh token storage
|
||||
* @return \League\OAuth2\Server\Storage\RefreshTokenInterface
|
||||
*/
|
||||
public function getRefreshTokenStorage()
|
||||
{
|
||||
return $this->refreshTokenStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the access token storage
|
||||
* @return \League\OAuth2\Server\Storage\AccessTokenInterface
|
||||
*/
|
||||
public function getAccessTokenStorage()
|
||||
{
|
||||
return $this->accessTokenStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the auth code storage
|
||||
* @return \League\OAuth2\Server\Storage\AuthCodeInterface
|
||||
*/
|
||||
public function getAuthCodeStorage()
|
||||
{
|
||||
return $this->authCodeStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the access token type
|
||||
* @param TokenTypeInterface $tokenType The token type
|
||||
* @return void
|
||||
*/
|
||||
public function setTokenType(TokenTypeInterface $tokenType)
|
||||
{
|
||||
$tokenType->setServer($this);
|
||||
$this->tokenType = $tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token type
|
||||
* @return TokenTypeInterface
|
||||
*/
|
||||
public function getTokenType()
|
||||
{
|
||||
return $this->tokenType;
|
||||
}
|
||||
}
|
266
src/AuthorizationServer.php
Normal file
266
src/AuthorizationServer.php
Normal file
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Authorization Server
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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;
|
||||
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use League\OAuth2\Server\Storage\AuthCodeInterface;
|
||||
use League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\TokenType\Bearer;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 authorization server class
|
||||
*/
|
||||
class AuthorizationServer extends AbstractServer
|
||||
{
|
||||
/**
|
||||
* 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 = [];
|
||||
|
||||
/**
|
||||
* The registered grant types
|
||||
* @var array
|
||||
*/
|
||||
protected $grantTypes = [];
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Require the "state" parameter to be in checkAuthoriseParams()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $requireStateParam = false;
|
||||
|
||||
/**
|
||||
* Create a new OAuth2 authorization server
|
||||
* @return self
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Set Bearer as the default token type
|
||||
$this->setTokenType(new Bearer);
|
||||
|
||||
parent::__construct();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* @return self
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 self
|
||||
*/
|
||||
public function requireScopeParam($require = true)
|
||||
{
|
||||
$this->requireScopeParam = $require;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $default Name of the default scope
|
||||
* @param self
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function issueAccessToken()
|
||||
{
|
||||
$grantType = $this->getRequest()->request->get('grant_type');
|
||||
if (is_null($grantType)) {
|
||||
throw new Exception\InvalidRequestException('grant_type');
|
||||
}
|
||||
|
||||
// Ensure grant type is one that is recognised and is enabled
|
||||
if (!in_array($grantType, array_keys($this->grantTypes))) {
|
||||
throw new Exception\UnsupportedGrantTypeException($grantType);
|
||||
}
|
||||
|
||||
// Complete the flow
|
||||
return $this->getGrantType($grantType)->completeFlow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a grant type class
|
||||
* @param string $grantType The grant type identifer
|
||||
* @return Grant\GrantTypeInterface
|
||||
*/
|
||||
public function getGrantType($grantType)
|
||||
{
|
||||
if (isset($this->grantTypes[$grantType])) {
|
||||
return $this->grantTypes[$grantType];
|
||||
}
|
||||
|
||||
throw new Exception\InvalidGrantException($grantType);
|
||||
}
|
||||
}
|
187
src/Entity/AbstractTokenEntity.php
Normal file
187
src/Entity/AbstractTokenEntity.php
Normal file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract token
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\AbstractServer;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
|
||||
/**
|
||||
* Abstract token class
|
||||
*/
|
||||
abstract class AbstractTokenEntity
|
||||
{
|
||||
/**
|
||||
* Token identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Associated session
|
||||
* @var \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* Session scopes
|
||||
* @var \League\OAuth2\Server\Entity\ScopeEntity[]
|
||||
*/
|
||||
protected $scopes;
|
||||
|
||||
/**
|
||||
* Token expire time
|
||||
* @var int
|
||||
*/
|
||||
protected $expireTime = 0;
|
||||
|
||||
/**
|
||||
* Authorization or resource server
|
||||
* @var \League\OAuth2\Server\AbstractServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
* @return self
|
||||
*/
|
||||
public function __construct(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set session
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity $session
|
||||
* @return self
|
||||
*/
|
||||
public function setSession(SessionEntity $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expire time of the token
|
||||
* @param integer $expireTime Unix time stamp
|
||||
* @return self
|
||||
*/
|
||||
public function setExpireTime($expireTime)
|
||||
{
|
||||
$this->expireTime = $expireTime;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return token expire time
|
||||
* @return int
|
||||
*/
|
||||
public function getExpireTime()
|
||||
{
|
||||
return $this->expireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the token expired?
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return ((time() - $this->expireTime) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set token ID
|
||||
* @param string $token Token ID
|
||||
* @return self
|
||||
*/
|
||||
public function setId($id = null)
|
||||
{
|
||||
$this->id = ($id !== null) ? $id : SecureKey::generate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token ID
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a scope
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity $scope
|
||||
* @return self
|
||||
*/
|
||||
public function associateScope(ScopeEntity $scope)
|
||||
{
|
||||
if (!isset($this->scopes[$scope->getId()])) {
|
||||
$this->scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the local scopes array
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity[]
|
||||
* @return array
|
||||
*/
|
||||
protected function formatScopes($unformatted = [])
|
||||
{
|
||||
if (is_null($unformatted)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$scopes = [];
|
||||
foreach ($unformatted as $scope) {
|
||||
if ($scope instanceof ScopeEntity) {
|
||||
$scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token as a string if the object is cast as a string
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if ($this->id === null) {
|
||||
return '';
|
||||
}
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expire the token
|
||||
* @return void
|
||||
*/
|
||||
abstract public function expire();
|
||||
|
||||
/**
|
||||
* Save the token
|
||||
* @return void
|
||||
*/
|
||||
abstract public function save();
|
||||
}
|
89
src/Entity/AccessTokenEntity.php
Normal file
89
src/Entity/AccessTokenEntity.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Access token entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
/**
|
||||
* Access token entity class
|
||||
*/
|
||||
class AccessTokenEntity extends AbstractTokenEntity
|
||||
{
|
||||
/**
|
||||
* Get session
|
||||
* @return \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
if ($this->session instanceof SessionEntity) {
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
$this->session = $this->server->getSessionStorage()->getByAccessToken($this);
|
||||
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if access token has an associated scope
|
||||
* @param string $scope Scope to check
|
||||
* @return bool
|
||||
*/
|
||||
public function hasScope($scope)
|
||||
{
|
||||
if ($this->scopes === null) {
|
||||
$this->getScopes();
|
||||
}
|
||||
|
||||
return isset($this->scopes[$scope]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all scopes associated with the access token
|
||||
* @return \League\OAuth2\Server\Entity\Scope[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
if ($this->scopes === null) {
|
||||
$this->scopes = $this->formatScopes(
|
||||
$this->server->getAccessTokenStorage()->getScopes($this)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->server->getAccessTokenStorage()->create(
|
||||
$this->getId(),
|
||||
$this->getExpireTime(),
|
||||
$this->getSession()->getId()
|
||||
);
|
||||
|
||||
// Associate the scope with the token
|
||||
foreach ($this->getScopes() as $scope) {
|
||||
$this->server->getAccessTokenStorage()->associateScope($this, $scope);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function expire()
|
||||
{
|
||||
$this->server->getAccessTokenStorage()->delete($this);
|
||||
}
|
||||
}
|
120
src/Entity/AuthCodeEntity.php
Normal file
120
src/Entity/AuthCodeEntity.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
/**
|
||||
* Access token entity class
|
||||
*/
|
||||
class AuthCodeEntity extends AbstractTokenEntity
|
||||
{
|
||||
/**
|
||||
* Redirect URI
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectUri = '';
|
||||
|
||||
/**
|
||||
* Set the redirect URI for the authorization request
|
||||
* @param string $redirectUri
|
||||
* @return self
|
||||
*/
|
||||
public function setRedirectUri($redirectUri)
|
||||
{
|
||||
$this->redirectUri = $redirectUri;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the redirect URI
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a redirect URI
|
||||
* @param string $state The state parameter if set by the client
|
||||
* @param string $queryDelimeter The query delimiter ('?' for auth code grant, '#' for implicit grant)
|
||||
* @return string
|
||||
*/
|
||||
public function generateRedirectUri($state = null, $queryDelimeter = '?')
|
||||
{
|
||||
$uri = $this->getRedirectUri();
|
||||
$uri .= (strstr($this->getRedirectUri(), $queryDelimeter) === false) ? $queryDelimeter : '&';
|
||||
|
||||
return $uri.http_build_query([
|
||||
'code' => $this->getId(),
|
||||
'state' => $state
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get session
|
||||
* @return \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
if ($this->session instanceof SessionEntity) {
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
$this->session = $this->server->getSessionStorage()->getByAuthCode($this);
|
||||
|
||||
return $this->session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all scopes associated with the session
|
||||
* @return \League\OAuth2\Server\Entity\Scope[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
if ($this->scopes === null) {
|
||||
$this->scopes = $this->formatScopes(
|
||||
$this->server->getAuthCodeStorage()->getScopes($this)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->server->getAuthCodeStorage()->create(
|
||||
$this->getId(),
|
||||
$this->getExpireTime(),
|
||||
$this->getSession()->getId(),
|
||||
$this->getRedirectUri()
|
||||
);
|
||||
|
||||
// Associate the scope with the token
|
||||
foreach ($this->getScopes() as $scope) {
|
||||
$this->server->getAuthCodeStorage()->associateScope($this, $scope);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function expire()
|
||||
{
|
||||
$this->server->getAuthCodeStorage()->delete($this);
|
||||
}
|
||||
}
|
100
src/Entity/ClientEntity.php
Normal file
100
src/Entity/ClientEntity.php
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
use League\OAuth2\Server\AbstractServer;
|
||||
|
||||
/**
|
||||
* Client entity class
|
||||
*/
|
||||
class ClientEntity
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
/**
|
||||
* Client identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $id = null;
|
||||
|
||||
/**
|
||||
* Client secret
|
||||
* @var string
|
||||
*/
|
||||
protected $secret = null;
|
||||
|
||||
/**
|
||||
* Client name
|
||||
* @var string
|
||||
*/
|
||||
protected $name = null;
|
||||
|
||||
/**
|
||||
* Client redirect URI
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectUri = null;
|
||||
|
||||
/**
|
||||
* Authorization or resource server
|
||||
* @var \League\OAuth2\Server\AbstractServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
* @return self
|
||||
*/
|
||||
public function __construct(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client secret
|
||||
* @return string
|
||||
*/
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the client name
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returnt the client redirect URI
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return $this->redirectUri;
|
||||
}
|
||||
}
|
30
src/Entity/EntityTrait.php
Normal file
30
src/Entity/EntityTrait.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Entity trait
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
trait EntityTrait
|
||||
{
|
||||
/**
|
||||
* Hydrate an entity with properites
|
||||
* @param array $properties
|
||||
*/
|
||||
public function hydrate(array $properties)
|
||||
{
|
||||
foreach ($properties as $prop => $val) {
|
||||
if (property_exists($this, $prop)) {
|
||||
$this->{$prop} = $val;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
87
src/Entity/RefreshTokenEntity.php
Normal file
87
src/Entity/RefreshTokenEntity.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
/**
|
||||
* Refresh token entity class
|
||||
*/
|
||||
class RefreshTokenEntity extends AbstractTokenEntity
|
||||
{
|
||||
/**
|
||||
* Access token associated to refresh token
|
||||
* @var \League\OAuth2\Server\Entity\AccessTokenEntity
|
||||
*/
|
||||
protected $accessTokenEntity;
|
||||
|
||||
/**
|
||||
* Id of the access token
|
||||
* @var string
|
||||
*/
|
||||
protected $accessTokenId;
|
||||
|
||||
/**
|
||||
* Set the ID of the associated access token
|
||||
* @param string $accessToken
|
||||
* @return self
|
||||
*/
|
||||
public function setAccessTokenId($accessTokenId)
|
||||
{
|
||||
$this->accessTokenId = $accessTokenId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate an access token
|
||||
* @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessToken
|
||||
* @return self
|
||||
*/
|
||||
public function setAccessToken(AccessTokenEntity $accessTokenEntity)
|
||||
{
|
||||
$this->accessTokenEntity = $accessTokenEntity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return access token
|
||||
* @return AccessToken
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
if (! $this->accessTokenEntity instanceof AccessTokenEntity) {
|
||||
$this->accessTokenEntity = $this->server->getAccessTokenStorage()->get($this->accessTokenId);
|
||||
}
|
||||
|
||||
return $this->accessTokenEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$this->server->getRefreshTokenStorage()->create(
|
||||
$this->getId(),
|
||||
$this->getExpireTime(),
|
||||
$this->getAccessToken()->getId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function expire()
|
||||
{
|
||||
$this->server->getRefreshTokenStorage()->delete($this);
|
||||
}
|
||||
}
|
82
src/Entity/ScopeEntity.php
Normal file
82
src/Entity/ScopeEntity.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 scope entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
use League\OAuth2\Server\AbstractServer;
|
||||
|
||||
/**
|
||||
* Scope entity class
|
||||
*/
|
||||
class ScopeEntity implements \JsonSerializable
|
||||
{
|
||||
use EntityTrait;
|
||||
|
||||
/**
|
||||
* Scope identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Scope description
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* Authorization or resource server
|
||||
* @var \League\OAuth2\Server\AbstractServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
* @return self
|
||||
*/
|
||||
public function __construct(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scope identifer
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scope's description
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON object when entity is passed into json_encode
|
||||
* @return array
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'description' => $this->getDescription()
|
||||
];
|
||||
}
|
||||
}
|
276
src/Entity/SessionEntity.php
Normal file
276
src/Entity/SessionEntity.php
Normal file
@@ -0,0 +1,276 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 session entity
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity;
|
||||
|
||||
use League\OAuth2\Server\AbstractServer;
|
||||
use League\OAuth2\Server\Event;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
* Session entity grant
|
||||
*/
|
||||
class SessionEntity
|
||||
{
|
||||
/**
|
||||
* Session identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Client identifier
|
||||
* @var \League\OAuth2\Server\Entity\ClientEntity
|
||||
*/
|
||||
protected $client;
|
||||
|
||||
/**
|
||||
* Session owner identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerId;
|
||||
|
||||
/**
|
||||
* Session owner type (e.g. "user")
|
||||
* @var string
|
||||
*/
|
||||
protected $ownerType;
|
||||
|
||||
/**
|
||||
* Auth code
|
||||
* @var \League\OAuth2\Server\Entity\AuthCodeEntity
|
||||
*/
|
||||
protected $authCode;
|
||||
|
||||
/**
|
||||
* Access token
|
||||
* @var \League\OAuth2\Server\Entity\AccessTokenEntity
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* Refresh token
|
||||
* @var \League\OAuth2\Server\Entity\RefreshTokenEntity
|
||||
*/
|
||||
protected $refreshToken;
|
||||
|
||||
/**
|
||||
* Session scopes
|
||||
* @var \Symfony\Component\HttpFoundation\ParameterBag
|
||||
*/
|
||||
protected $scopes;
|
||||
|
||||
/**
|
||||
* Authorization or resource server
|
||||
* @var \League\OAuth2\Server\AuthorizationServer|\League\OAuth2\Server\ResourceServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
* @return self
|
||||
*/
|
||||
public function __construct(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session identifier
|
||||
* @param string $id
|
||||
* @return self
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a scope
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity $scope
|
||||
* @return self
|
||||
*/
|
||||
public function associateScope(ScopeEntity $scope)
|
||||
{
|
||||
if (!isset($this->scopes[$scope->getId()])) {
|
||||
$this->scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if access token has an associated scope
|
||||
* @param string $scope Scope to check
|
||||
* @return bool
|
||||
*/
|
||||
public function hasScope($scope)
|
||||
{
|
||||
if ($this->scopes === null) {
|
||||
$this->getScopes();
|
||||
}
|
||||
|
||||
return isset($this->scopes[$scope]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all scopes associated with the session
|
||||
* @return \League\OAuth2\Server\Entity\Scope[]
|
||||
*/
|
||||
public function getScopes()
|
||||
{
|
||||
if ($this->scopes === null) {
|
||||
$this->scopes = $this->formatScopes($this->server->getSessionStorage()->getScopes($this));
|
||||
}
|
||||
|
||||
return $this->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the local scopes array
|
||||
* @param \League\OAuth2\Server\Entity\Scope[]
|
||||
* @return array
|
||||
*/
|
||||
private function formatScopes($unformated = [])
|
||||
{
|
||||
$scopes = [];
|
||||
if (is_array($unformated)) {
|
||||
foreach ($unformated as $scope) {
|
||||
if ($scope instanceof ScopeEntity) {
|
||||
$scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate an access token with the session
|
||||
* @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessToken
|
||||
* @return self
|
||||
*/
|
||||
public function associateAccessToken(AccessTokenEntity $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a refresh token with the session
|
||||
* @param \League\OAuth2\Server\Entity\RefreshTokenEntity $refreshToken
|
||||
* @return self
|
||||
*/
|
||||
public function associateRefreshToken(RefreshTokenEntity $refreshToken)
|
||||
{
|
||||
$this->refreshToken = $refreshToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a client with the session
|
||||
* @param \League\OAuth2\Server\Entity\ClientEntity $client The client
|
||||
* @return self
|
||||
*/
|
||||
public function associateClient(ClientEntity $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session client
|
||||
* @return \League\OAuth2\Server\Entity\ClientEntity
|
||||
*/
|
||||
public function getClient()
|
||||
{
|
||||
if ($this->client instanceof ClientEntity) {
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
$this->client = $this->server->getClientStorage()->getBySession($this);
|
||||
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session owner
|
||||
* @param string $type The type of the owner (e.g. user, app)
|
||||
* @param string $id The identifier of the owner
|
||||
* @return self
|
||||
*/
|
||||
public function setOwner($type, $id)
|
||||
{
|
||||
$this->ownerType = $type;
|
||||
$this->ownerId = $id;
|
||||
|
||||
$this->server->getEventEmitter()->emit(new Event\SessionOwnerEvent($this));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return session owner identifier
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerId()
|
||||
{
|
||||
return $this->ownerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return session owner type
|
||||
* @return string
|
||||
*/
|
||||
public function getOwnerType()
|
||||
{
|
||||
return $this->ownerType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the session
|
||||
* @return void
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
// Save the session and get an identifier
|
||||
$id = $this->server->getSessionStorage()->create(
|
||||
$this->getOwnerType(),
|
||||
$this->getOwnerId(),
|
||||
$this->getClient()->getId(),
|
||||
$this->getClient()->getRedirectUri()
|
||||
);
|
||||
|
||||
$this->setId($id);
|
||||
|
||||
// Associate the scope with the session
|
||||
foreach ($this->getScopes() as $scope) {
|
||||
$this->server->getSessionStorage()->associateScope($this, $scope);
|
||||
}
|
||||
}
|
||||
}
|
51
src/Event/ClientAuthenticationFailedEvent.php
Normal file
51
src/Event/ClientAuthenticationFailedEvent.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 client authentication failed event
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Event;
|
||||
|
||||
use League\Event\AbstractEvent;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ClientAuthenticationFailedEvent extends AbstractEvent
|
||||
{
|
||||
/**
|
||||
* Request
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* Init the event with a request
|
||||
* @param \Symfony\Component\HttpFoundation\Requesty $request
|
||||
*/
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the event
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'error.auth.client';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return request
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
51
src/Event/SessionOwnerEvent.php
Normal file
51
src/Event/SessionOwnerEvent.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 session owner event
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Event;
|
||||
|
||||
use League\Event\AbstractEvent;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
|
||||
class SessionOwnerEvent extends AbstractEvent
|
||||
{
|
||||
/**
|
||||
* Session entity
|
||||
* @var \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
private $session;
|
||||
|
||||
/**
|
||||
* Init the event with a session
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity $session
|
||||
*/
|
||||
public function __construct(SessionEntity $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the event
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'session.owner';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return session
|
||||
* @return \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
public function getSession()
|
||||
{
|
||||
return $this->session;
|
||||
}
|
||||
}
|
51
src/Event/UserAuthenticationFailedEvent.php
Normal file
51
src/Event/UserAuthenticationFailedEvent.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 user authentication failed event
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Event;
|
||||
|
||||
use League\Event\AbstractEvent;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class UserAuthenticationFailedEvent extends AbstractEvent
|
||||
{
|
||||
/**
|
||||
* Request
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* Init the event with a request
|
||||
* @param \Symfony\Component\HttpFoundation\Requesty $request
|
||||
*/
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the event
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return 'error.auth.user';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return request
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
}
|
36
src/Exception/AccessDeniedException.php
Normal file
36
src/Exception/AccessDeniedException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Access Denied Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class AccessDeniedException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 401;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'access_denied';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('The resource owner or authorization server denied the request.');
|
||||
}
|
||||
}
|
36
src/Exception/InvalidClientException.php
Normal file
36
src/Exception/InvalidClientException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Client Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidClientException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 401;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_client';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Client authentication failed.');
|
||||
}
|
||||
}
|
36
src/Exception/InvalidCredentialsException.php
Normal file
36
src/Exception/InvalidCredentialsException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Credentials Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidCredentialsException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 401;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_credentials';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('The user credentials were incorrect.');
|
||||
}
|
||||
}
|
42
src/Exception/InvalidGrantException.php
Normal file
42
src/Exception/InvalidGrantException.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Grant Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidGrantException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_grant';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
public function __construct($parameter)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'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.',
|
||||
$parameter
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
36
src/Exception/InvalidRefreshException.php
Normal file
36
src/Exception/InvalidRefreshException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Refresh Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidRefreshException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_request';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('The refresh token is invalid.');
|
||||
}
|
||||
}
|
44
src/Exception/InvalidRequestException.php
Normal file
44
src/Exception/InvalidRequestException.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Request Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidRequestException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_request';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'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.',
|
||||
$parameter
|
||||
)
|
||||
);
|
||||
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
}
|
44
src/Exception/InvalidScopeException.php
Normal file
44
src/Exception/InvalidScopeException.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Scope Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class InvalidScopeException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'invalid_scope';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The requested scope is invalid, unknown, or malformed. Check the "%s" scope.',
|
||||
$parameter
|
||||
)
|
||||
);
|
||||
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
}
|
123
src/Exception/OAuthException.php
Normal file
123
src/Exception/OAuthException.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Base Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class OAuthException extends \Exception
|
||||
{
|
||||
/**
|
||||
* The HTTP status code for this exception that should be sent in the response
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* Redirect URI if the server should redirect back to the client
|
||||
* @var string|null
|
||||
*/
|
||||
public $redirectUri = null;
|
||||
|
||||
/**
|
||||
* The exception type
|
||||
*/
|
||||
public $errorType = '';
|
||||
|
||||
/**
|
||||
* Throw a new exception
|
||||
*/
|
||||
public function __construct($msg = 'An error occured')
|
||||
{
|
||||
parent::__construct($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the server redirect back to the client?
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRedirect()
|
||||
{
|
||||
return is_null($this->redirectUri) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return redirect URI if set
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRedirectUri()
|
||||
{
|
||||
return \League\OAuth2\Server\Util\RedirectUri::make(
|
||||
$this->redirectUri,
|
||||
[
|
||||
'error' => $this->errorType,
|
||||
'message' => $this->getMessage(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers that have to be send with the error response
|
||||
* @return array Array with header values
|
||||
*/
|
||||
public function getHttpHeaders()
|
||||
{
|
||||
$headers = [];
|
||||
switch ($this->httpStatusCode) {
|
||||
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';
|
||||
break;
|
||||
}
|
||||
|
||||
// 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 = null;
|
||||
$request = new Request();
|
||||
if ($request->getUser() !== null) {
|
||||
$authScheme = 'Basic';
|
||||
} else {
|
||||
$authHeader = $request->headers->get('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;
|
||||
}
|
||||
}
|
37
src/Exception/ServerErrorException.php
Normal file
37
src/Exception/ServerErrorException.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Server Error Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class ServerErrorException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 500;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'server_error';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($parameter = null)
|
||||
{
|
||||
$parameter = is_null($parameter) ? 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' : $parameter;
|
||||
parent::__construct($parameter);
|
||||
}
|
||||
}
|
36
src/Exception/UnauthorizedClientException.php
Normal file
36
src/Exception/UnauthorizedClientException.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Unauthorized Client Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class UnauthorizedClientException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'unauthorized_client';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('The client is not authorized to request an access token using this method.');
|
||||
}
|
||||
}
|
42
src/Exception/UnsupportedGrantTypeException.php
Normal file
42
src/Exception/UnsupportedGrantTypeException.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Invalid Request Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class UnsupportedGrantTypeException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'unsupported_grant_type';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
public function __construct($parameter)
|
||||
{
|
||||
parent::__construct(
|
||||
sprintf(
|
||||
'The authorization grant type "%s" is not supported by the authorization server.',
|
||||
$parameter
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
37
src/Exception/UnsupportedResponseTypeException.php
Normal file
37
src/Exception/UnsupportedResponseTypeException.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Unsupported Response Type Exception
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Exception;
|
||||
|
||||
/**
|
||||
* Exception class
|
||||
*/
|
||||
class UnsupportedResponseTypeException extends OAuthException
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $httpStatusCode = 400;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public $errorType = 'unsupported_response_type';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($parameter, $redirectUri = null)
|
||||
{
|
||||
parent::__construct('The authorization server does not support obtaining an access token using this method.');
|
||||
$this->redirectUri = $redirectUri;
|
||||
}
|
||||
}
|
189
src/Grant/AbstractGrant.php
Normal file
189
src/Grant/AbstractGrant.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract grant
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\AuthorizationServer;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Exception;
|
||||
|
||||
/**
|
||||
* Abstract grant class
|
||||
*/
|
||||
abstract class AbstractGrant implements GrantTypeInterface
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = '';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType;
|
||||
|
||||
/**
|
||||
* Callback to authenticate a user's name and password
|
||||
* @var function
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var \League\OAuth2\Server\AuthorizationServer
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TTL for an access token
|
||||
* @return int The TTL
|
||||
*/
|
||||
public function getAccessTokenTTL()
|
||||
{
|
||||
if ($this->accessTokenTTL) {
|
||||
return $this->accessTokenTTL;
|
||||
}
|
||||
|
||||
return $this->server->getAccessTokenTTL();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 \League\OAuth2\Server\AuthorizationServer $server The authorization server instance
|
||||
* @return self
|
||||
*/
|
||||
public function setAuthorizationServer(AuthorizationServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of scopes, validate them and return an array of Scope entities
|
||||
* @param string $scopeParam A string of scopes (e.g. "profile email birthday")
|
||||
* @param \League\OAuth2\Server\Entity\ClientEntity $client Client entity
|
||||
* @param string|null $redirectUri The redirect URI to return the user to
|
||||
* @return \League\OAuth2\Server\Entity\ScopeEntity[]
|
||||
* @throws \League\OAuth2\Server\Exception\InvalidScopeException If scope is invalid, or no scopes passed when required
|
||||
*/
|
||||
public function validateScopes($scopeParam = '', ClientEntity $client, $redirectUri = null)
|
||||
{
|
||||
$scopesList = explode($this->server->getScopeDelimeter(), $scopeParam);
|
||||
|
||||
for ($i = 0; $i < count($scopesList); $i++) {
|
||||
$scopesList[$i] = trim($scopesList[$i]);
|
||||
if ($scopesList[$i] === '') {
|
||||
unset($scopesList[$i]); // Remove any junk scopes
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$this->server->scopeParamRequired() === true
|
||||
&& $this->server->getDefaultScope() === null
|
||||
&& count($scopesList) === 0
|
||||
) {
|
||||
throw new Exception\InvalidRequestException('scope');
|
||||
} elseif (count($scopesList) === 0 && $this->server->getDefaultScope() !== null) {
|
||||
if (is_array($this->server->getDefaultScope())) {
|
||||
$scopesList = $this->server->getDefaultScope();
|
||||
} else {
|
||||
$scopesList = [0 => $this->server->getDefaultScope()];
|
||||
}
|
||||
}
|
||||
|
||||
$scopes = [];
|
||||
|
||||
foreach ($scopesList as $scopeItem) {
|
||||
$scope = $this->server->getScopeStorage()->get(
|
||||
$scopeItem,
|
||||
$this->getIdentifier(),
|
||||
$client->getId()
|
||||
);
|
||||
|
||||
if (($scope instanceof ScopeEntity) === false) {
|
||||
throw new Exception\InvalidScopeException($scopeItem, $redirectUri);
|
||||
}
|
||||
|
||||
$scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the local scopes array
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity[]
|
||||
* @return array
|
||||
*/
|
||||
protected function formatScopes($unformated = [])
|
||||
{
|
||||
$scopes = [];
|
||||
foreach ($unformated as $scope) {
|
||||
if ($scope instanceof ScopeEntity) {
|
||||
$scopes[$scope->getId()] = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
}
|
267
src/Grant/AuthCodeGrant.php
Normal file
267
src/Grant/AuthCodeGrant.php
Normal file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code grant
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Request;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Event;
|
||||
|
||||
/**
|
||||
* Auth code grant class
|
||||
*/
|
||||
class AuthCodeGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'authorization_code';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = 'code';
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $server = 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 authorize parameters
|
||||
*
|
||||
* @return array Authorize request parameters
|
||||
*/
|
||||
public function checkAuthorizeParams()
|
||||
{
|
||||
// Get required params
|
||||
$clientId = $this->server->getRequest()->query->get('client_id', null);
|
||||
if (is_null($clientId)) {
|
||||
throw new Exception\InvalidRequestException('client_id');
|
||||
}
|
||||
|
||||
$redirectUri = $this->server->getRequest()->query->get('redirect_uri', null);
|
||||
if (is_null($redirectUri)) {
|
||||
throw new Exception\InvalidRequestException('redirect_uri');
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$clientId,
|
||||
null,
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidClientException();
|
||||
}
|
||||
|
||||
$state = $this->server->getRequest()->query->get('state', null);
|
||||
if ($this->server->stateParamRequired() === true && is_null($state)) {
|
||||
throw new Exception\InvalidRequestException('state', $redirectUri);
|
||||
}
|
||||
|
||||
$responseType = $this->server->getRequest()->query->get('response_type', null);
|
||||
if (is_null($responseType)) {
|
||||
throw new Exception\InvalidRequestException('response_type', $redirectUri);
|
||||
}
|
||||
|
||||
// Ensure response type is one that is recognised
|
||||
if (!in_array($responseType, $this->server->getResponseTypes())) {
|
||||
throw new Exception\UnsupportedResponseTypeException($responseType, $redirectUri);
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scopeParam = $this->server->getRequest()->query->get('scope', '');
|
||||
$scopes = $this->validateScopes($scopeParam, $client, $redirectUri);
|
||||
|
||||
return [
|
||||
'client' => $client,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'state' => $state,
|
||||
'response_type' => $responseType,
|
||||
'scopes' => $scopes
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a new authorize request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authParams The authorize request $_GET parameters
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
public function newAuthorizeRequest($type, $typeId, $authParams = [])
|
||||
{
|
||||
// Create a new session
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setOwner($type, $typeId);
|
||||
$session->associateClient($authParams['client']);
|
||||
$session->save();
|
||||
|
||||
// Create a new auth code
|
||||
$authCode = new AuthCodeEntity($this->server);
|
||||
$authCode->setId(SecureKey::generate());
|
||||
$authCode->setRedirectUri($authParams['redirect_uri']);
|
||||
$authCode->setExpireTime(time() + $this->authTokenTTL);
|
||||
|
||||
foreach ($authParams['scopes'] as $scope) {
|
||||
$authCode->associateScope($scope);
|
||||
}
|
||||
|
||||
$authCode->setSession($session);
|
||||
$authCode->save();
|
||||
|
||||
return $authCode->generateRedirectUri($authParams['state']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the auth code grant
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow()
|
||||
{
|
||||
// Get the required params
|
||||
$clientId = $this->server->getRequest()->request->get('client_id', null);
|
||||
if (is_null($clientId)) {
|
||||
$clientId = $this->server->getRequest()->getUser();
|
||||
if (is_null($clientId)) {
|
||||
throw new Exception\InvalidRequestException('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret', null);
|
||||
if (is_null($clientSecret)) {
|
||||
$clientSecret = $this->server->getRequest()->getPassword();
|
||||
if (is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
}
|
||||
|
||||
$redirectUri = $this->server->getRequest()->request->get('redirect_uri', null);
|
||||
if (is_null($redirectUri)) {
|
||||
throw new Exception\InvalidRequestException('redirect_uri');
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
$redirectUri,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidClientException();
|
||||
}
|
||||
|
||||
// Validate the auth code
|
||||
$authCode = $this->server->getRequest()->request->get('code', null);
|
||||
if (is_null($authCode)) {
|
||||
throw new Exception\InvalidRequestException('code');
|
||||
}
|
||||
|
||||
$code = $this->server->getAuthCodeStorage()->get($authCode);
|
||||
if (($code instanceof AuthCodeEntity) === false) {
|
||||
throw new Exception\InvalidRequestException('code');
|
||||
}
|
||||
|
||||
// Ensure the auth code hasn't expired
|
||||
if ($code->isExpired() === true) {
|
||||
throw new Exception\InvalidRequestException('code');
|
||||
}
|
||||
|
||||
// Check redirect URI presented matches redirect URI originally used in authorize request
|
||||
if ($code->getRedirectUri() !== $redirectUri) {
|
||||
throw new Exception\InvalidRequestException('redirect_uri');
|
||||
}
|
||||
|
||||
$session = $code->getSession();
|
||||
$session->associateClient($client);
|
||||
|
||||
$authCodeScopes = $code->getScopes();
|
||||
|
||||
// Generate the access token
|
||||
$accessToken = new AccessTokenEntity($this->server);
|
||||
$accessToken->setId(SecureKey::generate());
|
||||
$accessToken->setExpireTime($this->getAccessTokenTTL() + time());
|
||||
|
||||
foreach ($authCodeScopes as $authCodeScope) {
|
||||
$session->associateScope($authCodeScope);
|
||||
}
|
||||
|
||||
foreach ($session->getScopes() as $scope) {
|
||||
$accessToken->associateScope($scope);
|
||||
}
|
||||
|
||||
$this->server->getTokenType()->setSession($session);
|
||||
$this->server->getTokenType()->setParam('access_token', $accessToken->getId());
|
||||
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->server->hasGrantType('refresh_token')) {
|
||||
$refreshToken = new RefreshTokenEntity($this->server);
|
||||
$refreshToken->setId(SecureKey::generate());
|
||||
$refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time());
|
||||
$this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId());
|
||||
}
|
||||
|
||||
// Expire the auth code
|
||||
$code->expire();
|
||||
|
||||
// Save all the things
|
||||
$session->save();
|
||||
$accessToken->setSession($session);
|
||||
$accessToken->save();
|
||||
|
||||
if ($this->server->hasGrantType('refresh_token')) {
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->save();
|
||||
}
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
120
src/Grant/ClientCredentialsGrant.php
Normal file
120
src/Grant/ClientCredentialsGrant.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client credentials grant
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Event;
|
||||
|
||||
/**
|
||||
* Client credentials grant class
|
||||
*/
|
||||
class ClientCredentialsGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'client_credentials';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType = null;
|
||||
|
||||
/**
|
||||
* AuthServer instance
|
||||
* @var AuthServer
|
||||
*/
|
||||
protected $server = null;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL = null;
|
||||
|
||||
/**
|
||||
* Complete the client credentials grant
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow()
|
||||
{
|
||||
// Get the required params
|
||||
$clientId = $this->server->getRequest()->request->get('client_id', null);
|
||||
if (is_null($clientId)) {
|
||||
$clientId = $this->server->getRequest()->getUser();
|
||||
if (is_null($clientId)) {
|
||||
throw new Exception\InvalidRequestException('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret', null);
|
||||
if (is_null($clientSecret)) {
|
||||
$clientSecret = $this->server->getRequest()->getPassword();
|
||||
if (is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
null,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidClientException();
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scopeParam = $this->server->getRequest()->request->get('scope', '');
|
||||
$scopes = $this->validateScopes($scopeParam, $client);
|
||||
|
||||
// Create a new session
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setOwner('client', $client->getId());
|
||||
$session->associateClient($client);
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = new AccessTokenEntity($this->server);
|
||||
$accessToken->setId(SecureKey::generate());
|
||||
$accessToken->setExpireTime($this->getAccessTokenTTL() + time());
|
||||
|
||||
// Associate scopes with the session and access token
|
||||
foreach ($scopes as $scope) {
|
||||
$session->associateScope($scope);
|
||||
}
|
||||
|
||||
foreach ($session->getScopes() as $scope) {
|
||||
$accessToken->associateScope($scope);
|
||||
}
|
||||
|
||||
// Save everything
|
||||
$session->save();
|
||||
$accessToken->setSession($session);
|
||||
$accessToken->save();
|
||||
|
||||
$this->server->getTokenType()->setSession($session);
|
||||
$this->server->getTokenType()->setParam('access_token', $accessToken->getId());
|
||||
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
24
src/Grant/GrantTypeInterface.php
Normal file
24
src/Grant/GrantTypeInterface.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Grant type interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Grant type interface
|
||||
*/
|
||||
interface GrantTypeInterface
|
||||
{
|
||||
/**
|
||||
* Complete the grant flow
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow();
|
||||
}
|
175
src/Grant/PasswordGrant.php
Normal file
175
src/Grant/PasswordGrant.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Password grant
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Event;
|
||||
|
||||
/**
|
||||
* Password grant class
|
||||
*/
|
||||
class PasswordGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* Grant identifier
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier = 'password';
|
||||
|
||||
/**
|
||||
* Response type
|
||||
* @var string
|
||||
*/
|
||||
protected $responseType;
|
||||
|
||||
/**
|
||||
* Callback to authenticate a user's name and password
|
||||
* @var callable
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* Access token expires in override
|
||||
* @var int
|
||||
*/
|
||||
protected $accessTokenTTL;
|
||||
|
||||
/**
|
||||
* Set the callback to verify a user's username and password
|
||||
* @param callable $callback The callback function
|
||||
* @return void
|
||||
*/
|
||||
public function setVerifyCredentialsCallback(callable $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\ServerErrorException('Null or non-callable callback set on Password grant');
|
||||
}
|
||||
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the password grant
|
||||
* @return array
|
||||
*/
|
||||
public function completeFlow()
|
||||
{
|
||||
// Get the required params
|
||||
$clientId = $this->server->getRequest()->request->get('client_id', null);
|
||||
if (is_null($clientId)) {
|
||||
$clientId = $this->server->getRequest()->getUser();
|
||||
if (is_null($clientId)) {
|
||||
throw new Exception\InvalidRequestException('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret', null);
|
||||
if (is_null($clientSecret)) {
|
||||
$clientSecret = $this->server->getRequest()->getPassword();
|
||||
if (is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
null,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidClientException();
|
||||
}
|
||||
|
||||
$username = $this->server->getRequest()->request->get('username', null);
|
||||
if (is_null($username)) {
|
||||
throw new Exception\InvalidRequestException('username');
|
||||
}
|
||||
|
||||
$password = $this->server->getRequest()->request->get('password', null);
|
||||
if (is_null($password)) {
|
||||
throw new Exception\InvalidRequestException('password');
|
||||
}
|
||||
|
||||
// Check if user's username and password are correct
|
||||
$userId = call_user_func($this->getVerifyCredentialsCallback(), $username, $password);
|
||||
|
||||
if ($userId === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\UserAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidCredentialsException();
|
||||
}
|
||||
|
||||
// Validate any scopes that are in the request
|
||||
$scopeParam = $this->server->getRequest()->request->get('scope', '');
|
||||
$scopes = $this->validateScopes($scopeParam, $client);
|
||||
|
||||
// Create a new session
|
||||
$session = new SessionEntity($this->server);
|
||||
$session->setOwner('user', $userId);
|
||||
$session->associateClient($client);
|
||||
|
||||
// Generate an access token
|
||||
$accessToken = new AccessTokenEntity($this->server);
|
||||
$accessToken->setId(SecureKey::generate());
|
||||
$accessToken->setExpireTime($this->getAccessTokenTTL() + time());
|
||||
|
||||
// Associate scopes with the session and access token
|
||||
foreach ($scopes as $scope) {
|
||||
$session->associateScope($scope);
|
||||
}
|
||||
|
||||
foreach ($session->getScopes() as $scope) {
|
||||
$accessToken->associateScope($scope);
|
||||
}
|
||||
|
||||
$this->server->getTokenType()->setSession($session);
|
||||
$this->server->getTokenType()->setParam('access_token', $accessToken->getId());
|
||||
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
|
||||
|
||||
// Associate a refresh token if set
|
||||
if ($this->server->hasGrantType('refresh_token')) {
|
||||
$refreshToken = new RefreshTokenEntity($this->server);
|
||||
$refreshToken->setId(SecureKey::generate());
|
||||
$refreshToken->setExpireTime($this->server->getGrantType('refresh_token')->getRefreshTokenTTL() + time());
|
||||
$this->server->getTokenType()->setParam('refresh_token', $refreshToken->getId());
|
||||
}
|
||||
|
||||
// Save everything
|
||||
$session->save();
|
||||
$accessToken->setSession($session);
|
||||
$accessToken->save();
|
||||
|
||||
if ($this->server->hasGrantType('refresh_token')) {
|
||||
$refreshToken->setAccessToken($accessToken);
|
||||
$refreshToken->save();
|
||||
}
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
160
src/Grant/RefreshTokenGrant.php
Normal file
160
src/Grant/RefreshTokenGrant.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token grant
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Request;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use League\OAuth2\Server\Util\SecureKey;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\ClientEntity;
|
||||
use League\OAuth2\Server\Event;
|
||||
|
||||
/**
|
||||
* Referesh token grant
|
||||
*/
|
||||
class RefreshTokenGrant extends AbstractGrant
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $identifier = 'refresh_token';
|
||||
|
||||
/**
|
||||
* Refresh token TTL (default = 604800 | 1 week)
|
||||
* @var integer
|
||||
*/
|
||||
protected $refreshTokenTTL = 604800;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function completeFlow()
|
||||
{
|
||||
$clientId = $this->server->getRequest()->request->get('client_id', null);
|
||||
if (is_null($clientId)) {
|
||||
$clientId = $this->server->getRequest()->getUser();
|
||||
if (is_null($clientId)) {
|
||||
throw new Exception\InvalidRequestException('client_id');
|
||||
}
|
||||
}
|
||||
|
||||
$clientSecret = $this->server->getRequest()->request->get('client_secret', null);
|
||||
if (is_null($clientSecret)) {
|
||||
$clientSecret = $this->server->getRequest()->getPassword();
|
||||
if (is_null($clientSecret)) {
|
||||
throw new Exception\InvalidRequestException('client_secret');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate client ID and client secret
|
||||
$client = $this->server->getClientStorage()->get(
|
||||
$clientId,
|
||||
$clientSecret,
|
||||
null,
|
||||
$this->getIdentifier()
|
||||
);
|
||||
|
||||
if (($client instanceof ClientEntity) === false) {
|
||||
$this->server->getEventEmitter()->emit(new Event\ClientAuthenticationFailedEvent($this->server->getRequest()));
|
||||
throw new Exception\InvalidClientException();
|
||||
}
|
||||
|
||||
$oldRefreshTokenParam = $this->server->getRequest()->request->get('refresh_token', null);
|
||||
if ($oldRefreshTokenParam === null) {
|
||||
throw new Exception\InvalidRequestException('refresh_token');
|
||||
}
|
||||
|
||||
// Validate refresh token
|
||||
$oldRefreshToken = $this->server->getRefreshTokenStorage()->get($oldRefreshTokenParam);
|
||||
|
||||
if (($oldRefreshToken instanceof RefreshTokenEntity) === false) {
|
||||
throw new Exception\InvalidRefreshException();
|
||||
}
|
||||
|
||||
$oldAccessToken = $oldRefreshToken->getAccessToken();
|
||||
|
||||
// Get the scopes for the original session
|
||||
$session = $oldAccessToken->getSession();
|
||||
$scopes = $this->formatScopes($session->getScopes());
|
||||
|
||||
// Get and validate any requested scopes
|
||||
$requestedScopesString = $this->server->getRequest()->request->get('scope', '');
|
||||
$requestedScopes = $this->validateScopes($requestedScopesString, $client);
|
||||
|
||||
// If no new scopes are requested then give the access token the original session scopes
|
||||
if (count($requestedScopes) === 0) {
|
||||
$newScopes = $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 ($requestedScopes as $requestedScope) {
|
||||
if (!isset($scopes[$requestedScope->getId()])) {
|
||||
throw new Exception\InvalidScopeException($requestedScope->getId());
|
||||
}
|
||||
}
|
||||
|
||||
$newScopes = $requestedScopes;
|
||||
}
|
||||
|
||||
// Generate a new access token and assign it the correct sessions
|
||||
$newAccessToken = new AccessTokenEntity($this->server);
|
||||
$newAccessToken->setId(SecureKey::generate());
|
||||
$newAccessToken->setExpireTime($this->getAccessTokenTTL() + time());
|
||||
$newAccessToken->setSession($session);
|
||||
|
||||
foreach ($newScopes as $newScope) {
|
||||
$newAccessToken->associateScope($newScope);
|
||||
}
|
||||
|
||||
// Expire the old token and save the new one
|
||||
$oldAccessToken->expire();
|
||||
$newAccessToken->save();
|
||||
|
||||
$this->server->getTokenType()->setSession($session);
|
||||
$this->server->getTokenType()->setParam('access_token', $newAccessToken->getId());
|
||||
$this->server->getTokenType()->setParam('expires_in', $this->getAccessTokenTTL());
|
||||
|
||||
// Expire the old refresh token
|
||||
$oldRefreshToken->expire();
|
||||
|
||||
// Generate a new refresh token
|
||||
$newRefreshToken = new RefreshTokenEntity($this->server);
|
||||
$newRefreshToken->setId(SecureKey::generate());
|
||||
$newRefreshToken->setExpireTime($this->getRefreshTokenTTL() + time());
|
||||
$newRefreshToken->setAccessToken($newAccessToken);
|
||||
$newRefreshToken->save();
|
||||
|
||||
$this->server->getTokenType()->setParam('refresh_token', $newRefreshToken->getId());
|
||||
|
||||
return $this->server->getTokenType()->generateResponse();
|
||||
}
|
||||
}
|
@@ -1,320 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Authentication;
|
||||
|
||||
interface Database
|
||||
{
|
||||
/**
|
||||
* Validate a client
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* # Client ID + redirect URI
|
||||
* SELECT clients.id FROM clients LEFT JOIN client_endpoints ON
|
||||
* client_endpoints.client_id = clients.id WHERE clients.id = $clientId AND
|
||||
* client_endpoints.redirect_uri = $redirectUri
|
||||
*
|
||||
* # Client ID + client secret
|
||||
* SELECT clients.id FROM clients WHERE clients.id = $clientId AND
|
||||
* clients.secret = $clientSecret
|
||||
*
|
||||
* # Client ID + client secret + redirect URI
|
||||
* SELECT clients.id FROM clients LEFT JOIN client_endpoints ON
|
||||
* client_endpoints.client_id = clients.id WHERE clients.id = $clientId AND
|
||||
* clients.secret = $clientSecret AND client_endpoints.redirect_uri =
|
||||
* $redirectUri
|
||||
* </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")
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function validateClient(
|
||||
$clientId,
|
||||
$clientSecret = null,
|
||||
$redirectUri = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a new OAuth session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_sessions (client_id, redirect_uri, owner_type,
|
||||
* owner_id, auth_code, access_token, stage, first_requested, last_updated)
|
||||
* VALUES ($clientId, $redirectUri, $type, $typeId, $authCode,
|
||||
* $accessToken, $stage, UNIX_TIMESTAMP(NOW()), UNIX_TIMESTAMP(NOW()))
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $type The session owner's type (default = "user")
|
||||
* @param string $typeId The session owner's ID (default = "null")
|
||||
* @param string $authCode The authorisation code (default = "null")
|
||||
* @param string $accessToken The access token (default = "null")
|
||||
* @param string $stage The stage of the session (default ="request")
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function newSession(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type = 'user',
|
||||
$typeId = null,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
);
|
||||
|
||||
/**
|
||||
* Update an OAuth session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET auth_code = $authCode, access_token =
|
||||
* $accessToken, stage = $stage, last_updated = UNIX_TIMESTAMP(NOW()) WHERE
|
||||
* id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param string $sessionId The session ID
|
||||
* @param string $authCode The authorisation code (default = "null")
|
||||
* @param string $accessToken The access token (default = "null")
|
||||
* @param string $stage The stage of the session (default ="request")
|
||||
* @return void
|
||||
*/
|
||||
public function updateSession(
|
||||
$sessionId,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
);
|
||||
|
||||
/**
|
||||
* Delete an OAuth session
|
||||
*
|
||||
* <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 $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @return [type] [description]
|
||||
*/
|
||||
public function deleteSession(
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId
|
||||
);
|
||||
|
||||
/**
|
||||
* Validate that an authorisation code is valid
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT id FROM oauth_sessions WHERE client_id = $clientID AND
|
||||
* redirect_uri = $redirectUri AND auth_code = $authCode
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The session ID
|
||||
* [client_id] => (string) The client ID
|
||||
* [redirect_uri] => (string) The redirect URI
|
||||
* [owner_type] => (string) The session owner type
|
||||
* [owner_id] => (string) The session owner's ID
|
||||
* [auth_code] => (string) The authorisation code
|
||||
* [stage] => (string) The session's stage
|
||||
* [first_requested] => (int) Unix timestamp of the time the session was
|
||||
* first generated
|
||||
* [last_updated] => (int) Unix timestamp of the time the session was
|
||||
* last updated
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param string $authCode The authorisation code
|
||||
* @return int|bool Returns the session ID if the auth code
|
||||
* is valid otherwise returns false
|
||||
*/
|
||||
public function validateAuthCode(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$authCode
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the session ID for a given session owner and client combination
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT id FROM oauth_sessions WHERE client_id = $clientId
|
||||
* AND owner_type = $type AND owner_id = $typeId
|
||||
* </code>
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param string $clientId The client ID
|
||||
* @return string|null Return the session ID as an integer if
|
||||
* found otherwise returns false
|
||||
*/
|
||||
public function hasSession(
|
||||
$type,
|
||||
$typeId,
|
||||
$clientId
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the access token for a given session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT access_token FROM oauth_sessions WHERE id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @return string|null Returns the access token as a string if
|
||||
* found otherwise returns null
|
||||
*/
|
||||
public function getAccessToken($sessionId);
|
||||
|
||||
/**
|
||||
* Removes an authorisation code associated with a session
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET auth_code = NULL WHERE id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @return void
|
||||
*/
|
||||
public function removeAuthCode($sessionId);
|
||||
|
||||
/**
|
||||
* Sets a sessions access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_sessions SET access_token = $accessToken WHERE id =
|
||||
* $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The OAuth session ID
|
||||
* @param string $accessToken The access token
|
||||
* @return void
|
||||
*/
|
||||
public function setAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
);
|
||||
|
||||
/**
|
||||
* Associates a session with a scope
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* INSERT INTO oauth_session_scopes (session_id, scope) VALUE ($sessionId,
|
||||
* $scope)
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $scope The scope
|
||||
* @return void
|
||||
*/
|
||||
public function addSessionScope(
|
||||
$sessionId,
|
||||
$scope
|
||||
);
|
||||
|
||||
/**
|
||||
* Return information about a scope
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT * FROM 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
|
||||
* @return array
|
||||
*/
|
||||
public function getScope($scope);
|
||||
|
||||
/**
|
||||
* Associate a session's scopes with an access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* UPDATE oauth_session_scopes SET access_token = $accessToken WHERE
|
||||
* session_id = $sessionId
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @param string $accessToken The access token
|
||||
* @return void
|
||||
*/
|
||||
public function updateSessionScopeAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
);
|
||||
|
||||
/**
|
||||
* Return the scopes associated with an access token
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT scopes.scope, scopes.name, scopes.description FROM
|
||||
* oauth_session_scopes JOIN scopes ON oauth_session_scopes.scope =
|
||||
* scopes.scope WHERE access_token = $accessToken
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [0] => Array
|
||||
* (
|
||||
* [scope] => (string) The scope
|
||||
* [name] => (string) The scope's name
|
||||
* [description] => (string) The scope's description
|
||||
* )
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array
|
||||
*/
|
||||
public function accessTokenScopes($accessToken);
|
||||
}
|
@@ -1,517 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Authentication;
|
||||
|
||||
class OAuthServerClientException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class OAuthServerUserException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class OAuthServerException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Reference to the database abstractor
|
||||
* @var object
|
||||
*/
|
||||
private $_db = null;
|
||||
|
||||
/**
|
||||
* Server configuration
|
||||
* @var array
|
||||
*/
|
||||
private $_config = array(
|
||||
'scope_delimeter' => ',',
|
||||
'access_token_ttl' => null
|
||||
);
|
||||
|
||||
/**
|
||||
* Supported response types
|
||||
* @var array
|
||||
*/
|
||||
private $_responseTypes = array(
|
||||
'code'
|
||||
);
|
||||
|
||||
/**
|
||||
* Supported grant types
|
||||
* @var array
|
||||
*/
|
||||
private $_grantTypes = array(
|
||||
'authorization_code'
|
||||
);
|
||||
|
||||
/**
|
||||
* Exception error codes
|
||||
* @var array
|
||||
*/
|
||||
public $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'
|
||||
);
|
||||
|
||||
/**
|
||||
* Error codes.
|
||||
*
|
||||
* To provide i8ln errors just overwrite the keys
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errors = 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 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.'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param array $options Optional list of options to overwrite the defaults
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if ($options !== null) {
|
||||
$this->options = array_merge($this->_config, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a database abstrator class
|
||||
*
|
||||
* @access public
|
||||
* @param object $db A class that implements OAuth2ServerDatabase
|
||||
* @return void
|
||||
*/
|
||||
public function registerDbAbstractor($db)
|
||||
{
|
||||
$this->_db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check client authorise parameters
|
||||
*
|
||||
* @access public
|
||||
* @param array $authParams Optional array of parsed $_GET keys
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function checkClientAuthoriseParams($authParams = null)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
// Client ID
|
||||
if ( ! isset($authParams['client_id']) && ! isset($_GET['client_id'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_id'] = (isset($authParams['client_id'])) ? $authParams['client_id'] : $_GET['client_id'];
|
||||
|
||||
}
|
||||
|
||||
// Redirect URI
|
||||
if ( ! isset($authParams['redirect_uri']) && ! isset($_GET['redirect_uri'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? $authParams['redirect_uri'] : $_GET['redirect_uri'];
|
||||
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->_dbCall('validateClient', $params['client_id'], null, $params['redirect_uri']);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['invalid_client'], 8);
|
||||
}
|
||||
|
||||
// Response type
|
||||
if ( ! isset($authParams['response_type']) && ! isset($_GET['response_type'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'response_type'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['response_type'] = (isset($authParams['response_type'])) ? $authParams['response_type'] : $_GET['response_type'];
|
||||
|
||||
// Ensure response type is one that is recognised
|
||||
if ( ! in_array($params['response_type'], $this->_responseTypes)) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['unsupported_response_type'], 3);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Get and validate scopes
|
||||
if (isset($authParams['scope']) || isset($_GET['scope'])) {
|
||||
|
||||
$scopes = (isset($_GET['scope'])) ? $_GET['scope'] : $authParams['scope'];
|
||||
|
||||
$scopes = explode($this->_config['scope_delimeter'], $scopes);
|
||||
|
||||
// Remove any junk scopes
|
||||
for ($i = 0; $i < count($scopes); $i++) {
|
||||
$scopes[$i] = trim($scopes[$i]);
|
||||
|
||||
if ($scopes[$i] === '') {
|
||||
unset($scopes[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($scopes) === 0) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'scope'), 0);
|
||||
}
|
||||
|
||||
$params['scopes'] = array();
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
|
||||
$scopeDetails = $this->_dbCall('getScope', $scope);
|
||||
|
||||
if ($scopeDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_scope'], $scope), 4);
|
||||
|
||||
}
|
||||
|
||||
$params['scopes'][] = $scopeDetails;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a new authorise request
|
||||
*
|
||||
* @param string $type The session owner's type
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param array $authoriseParams The authorise request $_GET parameters
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
public function newAuthoriseRequest($type, $typeId, $authoriseParams)
|
||||
{
|
||||
// Remove any old sessions the user might have
|
||||
$this->_dbCall('deleteSession',
|
||||
$authoriseParams['client_id'],
|
||||
$type,
|
||||
$typeId
|
||||
);
|
||||
|
||||
// Create the new auth code
|
||||
$authCode = $this->newAuthCode(
|
||||
$authoriseParams['client_id'],
|
||||
'user',
|
||||
$typeId,
|
||||
$authoriseParams['redirect_uri'],
|
||||
$authoriseParams['scopes']
|
||||
);
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique code
|
||||
*
|
||||
* Generate a unique code for an authorisation code, or token
|
||||
*
|
||||
* @return string A unique code
|
||||
*/
|
||||
private function generateCode()
|
||||
{
|
||||
return sha1(uniqid(microtime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new authorisation code
|
||||
*
|
||||
* @param string $clientId The client ID
|
||||
* @param string $type The type of the owner of the session
|
||||
* @param string $typeId The session owner's ID
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param array $scopes The requested scopes
|
||||
* @param string $accessToken The access token (default = null)
|
||||
* @return string An authorisation code
|
||||
*/
|
||||
private function newAuthCode($clientId, $type, $typeId, $redirectUri, $scopes = array(), $accessToken = null)
|
||||
{
|
||||
$authCode = $this->generateCode();
|
||||
|
||||
// If an access token exists then update the existing session with the
|
||||
// new authorisation code otherwise create a new session
|
||||
if ($accessToken !== null) {
|
||||
|
||||
$this->_dbCall('updateSession',
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId,
|
||||
$authCode,
|
||||
$accessToken,
|
||||
'request'
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
// Delete any existing sessions just to be sure
|
||||
$this->_dbCall('deleteSession', $clientId, $type, $typeId);
|
||||
|
||||
// Create a new session
|
||||
$sessionId = $this->_dbCall('newSession',
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type,
|
||||
$typeId,
|
||||
$authCode,
|
||||
null,
|
||||
null,
|
||||
'request'
|
||||
);
|
||||
|
||||
// Add the scopes
|
||||
foreach ($scopes as $key => $scope) {
|
||||
|
||||
$this->_dbCall('addSessionScope', $sessionId, $scope['scope']);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $authCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an access token
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
* @param array $authParams Optional array of parsed $_POST keys
|
||||
*
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
public function issueAccessToken($authParams = null)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
if ( ! isset($authParams['grant_type']) && ! isset($_POST['grant_type'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'grant_type'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['grant_type'] = (isset($authParams['grant_type'])) ? $authParams['grant_type'] : $_POST['grant_type'];
|
||||
|
||||
// Ensure grant type is one that is recognised
|
||||
if ( ! in_array($params['grant_type'], $this->_grantTypes)) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['unsupported_grant_type'], 7);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch ($params['grant_type'])
|
||||
{
|
||||
|
||||
case 'authorization_code': // Authorization code grant
|
||||
return $this->completeAuthCodeGrant($authParams, $params);
|
||||
break;
|
||||
|
||||
case 'refresh_token': // Refresh token
|
||||
case 'password': // Resource owner password credentials grant
|
||||
case 'client_credentials': // Client credentials grant
|
||||
default: // Unsupported
|
||||
throw new OAuthServerException($this->errors['server_error'] . 'Tried to process an unsuppported grant type.', 5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the authorisation code grant
|
||||
*
|
||||
* @access private
|
||||
*
|
||||
* @param array $authParams Array of parsed $_POST keys
|
||||
* @param array $params Generated parameters from issueAccessToken()
|
||||
*
|
||||
* @return array Authorise request parameters
|
||||
*/
|
||||
private function completeAuthCodeGrant($authParams = array(), $params = array())
|
||||
{
|
||||
// Client ID
|
||||
if ( ! isset($authParams['client_id']) && ! isset($_POST['client_id'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_id'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_id'] = (isset($authParams['client_id'])) ? $authParams['client_id'] : $_POST['client_id'];
|
||||
|
||||
}
|
||||
|
||||
// Client secret
|
||||
if ( ! isset($authParams['client_secret']) && ! isset($_POST['client_secret'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'client_secret'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['client_secret'] = (isset($authParams['client_secret'])) ? $authParams['client_secret'] : $_POST['client_secret'];
|
||||
|
||||
}
|
||||
|
||||
// Redirect URI
|
||||
if ( ! isset($authParams['redirect_uri']) && ! isset($_POST['redirect_uri'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'redirect_uri'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['redirect_uri'] = (isset($authParams['redirect_uri'])) ? $authParams['redirect_uri'] : $_POST['redirect_uri'];
|
||||
|
||||
}
|
||||
|
||||
// Validate client ID and redirect URI
|
||||
$clientDetails = $this->_dbCall('validateClient',
|
||||
$params['client_id'],
|
||||
$params['client_secret'],
|
||||
$params['redirect_uri']
|
||||
);
|
||||
|
||||
if ($clientDetails === false) {
|
||||
|
||||
throw new OAuthServerClientException($this->errors['invalid_client'], 8);
|
||||
}
|
||||
|
||||
// The authorization code
|
||||
if ( ! isset($authParams['code']) && ! isset($_POST['code'])) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_request'], 'code'), 0);
|
||||
|
||||
} else {
|
||||
|
||||
$params['code'] = (isset($authParams['code'])) ? $authParams['code'] : $_POST['code'];
|
||||
|
||||
}
|
||||
|
||||
// Verify the authorization code matches the client_id and the
|
||||
// request_uri
|
||||
$session = $this->_dbCall('validateAuthCode',
|
||||
$params['client_id'],
|
||||
$params['redirect_uri'],
|
||||
$params['code']
|
||||
);
|
||||
|
||||
if ( ! $session) {
|
||||
|
||||
throw new OAuthServerClientException(sprintf($this->errors['invalid_grant'], 'code'), 9);
|
||||
|
||||
} else {
|
||||
|
||||
// A session ID was returned so update it with an access token,
|
||||
// remove the authorisation code, change the stage to 'granted'
|
||||
|
||||
$accessToken = $this->generateCode();
|
||||
|
||||
$accessTokenExpires = ($this->_config['access_token_ttl'] === null) ? null : time() + $this->_config['access_token_ttl'];
|
||||
|
||||
$this->_dbCall('updateSession',
|
||||
$session['id'],
|
||||
null,
|
||||
$accessToken,
|
||||
$accessTokenExpires,
|
||||
'granted'
|
||||
);
|
||||
|
||||
// Update the session's scopes to reference the access token
|
||||
$this->_dbCall('updateSessionScopeAccessToken',
|
||||
$session['id'],
|
||||
$accessToken
|
||||
);
|
||||
|
||||
return array(
|
||||
'access_token' => $accessToken,
|
||||
'token_type' => 'bearer',
|
||||
'expires_in' => $this->_config['access_token_ttl']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the redirect uri with appended params
|
||||
*
|
||||
* @param string $redirectUri The redirect URI
|
||||
* @param array $params The parameters to be appended to the URL
|
||||
* @param string $query_delimeter The query string delimiter (default: ?)
|
||||
*
|
||||
* @return string The updated redirect URI
|
||||
*/
|
||||
public function redirectUri($redirectUri, $params = array(), $queryDelimeter = '?')
|
||||
{
|
||||
|
||||
if (strstr($redirectUri, $queryDelimeter)) {
|
||||
|
||||
$redirectUri = $redirectUri . '&' . http_build_query($params);
|
||||
|
||||
} else {
|
||||
|
||||
$redirectUri = $redirectUri . $queryDelimeter . http_build_query($params);
|
||||
|
||||
}
|
||||
|
||||
return $redirectUri;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Call database methods from the abstractor
|
||||
*
|
||||
* @return mixed The query result
|
||||
*/
|
||||
private function _dbCall()
|
||||
{
|
||||
if ($this->_db === null) {
|
||||
throw new OAuthServerException('No registered database abstractor');
|
||||
}
|
||||
|
||||
if ( ! $this->_db instanceof Database) {
|
||||
throw new OAuthServerException('Registered database abstractor is not an instance of Oauth2\Authentication\Database');
|
||||
}
|
||||
|
||||
$args = func_get_args();
|
||||
$method = $args[0];
|
||||
unset($args[0]);
|
||||
$params = array_values($args);
|
||||
|
||||
return call_user_func_array(array($this->_db, $method), $params);
|
||||
}
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Resource;
|
||||
|
||||
interface Database
|
||||
{
|
||||
/**
|
||||
* Validate an access token and return the session details.
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT id, owner_type, owner_id FROM oauth_sessions WHERE access_token =
|
||||
* $accessToken AND stage = 'granted' AND
|
||||
* access_token_expires > UNIX_TIMESTAMP(now())
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [id] => (int) The session ID
|
||||
* [owner_type] => (string) The session owner type
|
||||
* [owner_id] => (string) The session owner's ID
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param string $accessToken The access token
|
||||
* @return array|bool Return an array on success or false on failure
|
||||
*/
|
||||
public function validateAccessToken($accessToken);
|
||||
|
||||
/**
|
||||
* Returns the scopes that the session is authorised with.
|
||||
*
|
||||
* Database query:
|
||||
*
|
||||
* <code>
|
||||
* SELECT scope FROM oauth_session_scopes WHERE access_token =
|
||||
* '291dca1c74900f5f252de351e0105aa3fc91b90b'
|
||||
* </code>
|
||||
*
|
||||
* Response:
|
||||
*
|
||||
* <code>
|
||||
* Array
|
||||
* (
|
||||
* [0] => (string) A scope
|
||||
* [1] => (string) Another scope
|
||||
* ...
|
||||
* )
|
||||
* </code>
|
||||
*
|
||||
* @param int $sessionId The session ID
|
||||
* @return array A list of scopes
|
||||
*/
|
||||
public function sessionScopes($sessionId);
|
||||
}
|
@@ -1,225 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Oauth2\Resource;
|
||||
|
||||
class OAuthResourceServerException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Reference to the database abstractor
|
||||
* @var object
|
||||
*/
|
||||
private $_db = null;
|
||||
|
||||
/**
|
||||
* The access token.
|
||||
* @access private
|
||||
*/
|
||||
private $_accessToken = null;
|
||||
|
||||
/**
|
||||
* The scopes the access token has access to.
|
||||
* @access private
|
||||
*/
|
||||
private $_scopes = array();
|
||||
|
||||
/**
|
||||
* The type of owner of the access token.
|
||||
* @access private
|
||||
*/
|
||||
private $_type = null;
|
||||
|
||||
/**
|
||||
* The ID of the owner of the access token.
|
||||
* @access private
|
||||
*/
|
||||
private $_typeId = null;
|
||||
|
||||
/**
|
||||
* Server configuration
|
||||
* @var array
|
||||
*/
|
||||
private $_config = array(
|
||||
'token_key' => 'oauth_token'
|
||||
);
|
||||
|
||||
/**
|
||||
* Error codes.
|
||||
*
|
||||
* To provide i8ln errors just overwrite the keys
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $errors = array(
|
||||
'missing_access_token' => 'An access token was not presented with the request',
|
||||
'invalid_access_token' => 'The access token is not registered with the resource server'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($options = null)
|
||||
{
|
||||
if ($options !== null) {
|
||||
$this->config = array_merge($this->config, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method to test if access token represents a particular owner type
|
||||
* @param string $method The method name
|
||||
* @param mixed $arguements The method arguements
|
||||
* @return bool If method is valid, and access token is owned by the requested party then true,
|
||||
*/
|
||||
public function __call($method, $arguements = null)
|
||||
{
|
||||
if (substr($method, 0, 2) === 'is') {
|
||||
|
||||
if ($this->_type === strtolower(substr($method, 2))) {
|
||||
return $this->_typeId;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
trigger_error('Call to undefined function ' . $method . '()');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a database abstrator class
|
||||
*
|
||||
* @access public
|
||||
* @param object $db A class that implements OAuth2ServerDatabase
|
||||
* @return void
|
||||
*/
|
||||
public function registerDbAbstractor($db)
|
||||
{
|
||||
$this->_db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init function
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$accessToken = null;
|
||||
|
||||
// Try and get the access token via an access_token or oauth_token parameter
|
||||
switch ($_SERVER['REQUEST_METHOD'])
|
||||
{
|
||||
case 'POST':
|
||||
$accessToken = isset($_POST[$this->_config['token_key']]) ? $_POST[$this->_config['token_key']] : null;
|
||||
break;
|
||||
|
||||
default:
|
||||
$accessToken = isset($_GET[$this->_config['token_key']]) ? $_GET[$this->_config['token_key']] : null;
|
||||
break;
|
||||
}
|
||||
|
||||
// Try and get an access token from the auth header
|
||||
if (function_exists('getallheaders')) {
|
||||
|
||||
$headers = getallheaders();
|
||||
|
||||
if (isset($headers['Authorization'])) {
|
||||
|
||||
$rawToken = trim(str_replace('Bearer', '', $headers['Authorization']));
|
||||
|
||||
if ( ! empty($rawToken)) {
|
||||
$accessToken = base64_decode($rawToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($accessToken) {
|
||||
|
||||
$result = $this->_dbCall('validateAccessToken', $accessToken);
|
||||
|
||||
if ($result === false) {
|
||||
|
||||
throw new OAuthResourceServerException($this->errors['invalid_access_token']);
|
||||
|
||||
} else {
|
||||
|
||||
$this->_accessToken = $accessToken;
|
||||
$this->_type = $result['owner_type'];
|
||||
$this->_typeId = $result['owner_id'];
|
||||
|
||||
// Get the scopes
|
||||
$this->_scopes = $this->_dbCall('sessionScopes', $result['id']);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
throw new OAuthResourceServerException($this->errors['missing_access_token']);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the access token has a specific scope
|
||||
*
|
||||
* @param mixed $scopes Scope(s) to check
|
||||
*
|
||||
* @access public
|
||||
* @return string|bool
|
||||
*/
|
||||
public function hasScope($scopes)
|
||||
{
|
||||
if (is_string($scopes)) {
|
||||
|
||||
if (in_array($scopes, $this->_scopes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} elseif (is_array($scopes)) {
|
||||
|
||||
foreach ($scopes as $scope) {
|
||||
|
||||
if ( ! in_array($scope, $this->_scopes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call database methods from the abstractor
|
||||
*
|
||||
* @return mixed The query result
|
||||
*/
|
||||
private function _dbCall()
|
||||
{
|
||||
if ($this->_db === null) {
|
||||
throw new OAuthResourceServerException('No registered database abstractor');
|
||||
}
|
||||
|
||||
if ( ! $this->_db instanceof Database) {
|
||||
throw new OAuthResourceServerException('Registered database abstractor is not an instance of Oauth2\Resource\Database');
|
||||
}
|
||||
|
||||
$args = func_get_args();
|
||||
$method = $args[0];
|
||||
unset($args[0]);
|
||||
$params = array_values($args);
|
||||
|
||||
return call_user_func_array(array($this->_db, $method), $params);
|
||||
}
|
||||
}
|
138
src/ResourceServer.php
Normal file
138
src/ResourceServer.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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;
|
||||
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\TokenType\Bearer;
|
||||
use League\OAuth2\Server\Exception;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 Resource Server
|
||||
*/
|
||||
class ResourceServer extends AbstractServer
|
||||
{
|
||||
/**
|
||||
* The access token
|
||||
* @var \League\OAuth2\Server\Entity\AccessTokenEntity
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* The query string key which is used by clients to present the access token (default: access_token)
|
||||
* @var string
|
||||
*/
|
||||
protected $tokenKey = 'access_token';
|
||||
|
||||
/**
|
||||
* Initialise the resource server
|
||||
* @param SessionInterface $sessionStorage
|
||||
* @param AccessTokenInteface $accessTokenStorage
|
||||
* @param ClientInterface $clientStorage
|
||||
* @param ScopeInterface $scopeStorage
|
||||
* @return self
|
||||
*/
|
||||
public function __construct(
|
||||
SessionInterface $sessionStorage,
|
||||
AccessTokenInterface $accessTokenStorage,
|
||||
ClientInterface $clientStorage,
|
||||
ScopeInterface $scopeStorage
|
||||
) {
|
||||
$this->setSessionStorage($sessionStorage);
|
||||
$this->setAccessTokenStorage($accessTokenStorage);
|
||||
$this->setClientStorage($clientStorage);
|
||||
$this->setScopeStorage($scopeStorage);
|
||||
|
||||
// Set Bearer as the default token type
|
||||
$this->setTokenType(new Bearer);
|
||||
|
||||
parent::__construct();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the query string key for the access token.
|
||||
* @param $key The new query string key
|
||||
* @return self
|
||||
*/
|
||||
public function setIdKey($key)
|
||||
{
|
||||
$this->tokenKey = $key;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the access token
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->accessToken->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the access token is valid or not
|
||||
* @param $headersOnly Limit Access Token to Authorization header only
|
||||
* @return bool
|
||||
*/
|
||||
public function isValidRequest($headersOnly = true, $accessToken = null)
|
||||
{
|
||||
$accessTokenString = ($accessToken !== null)
|
||||
? $accessToken
|
||||
: $this->determineAccessToken($headersOnly);
|
||||
|
||||
// Set the access token
|
||||
$this->accessToken = $this->getAccessTokenStorage()->get($accessTokenString);
|
||||
|
||||
// Ensure the access token exists
|
||||
if (!$this->accessToken instanceof AccessTokenEntity) {
|
||||
throw new Exception\AccessDeniedException;
|
||||
}
|
||||
|
||||
// Check the access token hasn't expired
|
||||
// Ensure the auth code hasn't expired
|
||||
if ($this->accessToken->isExpired() === true) {
|
||||
throw new Exception\AccessDeniedException;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if ($this->getRequest()->headers->get('Authorization') !== null) {
|
||||
$accessToken = $this->getTokenType()->determineAccessTokenInHeader($this->getRequest());
|
||||
} elseif ($headersOnly === false) {
|
||||
$accessToken = ($this->getRequest()->server->get('REQUEST_METHOD') === 'GET')
|
||||
? $this->getRequest()->query->get($this->tokenKey)
|
||||
: $this->getRequest()->request->get($this->tokenKey);
|
||||
}
|
||||
|
||||
if (empty($accessToken)) {
|
||||
throw new Exception\InvalidRequestException('access token');
|
||||
}
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
}
|
46
src/Storage/AbstractStorage.php
Normal file
46
src/Storage/AbstractStorage.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 abstract storage
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\AbstractServer;
|
||||
|
||||
/**
|
||||
* Abstract storage class
|
||||
*/
|
||||
abstract class AbstractStorage implements StorageInterface
|
||||
{
|
||||
/**
|
||||
* Server
|
||||
* @var \League\OAuth2\Server\AbstractServer $server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Set the server
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
*/
|
||||
public function setServer(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the server
|
||||
* @return \League\OAuth2\Server\AbstractServer
|
||||
*/
|
||||
protected function getServer()
|
||||
{
|
||||
return $this->server;
|
||||
}
|
||||
}
|
61
src/Storage/AccessTokenInterface.php
Normal file
61
src/Storage/AccessTokenInterface.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Access token storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AbstractTokenEntity;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
/**
|
||||
* Access token interface
|
||||
*/
|
||||
interface AccessTokenInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Get an instance of Entity\AccessTokenEntity
|
||||
* @param string $token The access token
|
||||
* @return \League\OAuth2\Server\Entity\AccessTokenEntity
|
||||
*/
|
||||
public function get($token);
|
||||
|
||||
/**
|
||||
* Get the scopes for an access token
|
||||
* @param \League\OAuth2\Server\Entity\AbstractTokenEntity $token The access token
|
||||
* @return array Array of \League\OAuth2\Server\Entity\ScopeEntity
|
||||
*/
|
||||
public function getScopes(AbstractTokenEntity $token);
|
||||
|
||||
/**
|
||||
* Creates a new access token
|
||||
* @param string $token The access token
|
||||
* @param integer $expireTime The expire time expressed as a unix timestamp
|
||||
* @param string|integer $sessionId The session ID
|
||||
* @return \League\OAuth2\Server\Entity\AccessToken
|
||||
*/
|
||||
public function create($token, $expireTime, $sessionId);
|
||||
|
||||
/**
|
||||
* Associate a scope with an acess token
|
||||
* @param \League\OAuth2\Server\Entity\AbstractTokenEntity $token The access token
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope
|
||||
* @return void
|
||||
*/
|
||||
public function associateScope(AbstractTokenEntity $token, ScopeEntity $scope);
|
||||
|
||||
/**
|
||||
* Delete an access token
|
||||
* @param \League\OAuth2\Server\Entity\AbstractTokenEntity $token The access token to delete
|
||||
* @return void
|
||||
*/
|
||||
public function delete(AbstractTokenEntity $token);
|
||||
}
|
61
src/Storage/AuthCodeInterface.php
Normal file
61
src/Storage/AuthCodeInterface.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Auth code storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
/**
|
||||
* Auth code storage interface
|
||||
*/
|
||||
interface AuthCodeInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Get the auth code
|
||||
* @param string $code
|
||||
* @return \League\OAuth2\Server\Entity\AuthCodeEntity
|
||||
*/
|
||||
public function get($code);
|
||||
|
||||
/**
|
||||
* Create an auth code.
|
||||
* @param string $token The token ID
|
||||
* @param integer $expireTime Token expire time
|
||||
* @param integer $sessionId Session identifier
|
||||
* @param string $redirectUri Client redirect uri
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function create($token, $expireTime, $sessionId, $redirectUri);
|
||||
|
||||
/**
|
||||
* Get the scopes for an access token
|
||||
* @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The auth code
|
||||
* @return array Array of \League\OAuth2\Server\Entity\ScopeEntity
|
||||
*/
|
||||
public function getScopes(AuthCodeEntity $token);
|
||||
|
||||
/**
|
||||
* Associate a scope with an acess token
|
||||
* @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The auth code
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope
|
||||
* @return void
|
||||
*/
|
||||
public function associateScope(AuthCodeEntity $token, ScopeEntity $scope);
|
||||
|
||||
/**
|
||||
* Delete an access token
|
||||
* @param \League\OAuth2\Server\Entity\AuthCodeEntity $token The access token to delete
|
||||
* @return void
|
||||
*/
|
||||
public function delete(AuthCodeEntity $token);
|
||||
}
|
37
src/Storage/ClientInterface.php
Normal file
37
src/Storage/ClientInterface.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Client storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\SessionEntity;
|
||||
|
||||
/**
|
||||
* Client storage interface
|
||||
*/
|
||||
interface ClientInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Validate a client
|
||||
* @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 (default = "null")
|
||||
* @return League\OAuth2\Server\Entity\ClientEntity
|
||||
*/
|
||||
public function get($clientId, $clientSecret = null, $redirectUri = null, $grantType = null);
|
||||
|
||||
/**
|
||||
* Get the client associated with a session
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity $session The session
|
||||
* @return \League\OAuth2\Server\Entity\ClientEntity
|
||||
*/
|
||||
public function getBySession(SessionEntity $session);
|
||||
}
|
43
src/Storage/RefreshTokenInterface.php
Normal file
43
src/Storage/RefreshTokenInterface.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Refresh token storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\RefreshTokenEntity;
|
||||
|
||||
/**
|
||||
* Refresh token interface
|
||||
*/
|
||||
interface RefreshTokenInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Return a new instance of \League\OAuth2\Server\Entity\RefreshTokenEntity
|
||||
* @param string $token
|
||||
* @return \League\OAuth2\Server\Entity\RefreshTokenEntity
|
||||
*/
|
||||
public function get($token);
|
||||
|
||||
/**
|
||||
* Create a new refresh token_name
|
||||
* @param string $token
|
||||
* @param integer $expireTime
|
||||
* @param string $accessToken
|
||||
* @return \League\OAuth2\Server\Entity\RefreshTokenEntity
|
||||
*/
|
||||
public function create($token, $expireTime, $accessToken);
|
||||
|
||||
/**
|
||||
* Delete the refresh token
|
||||
* @param \League\OAuth2\Server\Entity\RefreshTokenEntity $token
|
||||
* @return void
|
||||
*/
|
||||
public function delete(RefreshTokenEntity $token);
|
||||
}
|
27
src/Storage/ScopeInterface.php
Normal file
27
src/Storage/ScopeInterface.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Scope storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Scope interface
|
||||
*/
|
||||
interface ScopeInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Return information about a scope
|
||||
* @param string $scope The scope
|
||||
* @param string $grantType The grant type used in the request (default = "null")
|
||||
* @param string $clientId The client sending the request (default = "null")
|
||||
* @return \League\OAuth2\Server\Entity\ScopeEntity
|
||||
*/
|
||||
public function get($scope, $grantType = null, $clientId = null);
|
||||
}
|
62
src/Storage/SessionInterface.php
Normal file
62
src/Storage/SessionInterface.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Session storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Entity\AccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
|
||||
/**
|
||||
* Session storage interface
|
||||
*/
|
||||
interface SessionInterface extends StorageInterface
|
||||
{
|
||||
/**
|
||||
* Get a session from an access token
|
||||
* @param \League\OAuth2\Server\Entity\AccessTokenEntity $accessToken The access token
|
||||
* @return \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
public function getByAccessToken(AccessTokenEntity $accessToken);
|
||||
|
||||
/**
|
||||
* Get a session from an auth code
|
||||
* @param \League\OAuth2\Server\Entity\AuthCodeEntity $authCode The auth code
|
||||
* @return \League\OAuth2\Server\Entity\SessionEntity
|
||||
*/
|
||||
public function getByAuthCode(AuthCodeEntity $authCode);
|
||||
|
||||
/**
|
||||
* Get a session's scopes
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity
|
||||
* @return array Array of \League\OAuth2\Server\Entity\ScopeEntity
|
||||
*/
|
||||
public function getScopes(SessionEntity $session);
|
||||
|
||||
/**
|
||||
* Create a new session
|
||||
* @param string $ownerType Session owner's type (user, client)
|
||||
* @param string $ownerId Session owner's ID
|
||||
* @param string $clientId Client ID
|
||||
* @param string $clientRedirectUri Client redirect URI (default = null)
|
||||
* @return integer The session's ID
|
||||
*/
|
||||
public function create($ownerType, $ownerId, $clientId, $clientRedirectUri = null);
|
||||
|
||||
/**
|
||||
* Associate a scope with a session
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity $scope The scope
|
||||
* @param \League\OAuth2\Server\Entity\ScopeEntity $scope The scope
|
||||
* @return void
|
||||
*/
|
||||
public function associateScope(SessionEntity $session, ScopeEntity $scope);
|
||||
}
|
26
src/Storage/StorageInterface.php
Normal file
26
src/Storage/StorageInterface.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Storage interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\AbstractServer;
|
||||
|
||||
/**
|
||||
* Storage interface
|
||||
*/
|
||||
interface StorageInterface
|
||||
{
|
||||
/**
|
||||
* Set the server
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
*/
|
||||
public function setServer(AbstractServer $server);
|
||||
}
|
84
src/TokenType/AbstractTokenType.php
Normal file
84
src/TokenType/AbstractTokenType.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Abstract Token Type
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\TokenType;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use League\OAuth2\Server\AbstractServer;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
|
||||
abstract class AbstractTokenType
|
||||
{
|
||||
/**
|
||||
* Response array
|
||||
* @var array
|
||||
*/
|
||||
protected $response = [];
|
||||
|
||||
/**
|
||||
* Server
|
||||
* @var \League\OAuth2\Server\AbstractServer $server
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* Server
|
||||
* @var \League\OAuth2\Server\Entity\SessionEntity $session
|
||||
*/
|
||||
protected $session;
|
||||
|
||||
/**
|
||||
* Set the server
|
||||
* @param \League\OAuth2\Server\AbstractServer $server
|
||||
*/
|
||||
public function setServer(AbstractServer $server)
|
||||
{
|
||||
$this->server = $server;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the session entity
|
||||
* @param \League\OAuth2\Server\Entity\SessionEntity $session
|
||||
*/
|
||||
public function setSession(SessionEntity $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a key/value response pair
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setParam($key, $value)
|
||||
{
|
||||
$this->response[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a key from the response array
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParam($key)
|
||||
{
|
||||
return isset($this->response[$key]) ? $this->response[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the access token in the authorization header
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @return string
|
||||
*/
|
||||
abstract public function determineAccessTokenInHeader(Request $request);
|
||||
}
|
46
src/TokenType/Bearer.php
Normal file
46
src/TokenType/Bearer.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Bearer Token Type
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\TokenType;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class Bearer extends AbstractTokenType implements TokenTypeInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generateResponse()
|
||||
{
|
||||
$return = [
|
||||
'access_token' => $this->getParam('access_token'),
|
||||
'token_type' => 'Bearer',
|
||||
'expires_in' => $this->getParam('expires_in')
|
||||
];
|
||||
|
||||
if (!is_null($this->getParam('refresh_token'))) {
|
||||
$return['refresh_token'] = $this->getParam('refresh_token');
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function determineAccessTokenInHeader(Request $request)
|
||||
{
|
||||
$header = $request->headers->get('Authorization');
|
||||
$accessToken = trim(preg_replace('/^(?:\s+)?Bearer\s/', '', $header));
|
||||
|
||||
return ($accessToken === 'Bearer') ? '' : $accessToken;
|
||||
}
|
||||
}
|
21
src/TokenType/TokenTypeInterface.php
Normal file
21
src/TokenType/TokenTypeInterface.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Token Type Interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\TokenType;
|
||||
|
||||
interface TokenTypeInterface
|
||||
{
|
||||
/**
|
||||
* Generate a response
|
||||
* @return array
|
||||
*/
|
||||
public function generateResponse();
|
||||
}
|
35
src/Util/KeyAlgorithm/DefaultAlgorithm.php
Normal file
35
src/Util/KeyAlgorithm/DefaultAlgorithm.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Util\KeyAlgorithm;
|
||||
|
||||
class DefaultAlgorithm implements KeyAlgorithmInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function generate($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);
|
||||
}
|
||||
}
|
22
src/Util/KeyAlgorithm/KeyAlgorithmInterface.php
Normal file
22
src/Util/KeyAlgorithm/KeyAlgorithmInterface.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Secure key interface
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\Util\KeyAlgorithm;
|
||||
|
||||
interface KeyAlgorithmInterface
|
||||
{
|
||||
/**
|
||||
* Generate a new unique code
|
||||
* @param integer $len Length of the generated code
|
||||
* @return string
|
||||
*/
|
||||
public function generate($len);
|
||||
}
|
32
src/Util/RedirectUri.php
Normal file
32
src/Util/RedirectUri.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* OAuth 2.0 Redirect URI generator
|
||||
*
|
||||
* @package league/oauth2-server
|
||||
* @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\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);
|
||||
}
|
||||
}
|
53
src/Util/SecureKey.php
Normal file
53
src/Util/SecureKey.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?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 generate($len = 40)
|
||||
{
|
||||
return self::getAlgorithm()->generate($len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param KeyAlgorithmInterface $algorithm
|
||||
*/
|
||||
public static function setAlgorithm(KeyAlgorithmInterface $algorithm)
|
||||
{
|
||||
self::$algorithm = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return KeyAlgorithmInterface
|
||||
*/
|
||||
public static function getAlgorithm()
|
||||
{
|
||||
if (is_null(self::$algorithm)) {
|
||||
self::$algorithm = new DefaultAlgorithm();
|
||||
}
|
||||
|
||||
return self::$algorithm;
|
||||
}
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
-- Create syntax for TABLE 'clients'
|
||||
CREATE TABLE `clients` (
|
||||
`id` varchar(40) NOT NULL DEFAULT '',
|
||||
`secret` varchar(40) NOT NULL DEFAULT '',
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`auto_approve` tinyint(1) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'client_endpoints'
|
||||
CREATE TABLE `client_endpoints` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` varchar(40) NOT NULL DEFAULT '',
|
||||
`redirect_uri` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
CONSTRAINT `client_endpoints_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'oauth_sessions'
|
||||
CREATE TABLE `oauth_sessions` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`client_id` varchar(32) NOT NULL DEFAULT '',
|
||||
`redirect_uri` varchar(250) NOT NULL DEFAULT '',
|
||||
`owner_type` enum('user','client') NOT NULL DEFAULT 'user',
|
||||
`owner_id` varchar(255) DEFAULT NULL,
|
||||
`auth_code` varchar(40) DEFAULT '',
|
||||
`access_token` varchar(40) DEFAULT '',
|
||||
`access_token_expires` int(10) DEFAULT NULL,
|
||||
`stage` enum('requested','granted') NOT NULL DEFAULT 'requested',
|
||||
`first_requested` int(10) unsigned NOT NULL,
|
||||
`last_updated` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'scopes'
|
||||
CREATE TABLE `scopes` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`scope` varchar(255) NOT NULL DEFAULT '',
|
||||
`name` varchar(255) NOT NULL DEFAULT '',
|
||||
`description` varchar(255) DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `scope` (`scope`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Create syntax for TABLE 'oauth_session_scopes'
|
||||
CREATE TABLE `oauth_session_scopes` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`session_id` int(11) unsigned NOT NULL,
|
||||
`access_token` varchar(40) NOT NULL DEFAULT '',
|
||||
`scope` varchar(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `session_id` (`session_id`),
|
||||
KEY `access_token` (`access_token`),
|
||||
KEY `scope` (`scope`),
|
||||
CONSTRAINT `oauth_session_scopes_ibfk_3` FOREIGN KEY (`scope`) REFERENCES `scopes` (`scope`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `oauth_session_scopes_ibfk_4` FOREIGN KEY (`session_id`) REFERENCES `oauth_sessions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
@@ -1,191 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Oauth2\Authentication\Database;
|
||||
|
||||
class OAuthdb implements Database
|
||||
{
|
||||
private $sessions = array();
|
||||
private $sessions_client_type_id = array();
|
||||
private $sessions_code = array();
|
||||
private $session_scopes = array();
|
||||
|
||||
private $clients = array(0 => array(
|
||||
'client_id' => 'test',
|
||||
'client_secret' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'name' => 'Test Client'
|
||||
));
|
||||
|
||||
private $scopes = array('test' => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
));
|
||||
|
||||
public function validateClient(
|
||||
$clientId,
|
||||
$clientSecret = null,
|
||||
$redirectUri = null
|
||||
)
|
||||
{
|
||||
if ($clientId !== $this->clients[0]['client_id'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($clientSecret !== null && $clientSecret !== $this->clients[0]['client_secret'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($redirectUri !== null && $redirectUri !== $this->clients[0]['redirect_uri'])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->clients[0];
|
||||
}
|
||||
|
||||
public function newSession(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$type = 'user',
|
||||
$typeId = null,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
)
|
||||
{
|
||||
$id = count($this->sessions);
|
||||
|
||||
$this->sessions[$id] = array(
|
||||
'id' => $id,
|
||||
'client_id' => $clientId,
|
||||
'redirect_uri' => $redirectUri,
|
||||
'owner_type' => $type,
|
||||
'owner_id' => $typeId,
|
||||
'auth_code' => $authCode,
|
||||
'access_token' => $accessToken,
|
||||
'access_token_expire' => $accessTokenExpire,
|
||||
'stage' => $stage
|
||||
);
|
||||
|
||||
$this->sessions_client_type_id[$clientId . ':' . $type . ':' . $typeId] = $id;
|
||||
$this->sessions_code[$clientId . ':' . $redirectUri . ':' . $authCode] = $id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateSession(
|
||||
$sessionId,
|
||||
$authCode = null,
|
||||
$accessToken = null,
|
||||
$accessTokenExpire = null,
|
||||
$stage = 'requested'
|
||||
)
|
||||
{
|
||||
$this->sessions[$sessionId]['auth_code'] = $authCode;
|
||||
$this->sessions[$sessionId]['access_token'] = $accessToken;
|
||||
$this->sessions[$sessionId]['access_token_expire'] = $accessTokenExpire;
|
||||
$this->sessions[$sessionId]['stage'] = $stage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteSession(
|
||||
$clientId,
|
||||
$type,
|
||||
$typeId
|
||||
)
|
||||
{
|
||||
$key = $clientId . ':' . $type . ':' . $typeId;
|
||||
if (isset($this->sessions_client_type_id[$key]))
|
||||
{
|
||||
unset($this->sessions[$this->sessions_client_type_id[$key]]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validateAuthCode(
|
||||
$clientId,
|
||||
$redirectUri,
|
||||
$authCode
|
||||
)
|
||||
{
|
||||
$key = $clientId . ':' . $redirectUri . ':' . $authCode;
|
||||
|
||||
if (isset($this->sessions_code[$key]))
|
||||
{
|
||||
return $this->sessions[$this->sessions_code[$key]];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasSession(
|
||||
$type,
|
||||
$typeId,
|
||||
$clientId
|
||||
)
|
||||
{
|
||||
die('not implemented hasSession');
|
||||
}
|
||||
|
||||
public function getAccessToken($sessionId)
|
||||
{
|
||||
die('not implemented getAccessToken');
|
||||
}
|
||||
|
||||
public function removeAuthCode($sessionId)
|
||||
{
|
||||
die('not implemented removeAuthCode');
|
||||
}
|
||||
|
||||
public function setAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
)
|
||||
{
|
||||
die('not implemented setAccessToken');
|
||||
}
|
||||
|
||||
public function addSessionScope(
|
||||
$sessionId,
|
||||
$scope
|
||||
)
|
||||
{
|
||||
if ( ! isset($this->session_scopes[$sessionId]))
|
||||
{
|
||||
$this->session_scopes[$sessionId] = array();
|
||||
}
|
||||
|
||||
$this->session_scopes[$sessionId][] = $scope;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getScope($scope)
|
||||
{
|
||||
if ( ! isset($this->scopes[$scope]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->scopes[$scope];
|
||||
}
|
||||
|
||||
public function updateSessionScopeAccessToken(
|
||||
$sessionId,
|
||||
$accessToken
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function accessTokenScopes($accessToken)
|
||||
{
|
||||
die('not implemented accessTokenScopes');
|
||||
}
|
||||
}
|
@@ -1,398 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Authentication_Server_test extends PHPUnit_Framework_TestCase {
|
||||
|
||||
function setUp()
|
||||
{
|
||||
$this->oauth = new Oauth2\Authentication\Server();
|
||||
|
||||
require_once('database_mock.php');
|
||||
$this->oauthdb = new OAuthdb();
|
||||
$this->assertInstanceOf('Oauth2\Authentication\Database', $this->oauthdb);
|
||||
$this->oauth->registerDbAbstractor($this->oauthdb);
|
||||
}
|
||||
|
||||
function test_generateCode()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('generateCode');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->oauth);
|
||||
$result2 = $method->invoke($this->oauth);
|
||||
|
||||
$this->assertEquals(40, strlen($result));
|
||||
$this->assertNotEquals($result, $result2);
|
||||
}
|
||||
|
||||
function test_redirectUri()
|
||||
{
|
||||
$result1 = $this->oauth->redirectUri('http://example.com/foo');
|
||||
$result2 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'));
|
||||
$result3 = $this->oauth->redirectUri('http://example.com/foo', array('foo' => 'bar'), '#');
|
||||
|
||||
$this->assertEquals('http://example.com/foo?', $result1);
|
||||
$this->assertEquals('http://example.com/foo?foo=bar', $result2);
|
||||
$this->assertEquals('http://example.com/foo#foo=bar', $result3);
|
||||
}
|
||||
|
||||
function test_checkClientAuthoriseParams_GET()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
$_GET['redirect_uri'] = 'http://example.com/test';
|
||||
$_GET['response_type'] = 'code';
|
||||
$_GET['scope'] = 'test';
|
||||
|
||||
$expect = array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scopes' => array(
|
||||
0 => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$result = $this->oauth->checkClientAuthoriseParams();
|
||||
|
||||
$this->assertEquals($expect, $result);
|
||||
}
|
||||
|
||||
function test_checkClientAuthoriseParams_PassedParams()
|
||||
{
|
||||
unset($_GET['client_id']);
|
||||
unset($_GET['redirect_uri']);
|
||||
unset($_GET['response_type']);
|
||||
unset($_GET['scope']);
|
||||
|
||||
$params = array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'test'
|
||||
);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'response_type' => 'code',
|
||||
'scopes' => array(0 => array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
), $this->oauth->checkClientAuthoriseParams($params));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_checkClientAuthoriseParams_missingClientId()
|
||||
{
|
||||
$this->oauth->checkClientAuthoriseParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_checkClientAuthoriseParams_missingRedirectUri()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
|
||||
$this->oauth->checkClientAuthoriseParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_checkClientAuthoriseParams_missingResponseType()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
$_GET['redirect_uri'] = 'http://example.com/test';
|
||||
|
||||
$this->oauth->checkClientAuthoriseParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_checkClientAuthoriseParams_missingScopes()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
$_GET['redirect_uri'] = 'http://example.com/test';
|
||||
$_GET['response_type'] = 'code';
|
||||
$_GET['scope'] = ' ';
|
||||
|
||||
$this->oauth->checkClientAuthoriseParams();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 4
|
||||
*/
|
||||
function test_checkClientAuthoriseParams_invalidScopes()
|
||||
{
|
||||
$_GET['client_id'] = 'test';
|
||||
$_GET['redirect_uri'] = 'http://example.com/test';
|
||||
$_GET['response_type'] = 'code';
|
||||
$_GET['scope'] = 'blah';
|
||||
|
||||
$this->oauth->checkClientAuthoriseParams();
|
||||
}
|
||||
|
||||
function test_newAuthoriseRequest()
|
||||
{
|
||||
$result = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$this->assertEquals(40, strlen($result));
|
||||
}
|
||||
|
||||
function test_newAuthoriseRequest_isUnique()
|
||||
{
|
||||
$result1 = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$result2 = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$this->assertNotEquals($result1, $result2);
|
||||
}
|
||||
|
||||
function test_issueAccessToken_POST()
|
||||
{
|
||||
$auth_code = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$_POST['client_id'] = 'test';
|
||||
$_POST['client_secret'] = 'test';
|
||||
$_POST['redirect_uri'] = 'http://example.com/test';
|
||||
$_POST['grant_type'] = 'authorization_code';
|
||||
$_POST['code'] = $auth_code;
|
||||
|
||||
$result = $this->oauth->issueAccessToken();
|
||||
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertArrayHasKey('access_token', $result);
|
||||
$this->assertArrayHasKey('token_type', $result);
|
||||
$this->assertArrayHasKey('expires_in', $result);
|
||||
}
|
||||
|
||||
function test_issueAccessToken_PassedParams()
|
||||
{
|
||||
$auth_code = $this->oauth->newAuthoriseRequest('user', '123', array(
|
||||
'client_id' => 'test',
|
||||
'redirect_uri' => 'http://example.com/test',
|
||||
'scopes' => array(array(
|
||||
'id' => 1,
|
||||
'scope' => 'test',
|
||||
'name' => 'test',
|
||||
'description' => 'test'
|
||||
))
|
||||
));
|
||||
|
||||
$params['client_id'] = 'test';
|
||||
$params['client_secret'] = 'test';
|
||||
$params['redirect_uri'] = 'http://example.com/test';
|
||||
$params['grant_type'] = 'authorization_code';
|
||||
$params['code'] = $auth_code;
|
||||
|
||||
$result = $this->oauth->issueAccessToken($params);
|
||||
|
||||
$this->assertCount(3, $result);
|
||||
$this->assertArrayHasKey('access_token', $result);
|
||||
$this->assertArrayHasKey('token_type', $result);
|
||||
$this->assertArrayHasKey('expires_in', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_issueAccessToken_missingGrantType()
|
||||
{
|
||||
$this->oauth->issueAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 7
|
||||
*/
|
||||
function test_issueAccessToken_unsupportedGrantType()
|
||||
{
|
||||
$params['grant_type'] = 'blah';
|
||||
|
||||
$this->oauth->issueAccessToken($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_completeAuthCodeGrant_missingClientId()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$method->invoke($this->oauth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_completeAuthCodeGrant_missingClientSecret()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$authParams['client_id'] = 'test';
|
||||
|
||||
$method->invoke($this->oauth, $authParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_completeAuthCodeGrant_missingRedirectUri()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$authParams['client_id'] = 'test';
|
||||
$authParams['client_secret'] = 'test';
|
||||
|
||||
$method->invoke($this->oauth, $authParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 8
|
||||
*/
|
||||
function test_completeAuthCodeGrant_invalidClient()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$authParams['client_id'] = 'test';
|
||||
$authParams['client_secret'] = 'test123';
|
||||
$authParams['redirect_uri'] = 'http://example.com/test';
|
||||
|
||||
$method->invoke($this->oauth, $authParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 0
|
||||
*/
|
||||
function test_completeAuthCodeGrant_missingCode()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$authParams['client_id'] = 'test';
|
||||
$authParams['client_secret'] = 'test';
|
||||
$authParams['redirect_uri'] = 'http://example.com/test';
|
||||
|
||||
$method->invoke($this->oauth, $authParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerClientException
|
||||
* @expectedExceptionCode 9
|
||||
*/
|
||||
function test_completeAuthCodeGrant_invalidCode()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('completeAuthCodeGrant');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$authParams['client_id'] = 'test';
|
||||
$authParams['client_secret'] = 'test';
|
||||
$authParams['redirect_uri'] = 'http://example.com/test';
|
||||
$authParams['code'] = 'blah';
|
||||
|
||||
$method->invoke($this->oauth, $authParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerException
|
||||
* @expectedExceptionMessage No registered database abstractor
|
||||
*/
|
||||
function test_noRegisteredDatabaseAbstractor()
|
||||
{
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('_dbCall');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$dbAbstractor = $reflector->getProperty('_db');
|
||||
$dbAbstractor->setAccessible(true);
|
||||
$dbAbstractor->setValue($this->oauth, null);
|
||||
|
||||
$result = $method->invoke($this->oauth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Oauth2\Authentication\OAuthServerException
|
||||
* @expectedExceptionMessage Registered database abstractor is not an instance of Oauth2\Authentication\Database
|
||||
*/
|
||||
function test_invalidRegisteredDatabaseAbstractor()
|
||||
{
|
||||
$fake = new stdClass;
|
||||
$this->oauth->registerDbAbstractor($fake);
|
||||
|
||||
$reflector = new ReflectionClass($this->oauth);
|
||||
$method = $reflector->getMethod('_dbCall');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invoke($this->oauth);
|
||||
}
|
||||
|
||||
}
|
9
tests/fuzz/grant-authcode.yml
Normal file
9
tests/fuzz/grant-authcode.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
url: 'http://localhost:8000/authcode_grant.php/authorize?client_id=testclient&redirect_uri=http%3A%2F%2Fexample.com%2Fredirect&response_type=code&scope=basic'
|
||||
request:
|
||||
method: GET
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Location
|
||||
valueRegex: /http:\/\/example.com\/redirect\?code=([a-zA-Z0-9]*)/
|
67
tests/fuzz/grant-client-credentials.yml
Normal file
67
tests/fuzz/grant-client-credentials.yml
Normal file
@@ -0,0 +1,67 @@
|
||||
url: 'http://localhost:8000/other_grants.php/access_token'
|
||||
request:
|
||||
method: POST
|
||||
body:
|
||||
-
|
||||
key: client_id
|
||||
value: testclient
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"client_id\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_client
|
||||
body.message: "Client authentication failed."
|
||||
-
|
||||
key: client_secret
|
||||
value: secret
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"client_secret\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_client
|
||||
body.message: "Client authentication failed."
|
||||
-
|
||||
key: grant_type
|
||||
value: client_credentials
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"grant_type\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: unsupported_grant_type
|
||||
#body.message: "The authorization grant type XXX is not supported by the authorization server."
|
||||
-
|
||||
key: scope
|
||||
value: "basic"
|
||||
invalid:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_scope
|
||||
border.message: fooooooooo
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: expires_in
|
||||
valueType: integer
|
||||
-
|
||||
key: access_token
|
||||
valueRegex: /([a-zA-Z0-9]*)/
|
||||
-
|
||||
key: token_type
|
||||
value: Bearer
|
88
tests/fuzz/grant-password.yml
Normal file
88
tests/fuzz/grant-password.yml
Normal file
@@ -0,0 +1,88 @@
|
||||
url: 'http://localhost:8000/other_grants.php/access_token'
|
||||
request:
|
||||
method: POST
|
||||
body:
|
||||
-
|
||||
key: client_id
|
||||
value: testclient
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"client_id\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_client
|
||||
body.message: "Client authentication failed."
|
||||
-
|
||||
key: client_secret
|
||||
value: secret
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"client_secret\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_client
|
||||
body.message: "Client authentication failed."
|
||||
-
|
||||
key: username
|
||||
value: alexbilbie
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"username\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_credentials
|
||||
body.message: "The user credentials were incorrect."
|
||||
-
|
||||
key: password
|
||||
value: whisky
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"password\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 401
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_credentials
|
||||
body.message: "The user credentials were incorrect."
|
||||
-
|
||||
key: grant_type
|
||||
value: password
|
||||
missing:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: invalid_request
|
||||
body.message: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"grant_type\" parameter."
|
||||
invalid:
|
||||
response.statusCode: 400
|
||||
headers.content-type: "application/json"
|
||||
body.error: unsupported_grant_type
|
||||
#body.message: "The authorization grant type XXX is not supported by the authorization server."
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: expires_in
|
||||
valueType: integer
|
||||
-
|
||||
key: access_token
|
||||
valueRegex: /([a-zA-Z0-9]*)/
|
||||
-
|
||||
key: refresh_token
|
||||
valueRegex: /([a-zA-Z0-9]*)/
|
||||
-
|
||||
key: token_type
|
||||
value: Bearer
|
16
tests/fuzz/tokeninfo-no-access-token.yml
Normal file
16
tests/fuzz/tokeninfo-no-access-token.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
url: 'http://localhost:8000/api.php/tokeninfo'
|
||||
request:
|
||||
method: GET
|
||||
response:
|
||||
statusCode: 400
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: error
|
||||
value: "invalid_request"
|
||||
-
|
||||
key: message
|
||||
value: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"access token\" parameter."
|
16
tests/fuzz/tokeninfo-no-invalid-token-query-string.yml
Normal file
16
tests/fuzz/tokeninfo-no-invalid-token-query-string.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
url: 'http://localhost:8000/api.php/tokeninfo?access_token=foobar'
|
||||
request:
|
||||
method: GET
|
||||
response:
|
||||
statusCode: 401
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: error
|
||||
value: "access_denied"
|
||||
-
|
||||
key: message
|
||||
value: "The resource owner or authorization server denied the request."
|
20
tests/fuzz/tokeninfo-no-invalid-token.yml
Normal file
20
tests/fuzz/tokeninfo-no-invalid-token.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
url: 'http://localhost:8000/api.php/tokeninfo'
|
||||
request:
|
||||
method: GET
|
||||
headers:
|
||||
-
|
||||
key: Authorization
|
||||
value: Bearer foobar
|
||||
response:
|
||||
statusCode: 401
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: error
|
||||
value: "access_denied"
|
||||
-
|
||||
key: message
|
||||
value: "The resource owner or authorization server denied the request."
|
26
tests/fuzz/tokeninfo-valid-token-header.yml
Normal file
26
tests/fuzz/tokeninfo-valid-token-header.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
url: 'http://localhost:8000/api.php/tokeninfo'
|
||||
request:
|
||||
method: GET
|
||||
headers:
|
||||
-
|
||||
key: Authorization
|
||||
value: "Bearer iamgod"
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: owner_id
|
||||
value: testclient
|
||||
-
|
||||
key: owner_type
|
||||
value: client
|
||||
-
|
||||
key: access_token
|
||||
value: iamgod
|
||||
-
|
||||
key: client_id
|
||||
value: testclient
|
22
tests/fuzz/tokeninfo-valid-token.yml
Normal file
22
tests/fuzz/tokeninfo-valid-token.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
url: 'http://localhost:8000/api.php/tokeninfo?access_token=iamgod'
|
||||
request:
|
||||
method: GET
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: owner_id
|
||||
value: testclient
|
||||
-
|
||||
key: owner_type
|
||||
value: client
|
||||
-
|
||||
key: access_token
|
||||
value: iamgod
|
||||
-
|
||||
key: client_id
|
||||
value: testclient
|
32
tests/fuzz/users-token-iamalex.yml
Normal file
32
tests/fuzz/users-token-iamalex.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
url: 'http://localhost:8000/api.php/users'
|
||||
request:
|
||||
method: GET
|
||||
headers:
|
||||
-
|
||||
key: Authorization
|
||||
value: Bearer iamalex
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: 0.username
|
||||
value: alexbilbie
|
||||
-
|
||||
key: 0.name
|
||||
value: Alex Bilbie
|
||||
-
|
||||
key: 0.photo
|
||||
valueType: string
|
||||
-
|
||||
key: 1.username
|
||||
value: philsturgeon
|
||||
-
|
||||
key: 1.name
|
||||
value: Phil Sturgeon
|
||||
-
|
||||
key: 1.photo
|
||||
valueType: string
|
32
tests/fuzz/users-token-iamphil.yml
Normal file
32
tests/fuzz/users-token-iamphil.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
url: 'http://localhost:8000/api.php/users'
|
||||
request:
|
||||
method: GET
|
||||
headers:
|
||||
-
|
||||
key: Authorization
|
||||
value: Bearer iamphil
|
||||
response:
|
||||
statusCode: 200
|
||||
headers:
|
||||
-
|
||||
key: Content-type
|
||||
value: application/json
|
||||
body:
|
||||
-
|
||||
key: 0.username
|
||||
value: alexbilbie
|
||||
-
|
||||
key: 0.name
|
||||
value: Alex Bilbie
|
||||
-
|
||||
key: 0.email
|
||||
valueType: string
|
||||
-
|
||||
key: 1.username
|
||||
value: philsturgeon
|
||||
-
|
||||
key: 1.name
|
||||
value: Phil Sturgeon
|
||||
-
|
||||
key: 1.email
|
||||
valueType: string
|
@@ -1,31 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Oauth2\Resource\Database;
|
||||
|
||||
class ResourceDB implements Database
|
||||
{
|
||||
private $accessTokens = array(
|
||||
'test12345' => array(
|
||||
'id' => 1,
|
||||
'owner_type' => 'user',
|
||||
'owner_id' => 123
|
||||
)
|
||||
);
|
||||
|
||||
private $sessionScopes = array(
|
||||
1 => array(
|
||||
'foo',
|
||||
'bar'
|
||||
)
|
||||
);
|
||||
|
||||
public function validateAccessToken($accessToken)
|
||||
{
|
||||
return (isset($this->accessTokens[$accessToken])) ? $this->accessTokens[$accessToken] : false;
|
||||
}
|
||||
|
||||
public function sessionScopes($sessionId)
|
||||
{
|
||||
return (isset($this->sessionScopes[$sessionId])) ? $this->sessionScopes[$sessionId] : array();
|
||||
}
|
||||
}
|
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
class Resource_Server_test extends PHPUnit_Framework_TestCase {
|
||||
|
||||
function setUp()
|
||||
{
|
||||
require_once('database_mock.php');
|
||||
$this->server = new Oauth2\Resource\Server();
|
||||
$this->db = new ResourceDB();
|
||||
|
||||
$this->assertInstanceOf('Oauth2\Resource\Database', $this->db);
|
||||
$this->server->registerDbAbstractor($this->db);
|
||||
}
|
||||
|
||||
function test_init_POST()
|
||||
{
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
$_POST['oauth_token'] = 'test12345';
|
||||
|
||||
$this->server->init();
|
||||
|
||||
$reflector = new ReflectionClass($this->server);
|
||||
|
||||
$_accessToken = $reflector->getProperty('_accessToken');
|
||||
$_accessToken->setAccessible(true);
|
||||
|
||||
$_type = $reflector->getProperty('_type');
|
||||
$_type->setAccessible(true);
|
||||
|
||||
$_typeId = $reflector->getProperty('_typeId');
|
||||
$_typeId->setAccessible(true);
|
||||
|
||||
$_scopes = $reflector->getProperty('_scopes');
|
||||
$_scopes->setAccessible(true);
|
||||
|
||||
$this->assertEquals($_accessToken->getValue($this->server), $_POST['oauth_token']);
|
||||
$this->assertEquals($_type->getValue($this->server), 'user');
|
||||
$this->assertEquals($_typeId->getValue($this->server), 123);
|
||||
$this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar'));
|
||||
}
|
||||
|
||||
function test_init_GET()
|
||||
{
|
||||
$_GET['oauth_token'] = 'test12345';
|
||||
|
||||
$this->server->init();
|
||||
|
||||
$reflector = new ReflectionClass($this->server);
|
||||
|
||||
$_accessToken = $reflector->getProperty('_accessToken');
|
||||
$_accessToken->setAccessible(true);
|
||||
|
||||
$_type = $reflector->getProperty('_type');
|
||||
$_type->setAccessible(true);
|
||||
|
||||
$_typeId = $reflector->getProperty('_typeId');
|
||||
$_typeId->setAccessible(true);
|
||||
|
||||
$_scopes = $reflector->getProperty('_scopes');
|
||||
$_scopes->setAccessible(true);
|
||||
|
||||
$this->assertEquals($_accessToken->getValue($this->server), $_GET['oauth_token']);
|
||||
$this->assertEquals($_type->getValue($this->server), 'user');
|
||||
$this->assertEquals($_typeId->getValue($this->server), 123);
|
||||
$this->assertEquals($_scopes->getValue($this->server), array('foo', 'bar'));
|
||||
}
|
||||
|
||||
function test_init_header()
|
||||
{
|
||||
// Test with authorisation header
|
||||
$this->markTestIncomplete('Authorisation header test has not been implemented yet.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Oauth2\Resource\OAuthResourceServerException
|
||||
* @expectedExceptionMessage An access token was not presented with the request
|
||||
*/
|
||||
function test_init_missingToken()
|
||||
{
|
||||
$this->server->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Oauth2\Resource\OAuthResourceServerException
|
||||
* @expectedExceptionMessage The access token is not registered with the resource server
|
||||
*/
|
||||
function test_init_wrongToken()
|
||||
{
|
||||
$_POST['oauth_token'] = 'blah';
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
||||
$this->server->init();
|
||||
}
|
||||
|
||||
function test_hasScope()
|
||||
{
|
||||
$_POST['oauth_token'] = 'test12345';
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
||||
$this->server->init();
|
||||
|
||||
$this->assertEquals(true, $this->server->hasScope('foo'));
|
||||
$this->assertEquals(true, $this->server->hasScope('bar'));
|
||||
$this->assertEquals(true, $this->server->hasScope(array('foo', 'bar')));
|
||||
|
||||
$this->assertEquals(false, $this->server->hasScope('foobar'));
|
||||
$this->assertEquals(false, $this->server->hasScope(array('foobar')));
|
||||
}
|
||||
|
||||
function test___call()
|
||||
{
|
||||
$_POST['oauth_token'] = 'test12345';
|
||||
$_SERVER['REQUEST_METHOD'] = 'POST';
|
||||
|
||||
$this->server->init();
|
||||
|
||||
$this->assertEquals(123, $this->server->isUser());
|
||||
$this->assertEquals(false, $this->server->isMachine());
|
||||
}
|
||||
|
||||
}
|
28
tests/unit/AbstractServerTest.php
Normal file
28
tests/unit/AbstractServerTest.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests;
|
||||
|
||||
use LeagueTests\Stubs\StubAbstractServer;
|
||||
|
||||
class AbstractServerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSetGet()
|
||||
{
|
||||
$server = new StubAbstractServer();
|
||||
$var = 0;
|
||||
$server->addEventListener('event.name', function() use ($var) {
|
||||
$var++;
|
||||
$this->assertSame(1, $var);
|
||||
});
|
||||
$server->getEventEmitter()->emit('event.name');
|
||||
$this->assertTrue($server->getRequest() instanceof \Symfony\Component\HttpFoundation\Request);
|
||||
$this->assertTrue($server->getEventEmitter() instanceof \League\Event\Emitter);
|
||||
|
||||
|
||||
$server2 = new StubAbstractServer();
|
||||
$server2->setRequest((new \Symfony\Component\HttpFoundation\Request));
|
||||
$server2->setEventEmitter(1);
|
||||
$this->assertTrue($server2->getRequest() instanceof \Symfony\Component\HttpFoundation\Request);
|
||||
|
||||
}
|
||||
}
|
82
tests/unit/AuthorizationServerTest.php
Normal file
82
tests/unit/AuthorizationServerTest.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests;
|
||||
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use League\OAuth2\Server\Grant\GrantTypeInterface;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
use \Mockery as M;
|
||||
|
||||
class AuthorizationServerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSetGet()
|
||||
{
|
||||
$server = new AuthorizationServer;
|
||||
$server->requireScopeParam(true);
|
||||
$server->requireStateParam(true);
|
||||
$server->setDefaultScope('foobar');
|
||||
$server->setScopeDelimeter(',');
|
||||
$server->setAccessTokenTTL(1);
|
||||
|
||||
$grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface');
|
||||
$grant->shouldReceive('getIdentifier')->andReturn('foobar');
|
||||
$grant->shouldReceive('getResponseType')->andReturn('foobar');
|
||||
$grant->shouldReceive('setAuthorizationServer');
|
||||
|
||||
$scopeStorage = M::mock('League\OAuth2\Server\Storage\ScopeInterface');
|
||||
$scopeStorage->shouldReceive('setServer');
|
||||
|
||||
$server->addGrantType($grant);
|
||||
$server->setScopeStorage($scopeStorage);
|
||||
|
||||
$this->assertTrue($server->hasGrantType('foobar'));
|
||||
$this->assertTrue($server->getGrantType('foobar') instanceof GrantTypeInterface);
|
||||
$this->assertSame($server->getResponseTypes(), ['foobar']);
|
||||
$this->assertTrue($server->scopeParamRequired());
|
||||
$this->assertTrue($server->stateParamRequired());
|
||||
$this->assertTrue($server->getScopeStorage() instanceof ScopeInterface);
|
||||
$this->assertEquals('foobar', $server->getDefaultScope());
|
||||
$this->assertEquals(',', $server->getScopeDelimeter());
|
||||
$this->assertEquals(1, $server->getAccessTokenTTL());
|
||||
}
|
||||
|
||||
public function testInvalidGrantType()
|
||||
{
|
||||
$this->setExpectedException('League\OAuth2\Server\Exception\InvalidGrantException');
|
||||
$server = new AuthorizationServer;
|
||||
$server->getGrantType('foobar');
|
||||
}
|
||||
|
||||
public function testIssueAccessToken()
|
||||
{
|
||||
$grant = M::mock('League\OAuth2\Server\Grant\GrantTypeInterface');
|
||||
$grant->shouldReceive('getIdentifier')->andReturn('foobar');
|
||||
$grant->shouldReceive('getResponseType')->andReturn('foobar');
|
||||
$grant->shouldReceive('setAuthorizationServer');
|
||||
$grant->shouldReceive('completeFlow')->andReturn(true);
|
||||
|
||||
$_POST['grant_type'] = 'foobar';
|
||||
|
||||
$server = new AuthorizationServer;
|
||||
$server->addGrantType($grant);
|
||||
|
||||
$this->assertTrue($server->issueAccessToken());
|
||||
}
|
||||
|
||||
public function testIssueAccessTokenEmptyGrantType()
|
||||
{
|
||||
$this->setExpectedException('League\OAuth2\Server\Exception\InvalidRequestException');
|
||||
$server = new AuthorizationServer;
|
||||
$this->assertTrue($server->issueAccessToken());
|
||||
}
|
||||
|
||||
public function testIssueAccessTokenInvalidGrantType()
|
||||
{
|
||||
$this->setExpectedException('League\OAuth2\Server\Exception\UnsupportedGrantTypeException');
|
||||
|
||||
$_POST['grant_type'] = 'foobar';
|
||||
|
||||
$server = new AuthorizationServer;
|
||||
$this->assertTrue($server->issueAccessToken());
|
||||
}
|
||||
}
|
5
tests/unit/Bootstrap.php
Normal file
5
tests/unit/Bootstrap.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
if (! @include_once __DIR__ . '/../../vendor/autoload.php') {
|
||||
exit("You must set up the project dependencies, run the following commands:\n> wget http://getcomposer.org/composer.phar\n> php composer.phar install\n");
|
||||
}
|
116
tests/unit/Entity/AbstractTokenEntityTest.php
Normal file
116
tests/unit/Entity/AbstractTokenEntityTest.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests\Entity;
|
||||
|
||||
use LeagueTests\Stubs\StubAbstractTokenEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\AuthorizationServer;
|
||||
use \Mockery as M;
|
||||
|
||||
class AbstractTokenTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSetGet()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AbstractServer');
|
||||
$time = time();
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$entity->setId('foobar');
|
||||
$entity->setExpireTime($time);
|
||||
$entity->setSession((new SessionEntity($server)));
|
||||
$entity->associateScope((new ScopeEntity($server))->hydrate(['id' => 'foo']));
|
||||
|
||||
$this->assertEquals('foobar', $entity->getId());
|
||||
$this->assertEquals($time, $entity->getExpireTime());
|
||||
// $this->assertTrue($entity->getSession() instanceof SessionEntity);
|
||||
// $this->assertTrue($entity->hasScope('foo'));
|
||||
|
||||
// $result = $entity->getScopes();
|
||||
// $this->assertTrue(isset($result['foo']));
|
||||
}
|
||||
|
||||
/*public function testGetSession()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AuthorizationServer');
|
||||
$server->shouldReceive('setSessionStorage');
|
||||
|
||||
$sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface');
|
||||
$sessionStorage->shouldReceive('getByAccessToken')->andReturn(
|
||||
(new SessionEntity($server))
|
||||
);
|
||||
$sessionStorage->shouldReceive('setServer');
|
||||
|
||||
$server->shouldReceive('getStorage')->andReturn($sessionStorage);
|
||||
|
||||
$server->setSessionStorage($sessionStorage);
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$this->assertTrue($entity->getSession() instanceof SessionEntity);
|
||||
}*/
|
||||
|
||||
/*public function testGetScopes()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AuthorizationServer');
|
||||
$server->shouldReceive('setAccessTokenStorage');
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('getScopes')->andReturn(
|
||||
[]
|
||||
);
|
||||
$accessTokenStorage->shouldReceive('setServer');
|
||||
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$this->assertEquals($entity->getScopes(), []);
|
||||
}*/
|
||||
|
||||
/*public function testHasScopes()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AuthorizationServer');
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('getScopes')->andReturn(
|
||||
[]
|
||||
);
|
||||
$accessTokenStorage''>shouldReceive('setServer');
|
||||
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$this->assertFalse($entity->hasScope('foo'));
|
||||
}*/
|
||||
|
||||
public function testFormatScopes()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AbstractServer');
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$reflectedEntity = new \ReflectionClass('LeagueTests\Stubs\StubAbstractTokenEntity');
|
||||
$method = $reflectedEntity->getMethod('formatScopes');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$scopes = [
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'scope1', 'description' => 'foo']),
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'scope2', 'description' => 'bar'])
|
||||
];
|
||||
|
||||
$result = $method->invokeArgs($entity, [$scopes]);
|
||||
|
||||
$this->assertTrue(isset($result['scope1']));
|
||||
$this->assertTrue(isset($result['scope2']));
|
||||
$this->assertTrue($result['scope1'] instanceof ScopeEntity);
|
||||
$this->assertTrue($result['scope2'] instanceof ScopeEntity);
|
||||
}
|
||||
|
||||
public function test__toString()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AbstractServer');
|
||||
|
||||
$entity = new StubAbstractTokenEntity($server);
|
||||
$this->assertEquals('', (string) $entity);
|
||||
$entity->setId('foobar');
|
||||
$this->assertEquals('foobar', (string) $entity);
|
||||
}
|
||||
}
|
59
tests/unit/Entity/AccessTokenEntityTest.php
Normal file
59
tests/unit/Entity/AccessTokenEntityTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace LeagueTests\Entity;
|
||||
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity;
|
||||
use \Mockery as M;
|
||||
|
||||
class AccessTokenTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testSave()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AbstractServer');
|
||||
$server->shouldReceive('setAccessTokenStorage');
|
||||
$server->shouldReceive('setSessionStorage');
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('create');
|
||||
$accessTokenStorage->shouldReceive('associateScope');
|
||||
$accessTokenStorage->shouldReceive('setServer');
|
||||
$accessTokenStorage->shouldReceive('getScopes')->andReturn([
|
||||
(new ScopeEntity($server))->hydrate(['id' => 'foo'])
|
||||
]);
|
||||
|
||||
$sessionStorage = M::mock('League\OAuth2\Server\Storage\SessionInterface');
|
||||
$sessionStorage->shouldReceive('getByAccessToken')->andReturn(
|
||||
(new SessionEntity($server))
|
||||
);
|
||||
$sessionStorage->shouldReceive('setServer');
|
||||
|
||||
$server->shouldReceive('getSessionStorage')->andReturn($sessionStorage);
|
||||
$server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage);
|
||||
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
$server->setSessionStorage($sessionStorage);
|
||||
|
||||
$entity = new AccessTokenEntity($server);
|
||||
$this->assertTrue($entity->save() instanceof AccessTokenEntity);
|
||||
}
|
||||
|
||||
public function testExpire()
|
||||
{
|
||||
$server = M::mock('League\OAuth2\Server\AbstractServer');
|
||||
|
||||
$server->shouldReceive('setAccessTokenStorage');
|
||||
|
||||
$accessTokenStorage = M::mock('League\OAuth2\Server\Storage\AccessTokenInterface');
|
||||
$accessTokenStorage->shouldReceive('delete');
|
||||
$accessTokenStorage->shouldReceive('setServer');
|
||||
|
||||
$server->shouldReceive('getAccessTokenStorage')->andReturn($accessTokenStorage);
|
||||
|
||||
$server->setAccessTokenStorage($accessTokenStorage);
|
||||
|
||||
$entity = new AccessTokenEntity($server);
|
||||
$this->assertSame($entity->expire(), null);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user