Compare commits
1065 Commits
version/0.
...
version/0.
Author | SHA1 | Date | |
---|---|---|---|
c7f078ffcc | |||
571cb3d65f | |||
8c500c38b1 | |||
5644e57e6a | |||
cfc181eed1 | |||
91bea38b8e | |||
d95c5aa739 | |||
0b250b897e | |||
c6880a0f16 | |||
beb5ffcbdd | |||
0715cac39b | |||
41117d873d | |||
231e448b1a | |||
b3b8cd807d | |||
9021bbd5de | |||
169475ab39 | |||
c00e01626e | |||
05d4a9ef62 | |||
17a2ac73e7 | |||
6bc6f947dd | |||
b048a1fb4f | |||
363940ee8d | |||
a64e53479c | |||
14fdbe7720 | |||
f56332c954 | |||
21c53c748f | |||
b12182c1d1 | |||
d8f27f595a | |||
b25dc2aaa3 | |||
3ec3849e72 | |||
2dc1b65718 | |||
af22f507f4 | |||
9958019bf3 | |||
02d65972cb | |||
24ad893350 | |||
9c5792b1e1 | |||
094d191bff | |||
49fb9f688b | |||
7d161e5aa1 | |||
78e5d471e3 | |||
2e2c9f5287 | |||
d5a3e09a98 | |||
2402cfe29d | |||
26613b6ea9 | |||
e5165abf04 | |||
b26882a450 | |||
94281bee88 | |||
16b966c16e | |||
d3b0992456 | |||
dd74b73b4f | |||
0bdfccc1f3 | |||
ceb0793bc9 | |||
abea85b635 | |||
01c83f6f4a | |||
9167c9c3ba | |||
04add2e52d | |||
1e9241d45b | |||
22ee198a31 | |||
1d9c92d548 | |||
b30b58924f | |||
bead19c64c | |||
76e2ba4764 | |||
8d095d7436 | |||
d3a7fd5818 | |||
247a8dbc8f | |||
9241adfc68 | |||
ae83ee6d31 | |||
4701374021 | |||
bd40585247 | |||
cc0b8164b0 | |||
310b31a8b7 | |||
13900bc603 | |||
6634cc2edf | |||
3478a2cf6d | |||
3b70d12a5f | |||
219acf76d5 | |||
ec6f467fa2 | |||
0e6561987e | |||
62c20b6e67 | |||
13084562c5 | |||
02c1c434a2 | |||
5f04a75878 | |||
3556c76674 | |||
c7d638de2f | |||
143733499f | |||
0d6a0ffe14 | |||
6d4c7312d8 | |||
2cb6a179e8 | |||
7de2ad77b5 | |||
89c33060d4 | |||
b61f595562 | |||
ce2230f774 | |||
d18a78d04d | |||
c59c6aa728 | |||
729910c383 | |||
37fe637422 | |||
3114d064ed | |||
2ca5e1eedb | |||
d2bf579ff6 | |||
3716bda76e | |||
a76eb4d30f | |||
7c191b0984 | |||
9613fcde89 | |||
885a2ed057 | |||
b270fb0742 | |||
285a69d91f | |||
de3b753a26 | |||
34be1dd9f4 | |||
a4c0fb9e75 | |||
f040223646 | |||
bf297b8593 | |||
43eea9e99c | |||
8e38bc87bc | |||
50a57fb3dd | |||
38b8bc182f | |||
9743ad33d6 | |||
b746ce97ba | |||
dbee714dac | |||
d33f632203 | |||
812aa4ced5 | |||
63466e3384 | |||
920858ff72 | |||
56f599e4aa | |||
05183ed937 | |||
8d31eef47d | |||
96a6ac85df | |||
5a60341a6e | |||
21ba969072 | |||
d6a8d8292d | |||
693a92ada5 | |||
ec823aebed | |||
b8654c06bf | |||
9d03c4c7d2 | |||
8c36ab89e8 | |||
e75e71a5ce | |||
bf008e368e | |||
3c1d02bfc4 | |||
c1b2093cf7 | |||
cc7e4ad0e2 | |||
c07bd6e733 | |||
768464dc6a | |||
a2ed53c312 | |||
5a11206fe9 | |||
9675fbb07d | |||
57a7bed99d | |||
2dfec43750 | |||
ab9f6531c2 | |||
b8b5069df1 | |||
7045305aa8 | |||
49c706fde8 | |||
9eaceb9ec6 | |||
05778d8065 | |||
831e228f80 | |||
31e0d74495 | |||
05999cb8c7 | |||
6cb4773916 | |||
ec9b0600e4 | |||
c0d8aa2303 | |||
599fdf193e | |||
db6cb5ad51 | |||
52f138d402 | |||
bc37727758 | |||
547a728130 | |||
178c2b6927 | |||
59b8b1e92a | |||
0210cdadfb | |||
491e507d49 | |||
de1be2df88 | |||
39f51ec33d | |||
f69e20886b | |||
fd0f0c65e9 | |||
ed4daa64fe | |||
887163c45c | |||
1b3c0adf75 | |||
0838f518d4 | |||
5c49cda884 | |||
6643cce841 | |||
3eb2cda37d | |||
6fdaac9a7d | |||
6122dcacc7 | |||
246d00bdde | |||
7e47b64b05 | |||
4285175bba | |||
e4a9a84646 | |||
4d81172a48 | |||
c97b946a00 | |||
3753275453 | |||
e4cb9b7ff9 | |||
a0f05caf8e | |||
42e9ce4f72 | |||
331faa53bc | |||
17424ccc3b | |||
68efcc7bf2 | |||
7b7305607c | |||
f1e6d91289 | |||
0310d46314 | |||
14fd137f89 | |||
e91a8f88a0 | |||
af8cdb34ee | |||
03b1a67b44 | |||
12525051b6 | |||
01f004cec6 | |||
3a40e50fa0 | |||
fa5c2bd85c | |||
b83aa44c4f | |||
73e7158178 | |||
8c6a4a4968 | |||
d12462fe0d | |||
c83216ece0 | |||
133486f07f | |||
b0fec4f3e2 | |||
739a99f16e | |||
f54a1b627c | |||
242d8c2b91 | |||
77065794da | |||
dab53cfd03 | |||
6a4086c490 | |||
5b8bdac84b | |||
c71b150025 | |||
647d56e90c | |||
e85236959b | |||
afe3259e96 | |||
4be2c66cdf | |||
dc8c1ad297 | |||
9dc3b1dca0 | |||
cbfb509ca9 | |||
047361600d | |||
a5b8c91c04 | |||
4d317a21ce | |||
e07b65401e | |||
71df9ea74d | |||
1cbaf865d8 | |||
cf9023269e | |||
5f9e8ac89b | |||
bdf0e74af3 | |||
6dedb17029 | |||
5e8a1e3c0d | |||
703e67a060 | |||
de00f9f41a | |||
a05f841bed | |||
c23646e6f3 | |||
f0600b5482 | |||
afc8baff5f | |||
8a0b3bd299 | |||
3713d111a4 | |||
111459dc25 | |||
cdad8bb0c3 | |||
96c41f399e | |||
c4d7d0213f | |||
2a5ee9b185 | |||
9aa3b16c92 | |||
4c3de09f6a | |||
f4650ead40 | |||
1d59af7491 | |||
8605e62503 | |||
3f779fe766 | |||
1d3460b670 | |||
feba3e2430 | |||
b49d39a685 | |||
34c1b3b68b | |||
e3d6ca6ab4 | |||
6f0e292c43 | |||
9df1e7900d | |||
9920d121e5 | |||
7e77c88407 | |||
3fa982cb2a | |||
4f1e767488 | |||
8e6b503c0d | |||
17f1cad468 | |||
0b8eaff874 | |||
33a6d4cdeb | |||
d3224f4ee8 | |||
2a3166bf7e | |||
62fe4d617b | |||
b86b36f947 | |||
d6b9e67e78 | |||
f589da4e72 | |||
2e5170f631 | |||
bd312b60fc | |||
26aa7e1fef | |||
9495956fae | |||
089ee86d43 | |||
d321e2f52c | |||
5265064b10 | |||
ee8313142f | |||
0963b68f4e | |||
a4a7ecd493 | |||
3b6e414d0f | |||
8859806d64 | |||
56198e503b | |||
b1b3a23d1e | |||
45dd004d00 | |||
c4ebc5c085 | |||
31c42f1104 | |||
8b7f665c82 | |||
0ca7579d19 | |||
2291ae98c3 | |||
16c6e29801 | |||
fc2eb003ea | |||
aa440c17b7 | |||
4915205678 | |||
07da5f7122 | |||
f91e02a0ec | |||
c62794c738 | |||
7664b428e7 | |||
9f3f34389e | |||
30ca926b38 | |||
eeb62f543f | |||
6a7ffa855e | |||
0c5aff21bc | |||
b0f426e51a | |||
57b91eb128 | |||
ed0094eba2 | |||
4c1b6d5f48 | |||
41a7e1ef07 | |||
4ff41be74a | |||
7067d1f236 | |||
73116b9d1a | |||
147212a5f9 | |||
5502c319d4 | |||
d18b76a47d | |||
90ce704def | |||
790139f8bc | |||
f4be007803 | |||
448ca62661 | |||
4824e5c8ba | |||
9882342ed1 | |||
c4facd53b4 | |||
ef913abc7a | |||
55fc5a6068 | |||
f22c89c998 | |||
2a78d2d0a0 | |||
b0ddc6a8c0 | |||
8080b0380e | |||
ddfa2abbaa | |||
5fc5e54f47 | |||
7462d56182 | |||
3f92d1c420 | |||
d4fa60f509 | |||
052bf88c3d | |||
07d047c887 | |||
23193314f1 | |||
1912b29dc5 | |||
46410428d9 | |||
1774e33c24 | |||
c961327d27 | |||
fe1ff7fc76 | |||
82d12ecfdf | |||
6ed822fa38 | |||
4d1658b35e | |||
08302a04bf | |||
1c906b12be | |||
4d835b18cc | |||
e02ff7ec30 | |||
2e67b0194b | |||
8b4558fcd0 | |||
27728abe99 | |||
467b95cf02 | |||
80a36a3441 | |||
b1b63fbb7f | |||
0302a95dd7 | |||
fe6bfb1620 | |||
3cad746407 | |||
e6d64bf5b3 | |||
8dd05d5431 | |||
270739a45a | |||
df8995deed | |||
02f0712934 | |||
7e7ea47f39 | |||
7e52711e3a | |||
40fd1c9c1f | |||
4037a444eb | |||
1ed7e900f2 | |||
cfc8d0a0f7 | |||
df33616544 | |||
fdfc6472d2 | |||
bc495828e7 | |||
fa138a273f | |||
5555dd4dde | |||
084ff2994f | |||
ee8a61d164 | |||
60a363e4bf | |||
e2804b9755 | |||
9330a03273 | |||
beabba2890 | |||
eeeb14a045 | |||
ff3f126832 | |||
73225917cd | |||
8b7a285f4a | |||
3a4c6a5d67 | |||
0664f0b6b2 | |||
fab9f1cb1b | |||
b3c54308b7 | |||
c1a72a0474 | |||
4377d1e86e | |||
cafe2f1e1f | |||
c329a724e8 | |||
969da05437 | |||
c61c84e9f3 | |||
e08c5ff875 | |||
d1fd616b8d | |||
cc4bbc049b | |||
24a3e787dd | |||
13a20478fd | |||
f58ee7fb52 | |||
4d45dc31a9 | |||
f6b5fbc2cf | |||
db69c3e38d | |||
5ba55356a9 | |||
6104b7c9ba | |||
bcef8369ff | |||
0fe555a76e | |||
c903c81bd5 | |||
2c43bfb13f | |||
24ecab0878 | |||
6285c79341 | |||
5f7c56fab4 | |||
6338b14a5b | |||
62ff3667f9 | |||
3b97eef641 | |||
b05d66466b | |||
220144c919 | |||
3b9402420d | |||
1324143146 | |||
595144cdd9 | |||
b3e714a741 | |||
2b3ae1e2d5 | |||
886845306a | |||
de6aaec088 | |||
137e0854ab | |||
b6a0e895bc | |||
05c791b1c0 | |||
669f3051e8 | |||
d945b56561 | |||
27333bbff1 | |||
80c800f233 | |||
5d17d3dd31 | |||
8c64fcd17f | |||
753110583e | |||
4206a8c43e | |||
7cc9ae45bc | |||
09ef58350c | |||
0b70007926 | |||
2c5d6e8187 | |||
10d3f9ac2f | |||
a6301055f0 | |||
9a1b8eb7c8 | |||
2ee45f388c | |||
9a9feea5ff | |||
8540e787d3 | |||
db26ce808e | |||
802d568273 | |||
7b6524357f | |||
83013f063d | |||
333ee3eed4 | |||
e68352b09c | |||
df1cb88abc | |||
5596caedbc | |||
7bd65120b9 | |||
227966e727 | |||
406f69080b | |||
2ce31dfaa5 | |||
b23afcfc3b | |||
7ed3ceb960 | |||
615cd7870d | |||
b907105f4a | |||
023423c6e7 | |||
a5319fc2fe | |||
8cfd3f9a2b | |||
814c797c64 | |||
776ad3cfbf | |||
74ddf70cb7 | |||
a7a839a29c | |||
9859c5db0a | |||
fe503c8de0 | |||
43a583e2d2 | |||
f289025d8e | |||
19cb310446 | |||
47f6d0ac59 | |||
922cbf932d | |||
c104eeebe6 | |||
80c3246333 | |||
461fed5567 | |||
d5f6714ed7 | |||
c42ed6bc99 | |||
57fed2b92b | |||
e45b33c6c2 | |||
137e90355b | |||
7500e622f6 | |||
d49c58f326 | |||
9814d3be03 | |||
fc9f86cccc | |||
6fd19c0a37 | |||
10cb412532 | |||
e12780f78f | |||
9dec13c225 | |||
69120da45c | |||
5b2bf7519a | |||
631cf77f89 | |||
6676e95011 | |||
3219cffb52 | |||
d4f149bc02 | |||
206cf4967d | |||
a67c53f46a | |||
e989c61793 | |||
99bab03cce | |||
a7567ad8c6 | |||
2ffa2fc6b8 | |||
8de87d9acb | |||
1d03b36750 | |||
8dc3c49a2f | |||
f6461b08d7 | |||
a3a3dde1c8 | |||
f111604b70 | |||
4315d1a03c | |||
9def45c8d7 | |||
358922b09b | |||
fbc3ac6b30 | |||
4f785da452 | |||
ff4bd1c91f | |||
7a96f9e894 | |||
c27d257146 | |||
9bccf9bb0a | |||
c0b05a62f4 | |||
c140c39d07 | |||
9a700e506b | |||
8e488670ad | |||
fd5b2298e5 | |||
caeaf8d5a9 | |||
c46f0781fc | |||
0aad0604d8 | |||
131c3fdb32 | |||
8a6009c278 | |||
3456527f10 | |||
28b913136d | |||
f700899640 | |||
5ba45d3037 | |||
212e966dd4 | |||
08c0eb2ec6 | |||
872ecd93a6 | |||
f8af9d6ce0 | |||
c3e43a7c2f | |||
273af0f1cb | |||
2a85e5ae87 | |||
114bb1b0bd | |||
97b5d120f8 | |||
e1f0fe45cb | |||
bc0f4973d8 | |||
5400882d78 | |||
8de66b27ad | |||
179f0097c0 | |||
b40bffdf38 | |||
2e9496bb74 | |||
d9d765c6cd | |||
10cc6856a4 | |||
813dd2894f | |||
80d90b91e8 | |||
fff05e35ac | |||
75bb59a22a | |||
3ce69bb391 | |||
4eb7c5f94b | |||
aac7e6be90 | |||
c77f4204c0 | |||
5f4452470b | |||
9a1270c693 | |||
7b9d1a1159 | |||
cdbe1f6161 | |||
e43db2e065 | |||
d1c74d2160 | |||
f2119ce567 | |||
2c4dcb9cf0 | |||
93b8266821 | |||
443797d9b0 | |||
a4365ca02c | |||
3750083667 | |||
66ef067ecf | |||
b489b0e691 | |||
f2154d9875 | |||
80a50f9bdb | |||
dc8b89a6b9 | |||
8df55f22aa | |||
f6c322be27 | |||
a144552059 | |||
535d529193 | |||
6ed2e137a2 | |||
45bd63c720 | |||
736e13fc35 | |||
966fff008c | |||
64f15eadbd | |||
81b66ecdcd | |||
53e5cf7826 | |||
82654b3fd9 | |||
9b72c604dd | |||
5fb1b8044c | |||
b8daab4377 | |||
c5b91bdae8 | |||
39a208c55f | |||
a5bfef9b6b | |||
f1f4cbef9b | |||
8388120b06 | |||
2bf96828f1 | |||
22838e66fe | |||
484dd6de09 | |||
b743736c26 | |||
af91e2079b | |||
cad1c17f14 | |||
120d32e4dc | |||
238b489e07 | |||
4daa70c894 | |||
f8599438df | |||
155c9a4c3f | |||
8433b5e583 | |||
dc5ba144f1 | |||
521a8b5356 | |||
3453077d7b | |||
70ede8581a | |||
6e9d297f02 | |||
6a7545fd43 | |||
a8926cbd07 | |||
64d7b009ab | |||
2b5fddb7bf | |||
b99d23c119 | |||
03905b74ff | |||
6b8a59cfbd | |||
d6fdcd3ef9 | |||
53ebc551d2 | |||
3d4f43d6e3 | |||
074cde7cd5 | |||
382e563590 | |||
ca61a7cc21 | |||
fa2870afe0 | |||
0f46207ea4 | |||
1e7d912144 | |||
f4a676e2fb | |||
b2c10e2387 | |||
8c329dca7d | |||
83da175749 | |||
995c87938f | |||
40678b2f84 | |||
8dbbe9102b | |||
2f51f354de | |||
04b815a33e | |||
2a4d68911b | |||
4d5a2d61ff | |||
efd88c27ad | |||
80d361ccd2 | |||
6ed4501615 | |||
8d34faa28e | |||
a3ae827839 | |||
88c1ad4c1c | |||
1147c4901b | |||
063181d7a7 | |||
1285ba6fbb | |||
a09a1793ec | |||
50caa3ac3e | |||
9440d24358 | |||
26bf6fd22f | |||
e2f836feae | |||
b6326f399c | |||
ea6a1422f7 | |||
8fd86a28ff | |||
d88283a7a9 | |||
32a15f84c0 | |||
93ba4b7f62 | |||
187780dab2 | |||
d988f37afc | |||
295c0bae3f | |||
38a22ddf13 | |||
d06f1abb89 | |||
027a64fad2 | |||
84fc54ddaa | |||
0b5caa85f5 | |||
14e0a17dbc | |||
3c04afa31f | |||
40a2a26904 | |||
c8b3c6e51a | |||
e0272a6422 | |||
b290bbf6d7 | |||
8d875cb01d | |||
36b1f8ba36 | |||
6c889eff27 | |||
9d8675e54b | |||
22ae986c0b | |||
2bef5f3911 | |||
3c2b8e5ee1 | |||
c96571bdba | |||
2dfd93afb1 | |||
f1d77d475c | |||
1d22e30c70 | |||
07b7951390 | |||
995615d0a0 | |||
ac273aab75 | |||
44cd03654d | |||
3e2375f970 | |||
38ad8e5fd3 | |||
c481558a46 | |||
e27a05a7fc | |||
e4886f0c6f | |||
8b2ce5476a | |||
1b82283a20 | |||
7f3d0113c2 | |||
0f6dd33a6b | |||
5b79b3fd22 | |||
d68c72f1fa | |||
9267d0c1dd | |||
865abc005a | |||
a2725d5b82 | |||
4a05bc6e02 | |||
4e8238603a | |||
ff25c1c057 | |||
78cddca0d7 | |||
4742ee1d93 | |||
0c2dc309e7 | |||
144935d10f | |||
74ad1b6759 | |||
591d2f89a1 | |||
7c353f9297 | |||
cd1af15c56 | |||
878169ea2e | |||
38dfb03668 | |||
e2631cec0e | |||
5dad853f8a | |||
9f00843441 | |||
f31cd7dec6 | |||
1c1afca31f | |||
fbd4bdef33 | |||
5b22f9b6c3 | |||
083e317028 | |||
95416623b3 | |||
813b2676de | |||
aeca66a288 | |||
04a5428148 | |||
73b173b92a | |||
7cbf20a71c | |||
7a98e6d92b | |||
49e915f98b | |||
3aa2f1e892 | |||
bc4b7ef44d | |||
9400b01a55 | |||
e57da71dcf | |||
7268afaaf9 | |||
205183445c | |||
a08bdfdbcd | |||
e6c47fee26 | |||
a5629c5155 | |||
41689fe3ce | |||
8e84208e2c | |||
32a48fa07a | |||
773a9c0692 | |||
8808e3afe0 | |||
ecea85f8ca | |||
5dfa141e35 | |||
447e81d0b8 | |||
e138076e1d | |||
721d133dc3 | |||
75b687ecbe | |||
bdd1863177 | |||
e5b85e8e6a | |||
d7481c9de7 | |||
571373866e | |||
e36d7928e4 | |||
2be026dd44 | |||
d5b9de3569 | |||
e22620b0ec | |||
ba74a3213d | |||
d9ecb7070d | |||
fc4a46bd9c | |||
78301b7bab | |||
7bf7bde856 | |||
9bdff14403 | |||
f124314eab | |||
684e4ffdcf | |||
d9ff5c69c8 | |||
8142e3df45 | |||
73920899de | |||
13666965a7 | |||
86f16e2781 | |||
2ed8e72c62 | |||
edeed18ae8 | |||
d24133d8a2 | |||
b9733e56aa | |||
cd34413914 | |||
c3a4a76d43 | |||
a59a29b256 | |||
dce1edbe53 | |||
264d43827a | |||
6207226bdf | |||
ebf33f39c9 | |||
696cd1f247 | |||
b7b3abc462 | |||
575739d07c | |||
2d7e70eebf | |||
387f3c981f | |||
865435fb25 | |||
b10c5306b9 | |||
7c706369cd | |||
20dd6355c1 | |||
ba8d5d6e27 | |||
c448f87027 | |||
2b8c70a61f | |||
9d7ed9a0ed | |||
ff69b4affe | |||
d77afd1ded | |||
c3909f9196 | |||
fa55ba5ef0 | |||
766518ee0e | |||
74b2b26a20 | |||
4ebbc6f065 | |||
3bd1eadd51 | |||
8eb3f0f708 | |||
31ea2e7139 | |||
323b4b4a5d | |||
7b8e1bea92 | |||
f986dc89ad | |||
b21fd10093 | |||
6f9c19b142 | |||
f45643ca87 | |||
85f8bea784 | |||
b428ec5237 | |||
92428529ad | |||
f6761b5b0b | |||
307b04f4ca | |||
6a520a5697 | |||
f22dbba931 | |||
82cf482fba | |||
a6afb99edd | |||
ac5f8465b9 | |||
218acb9e38 | |||
927c718fdd | |||
b7a6d6e739 | |||
0946d6a25d | |||
c1e98e2f0c | |||
807cbbeaaf | |||
6c358c4e0a | |||
74cd0bc08f | |||
b08ec0477e | |||
328c999cb9 | |||
c37e382c15 | |||
784dd0fdd6 | |||
e6256cb9c8 | |||
4520e3f8b8 | |||
23146de2bf | |||
e24f4fe3a8 | |||
8e6b69f96f | |||
979bea17ed | |||
30dba285d9 | |||
99fadf2e55 | |||
b606e3d0cb | |||
be642bc874 | |||
49a347b32f | |||
089b48aad1 | |||
2997cb83b1 | |||
08f0aca894 | |||
80ea7c40b7 | |||
019a0cb14d | |||
97290755e7 | |||
7f150c96b4 | |||
73558f30d1 | |||
dfcfd87644 | |||
2c0f0a68a8 | |||
3d73aac3ab | |||
e4fbcd3735 | |||
44c0eb37cf | |||
adc3dcc2c4 | |||
bac8227371 | |||
73d4d9dfe0 | |||
afdac5f3f8 | |||
dabce36667 | |||
3bd56ce522 | |||
540419d5c1 | |||
ed1fcc3930 | |||
c22ddc5394 | |||
0544864a3f | |||
0b9fc9e444 | |||
e862b97005 | |||
cffe09b02e | |||
846a86fb62 | |||
463c130351 | |||
ffca957838 | |||
543e949a48 | |||
feb80049aa | |||
5c59c8ccb6 | |||
1fadd82c65 | |||
7e7736126d | |||
5e0915afce | |||
bf6c9e8c4a | |||
3353aa0298 | |||
d4cb1a98c7 | |||
13f4ea0b8b | |||
261d57ad7b | |||
4086252979 | |||
8bdf12cff1 | |||
65a065c4ee | |||
a691ee529c | |||
f1c4a62612 | |||
358e39ced0 | |||
48c3f68cfc | |||
1849a7c383 | |||
82d14f37c3 | |||
a0261eafa3 | |||
2a27325dfd | |||
a6dee2e8ed | |||
2ff1635696 | |||
1cb6b5e984 | |||
1fe420fd80 | |||
50172e58d8 | |||
d7483d129f | |||
34ed0b3594 | |||
f008a3e20c | |||
9de950220f | |||
567c90b4c6 | |||
ae19236366 | |||
f9babe7089 | |||
78c74cd469 | |||
32abb27e61 | |||
8478b03892 | |||
e972f2b289 | |||
22c4fb1414 | |||
0154def916 | |||
fc69b6851d | |||
44a3c7fa5f | |||
37111fd07b | |||
4e6653e299 | |||
143a575369 | |||
c782585287 | |||
7718b3b3b8 | |||
8ff9e72972 | |||
ef6ef68a39 | |||
48a04744e0 | |||
6446ca8bb2 | |||
b9991465ee | |||
3d8242be06 | |||
344a8817c3 | |||
3afb0d4f6d | |||
c9714893bb | |||
3185a86b22 | |||
a53f7a49ac | |||
ca3bcc565d | |||
432176ea2f | |||
c1dae0b599 | |||
e70d3b6286 | |||
17e6bc921b | |||
46111e7cac | |||
3b7e47dbe2 | |||
fff99f0e3d | |||
2e15b24f0a | |||
088b9592cd | |||
b1e4e32b83 | |||
d91a852eda | |||
171c5b9759 | |||
64290b2a37 | |||
72769b8a0a | |||
1018309413 | |||
6d0ecd228e | |||
40a651e66c | |||
a390bb7b59 | |||
245ec65cbb | |||
17eea4a10c | |||
862fb0f5d2 | |||
ec73b53340 | |||
9110f7fee3 | |||
54cc1fdeef | |||
8f42a7f0b4 | |||
2c221ea819 | |||
93e0441b58 | |||
7f1455cb12 | |||
59fc223a85 | |||
0a6f555c23 | |||
6a4233d6fd | |||
15fa7e9652 | |||
f2acc154cd | |||
d21ec6c9a5 | |||
43dd858cd5 | |||
34cbf5f702 | |||
3c6e94b6a8 | |||
1cd149c815 | |||
4c6f562805 | |||
e59c4ec1c7 | |||
1169db7530 | |||
1453008796 | |||
2209b6d603 | |||
ccbc0384f9 | |||
a48924c896 | |||
dc8d8dd2b6 | |||
afca94ceb8 | |||
0b86231a36 | |||
c0df1f38b8 | |||
2b8fed8f4e | |||
c7322a32a0 | |||
64b75cab84 | |||
f58bc61999 | |||
fb8ccc0283 | |||
c38012f147 | |||
3676ff21c2 | |||
920e705d75 | |||
de0b137b1e | |||
d44ac6e2a3 | |||
71039a4012 | |||
8745ac7932 | |||
7f70048423 | |||
97dbfc8885 | |||
149ea22a93 | |||
404ed5406d | |||
b8656858ec | |||
6b0f0e8993 | |||
aec1ccd88d | |||
bee5c200b6 | |||
9d640efc88 | |||
f0907841dd | |||
2bffc12ef9 | |||
2ff9ec6522 | |||
43a54f5c54 | |||
7bff2734aa | |||
84768c0ec6 | |||
f4499a5459 | |||
b3aede5bba | |||
531ea1c039 | |||
c2c5ff6912 | |||
9cddab8fd5 | |||
06d15d8a27 | |||
b5c711854b | |||
4cf6c36f34 | |||
75a6f6c875 | |||
62abe3f256 | |||
9296c41650 | |||
7fb48fde6d | |||
174472bb45 | |||
17575ed921 | |||
b1b1a27444 | |||
f97a5eeefb | |||
10fd96981e | |||
67e3eb549c | |||
30a6d1f0b1 | |||
3d1fa9f048 | |||
1d2be6e68b | |||
c21e343986 | |||
ff37ed095c | |||
8623a2c3fc | |||
23d277eaf1 | |||
75ced59451 | |||
bccf424c5e | |||
2f9ae40d20 | |||
11e1eec3fb | |||
765c5633df | |||
6344b1aafb | |||
ed25801e6e | |||
4d0148193f | |||
804ae15c2e | |||
b35a9fad86 | |||
a4f83bd28a | |||
796f83c3d0 | |||
2099bbb713 | |||
67beba8f78 | |||
a798412e17 | |||
3b2c2d781f | |||
98c844f3d6 | |||
2645bd0132 | |||
2c4fc56b49 | |||
0ec1468058 | |||
5d1a3043b2 | |||
b46958d1f9 | |||
5daa8d5fe3 | |||
31846f1d05 | |||
1fac964b8b | |||
dfa6ed8ac2 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.1.37-beta
|
current_version = 0.9.0-pre7
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||||
@ -15,45 +15,10 @@ values =
|
|||||||
beta
|
beta
|
||||||
stable
|
stable
|
||||||
|
|
||||||
[bumpversion:file:client-packages/allauth/setup.py]
|
[bumpversion:file:helm/values.yaml]
|
||||||
|
|
||||||
[bumpversion:file:client-packages/sentry-auth-passbook/setup.py]
|
[bumpversion:file:helm/Chart.yaml]
|
||||||
|
|
||||||
[bumpversion:file:helm/passbook/values.yaml]
|
[bumpversion:file:.github/workflows/release.yml]
|
||||||
|
|
||||||
[bumpversion:file:helm/passbook/Chart.yaml]
|
|
||||||
|
|
||||||
[bumpversion:file:.gitlab-ci.yml]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/__init__.py]
|
[bumpversion:file:passbook/__init__.py]
|
||||||
|
|
||||||
[bumpversion:file:passbook/api/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/core/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/admin/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/captcha_factor/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/oauth_client/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/ldap/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/lib/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/hibp_policy/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/password_expiry_policy/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/saml_idp/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/audit/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/oauth_provider/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/otp/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/app_gw/__init__.py]
|
|
||||||
|
|
||||||
[bumpversion:file:passbook/suspicious_policy/__init__.py]
|
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[run]
|
[run]
|
||||||
source = passbook
|
source = passbook
|
||||||
omit =
|
omit =
|
||||||
env/
|
|
||||||
*/wsgi.py
|
*/wsgi.py
|
||||||
manage.py
|
manage.py
|
||||||
*/migrations/*
|
*/migrations/*
|
||||||
@ -22,6 +21,7 @@ exclude_lines =
|
|||||||
def __str__
|
def __str__
|
||||||
def __repr__
|
def __repr__
|
||||||
if self\.debug
|
if self\.debug
|
||||||
|
if TYPE_CHECKING
|
||||||
|
|
||||||
# Don't complain if tests don't hit defensive assertion code:
|
# Don't complain if tests don't hit defensive assertion code:
|
||||||
raise AssertionError
|
raise AssertionError
|
||||||
|
@ -2,3 +2,5 @@ env
|
|||||||
helm
|
helm
|
||||||
passbook-ui
|
passbook-ui
|
||||||
static
|
static
|
||||||
|
*.env.yml
|
||||||
|
node_modules/
|
||||||
|
20
.fossa.yml
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by FOSSA CLI (https://github.com/fossas/fossa-cli)
|
||||||
|
# Visit https://fossa.com to learn more
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
cli:
|
||||||
|
server: https://app.fossa.com
|
||||||
|
fetcher: custom
|
||||||
|
project: git@github.com:BeryJu/passbook.git
|
||||||
|
analyze:
|
||||||
|
modules:
|
||||||
|
- name: static
|
||||||
|
type: npm
|
||||||
|
target: passbook/static/static
|
||||||
|
path: passbook/static/static
|
||||||
|
- name: .
|
||||||
|
type: pip
|
||||||
|
target: .
|
||||||
|
path: .
|
||||||
|
options:
|
||||||
|
strategy: pipenv
|
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
custom: ["https://www.paypal.me/beryju"]
|
104
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
name: passbook-release
|
||||||
|
on:
|
||||||
|
release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build
|
||||||
|
build-server:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Docker Login Registry
|
||||||
|
env:
|
||||||
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
|
||||||
|
- name: Building Docker Image
|
||||||
|
run: docker build
|
||||||
|
--no-cache
|
||||||
|
-t beryju/passbook:0.9.0-pre7
|
||||||
|
-t beryju/passbook:latest
|
||||||
|
-f Dockerfile .
|
||||||
|
- name: Push Docker Container to Registry (versioned)
|
||||||
|
run: docker push beryju/passbook:0.9.0-pre7
|
||||||
|
- name: Push Docker Container to Registry (latest)
|
||||||
|
run: docker push beryju/passbook:latest
|
||||||
|
build-gatekeeper:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Docker Login Registry
|
||||||
|
env:
|
||||||
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
|
||||||
|
- name: Building Docker Image
|
||||||
|
run: |
|
||||||
|
cd gatekeeper
|
||||||
|
docker build \
|
||||||
|
--no-cache \
|
||||||
|
-t beryju/passbook-gatekeeper:0.9.0-pre7 \
|
||||||
|
-t beryju/passbook-gatekeeper:latest \
|
||||||
|
-f Dockerfile .
|
||||||
|
- name: Push Docker Container to Registry (versioned)
|
||||||
|
run: docker push beryju/passbook-gatekeeper:0.9.0-pre7
|
||||||
|
- name: Push Docker Container to Registry (latest)
|
||||||
|
run: docker push beryju/passbook-gatekeeper:latest
|
||||||
|
build-static:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:latest
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: passbook
|
||||||
|
POSTGRES_USER: passbook
|
||||||
|
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Docker Login Registry
|
||||||
|
env:
|
||||||
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
|
||||||
|
- name: Building Docker Image
|
||||||
|
run: docker build
|
||||||
|
--no-cache
|
||||||
|
--network=$(docker network ls | grep github | awk '{print $1}')
|
||||||
|
-t beryju/passbook-static:0.9.0-pre7
|
||||||
|
-t beryju/passbook-static:latest
|
||||||
|
-f static.Dockerfile .
|
||||||
|
- name: Push Docker Container to Registry (versioned)
|
||||||
|
run: docker push beryju/passbook-static:0.9.0-pre7
|
||||||
|
- name: Push Docker Container to Registry (latest)
|
||||||
|
run: docker push beryju/passbook-static:latest
|
||||||
|
test-release:
|
||||||
|
needs:
|
||||||
|
- build-server
|
||||||
|
- build-static
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Run test suite in final docker images
|
||||||
|
run: |
|
||||||
|
docker-compose pull -q
|
||||||
|
docker-compose up --no-start
|
||||||
|
docker-compose start postgresql redis
|
||||||
|
docker-compose run -u root server bash -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test"
|
||||||
|
sentry-release:
|
||||||
|
needs:
|
||||||
|
- test-release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Create a Sentry.io release
|
||||||
|
uses: tclindner/sentry-releases-action@v1.2.0
|
||||||
|
env:
|
||||||
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
|
SENTRY_ORG: beryjuorg
|
||||||
|
SENTRY_PROJECT: passbook
|
||||||
|
SENTRY_URL: https://sentry.beryju.org
|
||||||
|
with:
|
||||||
|
tagName: 0.9.0-pre7
|
||||||
|
environment: production
|
59
.github/workflows/tag.yml
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'version/*'
|
||||||
|
|
||||||
|
name: passbook-version-tag
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Create Release from Tag
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
- name: Pre-release test
|
||||||
|
run: |
|
||||||
|
docker-compose pull -q
|
||||||
|
docker build \
|
||||||
|
--no-cache \
|
||||||
|
-t beryju/passbook:latest \
|
||||||
|
-f Dockerfile .
|
||||||
|
docker-compose up --no-start
|
||||||
|
docker-compose start postgresql redis
|
||||||
|
docker-compose run -u root server bash -c "pip install --no-cache -r requirements-dev.txt && ./manage.py test"
|
||||||
|
- name: Install Helm
|
||||||
|
run: |
|
||||||
|
apt update && apt install -y curl
|
||||||
|
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||||
|
- name: Helm package
|
||||||
|
run: |
|
||||||
|
helm dependency update helm/
|
||||||
|
helm package helm/
|
||||||
|
mv passbook-*.tgz passbook-chart.tgz
|
||||||
|
- name: Extract verison number
|
||||||
|
id: get_version
|
||||||
|
uses: actions/github-script@0.2.0
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
return context.payload.ref.replace(/\/refs\/tags\/version\//, '');
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1.0.0
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: Release ${{ steps.get_version.outputs.result }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
- name: Upload packaged Helm Chart
|
||||||
|
id: upload-release-asset
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: ./passbook-chart.tgz
|
||||||
|
asset_name: passbook-chart.tgz
|
||||||
|
asset_content_type: application/gzip
|
10
.gitignore
vendored
@ -63,6 +63,7 @@ coverage.xml
|
|||||||
*.cover
|
*.cover
|
||||||
.hypothesis/
|
.hypothesis/
|
||||||
.pytest_cache/
|
.pytest_cache/
|
||||||
|
unittest.xml
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
@ -184,10 +185,17 @@ dmypy.json
|
|||||||
[Ii]nclude
|
[Ii]nclude
|
||||||
[Ll]ib64
|
[Ll]ib64
|
||||||
[Ll]ocal
|
[Ll]ocal
|
||||||
[Ss]cripts
|
|
||||||
pyvenv.cfg
|
pyvenv.cfg
|
||||||
pip-selfcheck.json
|
pip-selfcheck.json
|
||||||
|
|
||||||
# End of https://www.gitignore.io/api/python,django
|
# End of https://www.gitignore.io/api/python,django
|
||||||
/static/
|
/static/
|
||||||
local.env.yml
|
local.env.yml
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Helm ###
|
||||||
|
# Chart dependencies
|
||||||
|
**/charts/*.tgz
|
||||||
|
|
||||||
|
# Selenium Screenshots
|
||||||
|
selenium_screenshots/**
|
||||||
|
109
.gitlab-ci.yml
@ -1,109 +0,0 @@
|
|||||||
# Global Variables
|
|
||||||
stages:
|
|
||||||
- build-buildimage
|
|
||||||
- test
|
|
||||||
- build
|
|
||||||
- docs
|
|
||||||
- deploy
|
|
||||||
image: docker.beryju.org/passbook/build-base:latest
|
|
||||||
services:
|
|
||||||
- postgres:latest
|
|
||||||
- redis:latest
|
|
||||||
|
|
||||||
variables:
|
|
||||||
POSTGRES_DB: passbook
|
|
||||||
POSTGRES_USER: passbook
|
|
||||||
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
|
||||||
|
|
||||||
create-build-image:
|
|
||||||
image:
|
|
||||||
name: gcr.io/kaniko-project/executor:debug
|
|
||||||
entrypoint: [""]
|
|
||||||
before_script:
|
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
|
||||||
script:
|
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile.build-base --destination docker.beryju.org/passbook/build-base:latest --destination docker.beryju.org/passbook/build-base:0.1.37-beta
|
|
||||||
stage: build-buildimage
|
|
||||||
only:
|
|
||||||
refs:
|
|
||||||
- tags
|
|
||||||
- /^version/.*$/
|
|
||||||
|
|
||||||
isort:
|
|
||||||
script:
|
|
||||||
- isort -c -sg env
|
|
||||||
stage: test
|
|
||||||
migrations:
|
|
||||||
script:
|
|
||||||
- python manage.py migrate
|
|
||||||
stage: test
|
|
||||||
prospector:
|
|
||||||
script:
|
|
||||||
- prospector
|
|
||||||
stage: test
|
|
||||||
pylint:
|
|
||||||
script:
|
|
||||||
- pylint passbook
|
|
||||||
stage: test
|
|
||||||
coverage:
|
|
||||||
script:
|
|
||||||
- python manage.py collectstatic --no-input
|
|
||||||
- coverage run manage.py test
|
|
||||||
- coverage report
|
|
||||||
stage: test
|
|
||||||
bandit:
|
|
||||||
script:
|
|
||||||
- bandit -r passbook
|
|
||||||
stage: test
|
|
||||||
|
|
||||||
package-docker:
|
|
||||||
image:
|
|
||||||
name: gcr.io/kaniko-project/executor:debug
|
|
||||||
entrypoint: [""]
|
|
||||||
before_script:
|
|
||||||
- echo "{\"auths\":{\"docker.beryju.org\":{\"auth\":\"$DOCKER_AUTH\"}}}" > /kaniko/.docker/config.json
|
|
||||||
script:
|
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.beryju.org/passbook/server:latest --destination docker.beryju.org/passbook/server:0.1.37-beta
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
- /^version/.*$/
|
|
||||||
package-helm:
|
|
||||||
stage: build
|
|
||||||
script:
|
|
||||||
- curl https://raw.githubusercontent.com/helm/helm/master/scripts/get | bash
|
|
||||||
- helm init --client-only
|
|
||||||
- helm package helm/passbook
|
|
||||||
artifacts:
|
|
||||||
paths:
|
|
||||||
- passbook-*.tgz
|
|
||||||
expire_in: 2 days
|
|
||||||
only:
|
|
||||||
- tags
|
|
||||||
- /^version/.*$/
|
|
||||||
|
|
||||||
package-client-package-allauth:
|
|
||||||
script:
|
|
||||||
- cd client-packages/allauth
|
|
||||||
- python setup.py sdist
|
|
||||||
- twine upload --username $TWINE_USERNAME --password $TWINE_PASSWORD dist/*
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
refs:
|
|
||||||
- tags
|
|
||||||
- /^version/.*$/
|
|
||||||
changes:
|
|
||||||
- client-packages/allauth/**
|
|
||||||
|
|
||||||
package-client-package-sentry:
|
|
||||||
script:
|
|
||||||
- cd client-packages/sentry-auth-passbook
|
|
||||||
- python setup.py sdist
|
|
||||||
- twine upload --username $TWINE_USERNAME --password $TWINE_PASSWORD dist/*
|
|
||||||
stage: build
|
|
||||||
only:
|
|
||||||
refs:
|
|
||||||
- tags
|
|
||||||
- /^version/.*$/
|
|
||||||
changes:
|
|
||||||
- client-packages/sentry-auth-passbook/**
|
|
6
.isort.cfg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[settings]
|
||||||
|
multi_line_output=3
|
||||||
|
include_trailing_comma=True
|
||||||
|
force_grid_wrap=0
|
||||||
|
use_parentheses=True
|
||||||
|
line_length=88
|
@ -3,11 +3,9 @@ test-warnings: true
|
|||||||
doc-warnings: false
|
doc-warnings: false
|
||||||
|
|
||||||
ignore-paths:
|
ignore-paths:
|
||||||
- env
|
|
||||||
- migrations
|
- migrations
|
||||||
- docs
|
- docs
|
||||||
- node_modules
|
- node_modules
|
||||||
- client-packages
|
|
||||||
|
|
||||||
uses:
|
uses:
|
||||||
- django
|
- django
|
||||||
|
11
.pylintrc
@ -1,12 +1,9 @@
|
|||||||
[MASTER]
|
[MASTER]
|
||||||
|
|
||||||
disable=redefined-outer-name,arguments-differ,no-self-use,cyclic-import,fixme,locally-disabled,unpacking-non-sequence,too-many-ancestors,too-many-branches,too-few-public-methods
|
disable=redefined-outer-name,arguments-differ,no-self-use,cyclic-import,fixme,locally-disabled,too-many-ancestors,too-few-public-methods,import-outside-toplevel,bad-continuation,signature-differs
|
||||||
load-plugins=pylint_django,pylint.extensions.bad_builtin
|
load-plugins=pylint_django,pylint.extensions.bad_builtin
|
||||||
#,pylint.extensions.docparams
|
|
||||||
extension-pkg-whitelist=lxml
|
extension-pkg-whitelist=lxml
|
||||||
const-rgx=[a-zA-Z0-9_]{1,40}$
|
const-rgx=[a-zA-Z0-9_]{1,40}$
|
||||||
|
ignored-modules=django-otp
|
||||||
[SIMILARITIES]
|
jobs=12
|
||||||
|
ignore=migrations
|
||||||
# Minimum lines number of a similarity.
|
|
||||||
min-similarity-lines=20
|
|
||||||
|
114
.vscode/.ropeproject/config.py
vendored
@ -1,114 +0,0 @@
|
|||||||
# The default ``config.py``
|
|
||||||
# flake8: noqa
|
|
||||||
|
|
||||||
|
|
||||||
def set_prefs(prefs):
|
|
||||||
"""This function is called before opening the project"""
|
|
||||||
|
|
||||||
# Specify which files and folders to ignore in the project.
|
|
||||||
# Changes to ignored resources are not added to the history and
|
|
||||||
# VCSs. Also they are not returned in `Project.get_files()`.
|
|
||||||
# Note that ``?`` and ``*`` match all characters but slashes.
|
|
||||||
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
|
|
||||||
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
|
|
||||||
# '.svn': matches 'pkg/.svn' and all of its children
|
|
||||||
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
|
|
||||||
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
|
|
||||||
prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
|
|
||||||
'.hg', '.svn', '_svn', '.git', '.tox']
|
|
||||||
|
|
||||||
# Specifies which files should be considered python files. It is
|
|
||||||
# useful when you have scripts inside your project. Only files
|
|
||||||
# ending with ``.py`` are considered to be python files by
|
|
||||||
# default.
|
|
||||||
# prefs['python_files'] = ['*.py']
|
|
||||||
|
|
||||||
# Custom source folders: By default rope searches the project
|
|
||||||
# for finding source folders (folders that should be searched
|
|
||||||
# for finding modules). You can add paths to that list. Note
|
|
||||||
# that rope guesses project source folders correctly most of the
|
|
||||||
# time; use this if you have any problems.
|
|
||||||
# The folders should be relative to project root and use '/' for
|
|
||||||
# separating folders regardless of the platform rope is running on.
|
|
||||||
# 'src/my_source_folder' for instance.
|
|
||||||
# prefs.add('source_folders', 'src')
|
|
||||||
|
|
||||||
# You can extend python path for looking up modules
|
|
||||||
# prefs.add('python_path', '~/python/')
|
|
||||||
|
|
||||||
# Should rope save object information or not.
|
|
||||||
prefs['save_objectdb'] = True
|
|
||||||
prefs['compress_objectdb'] = False
|
|
||||||
|
|
||||||
# If `True`, rope analyzes each module when it is being saved.
|
|
||||||
prefs['automatic_soa'] = True
|
|
||||||
# The depth of calls to follow in static object analysis
|
|
||||||
prefs['soa_followed_calls'] = 0
|
|
||||||
|
|
||||||
# If `False` when running modules or unit tests "dynamic object
|
|
||||||
# analysis" is turned off. This makes them much faster.
|
|
||||||
prefs['perform_doa'] = True
|
|
||||||
|
|
||||||
# Rope can check the validity of its object DB when running.
|
|
||||||
prefs['validate_objectdb'] = True
|
|
||||||
|
|
||||||
# How many undos to hold?
|
|
||||||
prefs['max_history_items'] = 32
|
|
||||||
|
|
||||||
# Shows whether to save history across sessions.
|
|
||||||
prefs['save_history'] = True
|
|
||||||
prefs['compress_history'] = False
|
|
||||||
|
|
||||||
# Set the number spaces used for indenting. According to
|
|
||||||
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
|
|
||||||
# unit-tests use 4 spaces it is more reliable, too.
|
|
||||||
prefs['indent_size'] = 4
|
|
||||||
|
|
||||||
# Builtin and c-extension modules that are allowed to be imported
|
|
||||||
# and inspected by rope.
|
|
||||||
prefs['extension_modules'] = []
|
|
||||||
|
|
||||||
# Add all standard c-extensions to extension_modules list.
|
|
||||||
prefs['import_dynload_stdmods'] = True
|
|
||||||
|
|
||||||
# If `True` modules with syntax errors are considered to be empty.
|
|
||||||
# The default value is `False`; When `False` syntax errors raise
|
|
||||||
# `rope.base.exceptions.ModuleSyntaxError` exception.
|
|
||||||
prefs['ignore_syntax_errors'] = False
|
|
||||||
|
|
||||||
# If `True`, rope ignores unresolvable imports. Otherwise, they
|
|
||||||
# appear in the importing namespace.
|
|
||||||
prefs['ignore_bad_imports'] = False
|
|
||||||
|
|
||||||
# If `True`, rope will insert new module imports as
|
|
||||||
# `from <package> import <module>` by default.
|
|
||||||
prefs['prefer_module_from_imports'] = False
|
|
||||||
|
|
||||||
# If `True`, rope will transform a comma list of imports into
|
|
||||||
# multiple separate import statements when organizing
|
|
||||||
# imports.
|
|
||||||
prefs['split_imports'] = False
|
|
||||||
|
|
||||||
# If `True`, rope will remove all top-level import statements and
|
|
||||||
# reinsert them at the top of the module when making changes.
|
|
||||||
prefs['pull_imports_to_top'] = True
|
|
||||||
|
|
||||||
# If `True`, rope will sort imports alphabetically by module name instead
|
|
||||||
# of alphabetically by import statement, with from imports after normal
|
|
||||||
# imports.
|
|
||||||
prefs['sort_imports_alphabetically'] = False
|
|
||||||
|
|
||||||
# Location of implementation of
|
|
||||||
# rope.base.oi.type_hinting.interfaces.ITypeHintingFactory In general
|
|
||||||
# case, you don't have to change this value, unless you're an rope expert.
|
|
||||||
# Change this value to inject you own implementations of interfaces
|
|
||||||
# listed in module rope.base.oi.type_hinting.providers.interfaces
|
|
||||||
# For example, you can add you own providers for Django Models, or disable
|
|
||||||
# the search type-hinting in a class hierarchy, etc.
|
|
||||||
prefs['type_hinting_factory'] = (
|
|
||||||
'rope.base.oi.type_hinting.factory.default_type_hinting_factory')
|
|
||||||
|
|
||||||
|
|
||||||
def project_opened(project):
|
|
||||||
"""This function is called after opening the project"""
|
|
||||||
# Do whatever you like here!
|
|
BIN
.vscode/.ropeproject/objectdb
vendored
14
.vscode/settings.json
vendored
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"python.pythonPath": "env/bin/python",
|
|
||||||
"editor.tabSize": 4,
|
|
||||||
"[html]": {
|
|
||||||
"editor.tabSize": 2
|
|
||||||
},
|
|
||||||
"[yml]": {
|
|
||||||
"editor.tabSize": 2
|
|
||||||
},
|
|
||||||
"cSpell.words": [
|
|
||||||
"SAML",
|
|
||||||
"passbook"
|
|
||||||
]
|
|
||||||
}
|
|
47
Dockerfile
@ -1,34 +1,35 @@
|
|||||||
FROM python:3.6-slim-stretch as build
|
FROM python:3.8-slim-buster as locker
|
||||||
|
|
||||||
COPY ./passbook/ /app/passbook
|
COPY ./Pipfile /app/
|
||||||
COPY ./manage.py /app/
|
COPY ./Pipfile.lock /app/
|
||||||
COPY ./requirements.txt /app/
|
|
||||||
|
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
|
|
||||||
RUN apt-get update && apt-get install build-essential libssl-dev libffi-dev libpq-dev -y && \
|
RUN pip install pipenv && \
|
||||||
mkdir /app/static/ && \
|
pipenv lock -r > requirements.txt && \
|
||||||
pip install -r requirements.txt && \
|
pipenv lock -rd > requirements-dev.txt
|
||||||
pip install psycopg2 && \
|
|
||||||
./manage.py collectstatic --no-input && \
|
|
||||||
apt-get remove --purge -y build-essential && \
|
|
||||||
apt-get autoremove --purge -y
|
|
||||||
|
|
||||||
FROM python:3.6-slim-stretch
|
FROM python:3.8-slim-buster
|
||||||
|
|
||||||
COPY ./passbook/ /app/passbook
|
COPY --from=locker /app/requirements.txt /app/
|
||||||
COPY ./manage.py /app/
|
COPY --from=locker /app/requirements-dev.txt /app/
|
||||||
COPY ./requirements.txt /app/
|
|
||||||
COPY --from=build /app/static /app/static/
|
|
||||||
|
|
||||||
WORKDIR /app/
|
WORKDIR /app/
|
||||||
|
|
||||||
RUN apt-get update && apt-get install build-essential libssl-dev libffi-dev libpq-dev -y && \
|
RUN apt-get update && \
|
||||||
pip install -r requirements.txt && \
|
apt-get install -y --no-install-recommends postgresql-client-11 && \
|
||||||
pip install psycopg2 && \
|
rm -rf /var/lib/apt/ && \
|
||||||
adduser --system --home /app/ passbook && \
|
pip install -r requirements.txt --no-cache-dir && \
|
||||||
chown -R passbook /app/ && \
|
adduser --system --no-create-home --uid 1000 --group --home /app passbook
|
||||||
apt-get remove --purge -y build-essential && \
|
|
||||||
apt-get autoremove --purge -y
|
COPY ./passbook/ /app/passbook
|
||||||
|
COPY ./manage.py /app/
|
||||||
|
COPY ./docker/uwsgi.ini /app/
|
||||||
|
COPY ./docker/bootstrap.sh /bootstrap.sh
|
||||||
|
COPY ./docker/wait_for_db.py /app/wait_for_db.py
|
||||||
|
|
||||||
|
WORKDIR /app/
|
||||||
|
|
||||||
USER passbook
|
USER passbook
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/bootstrap.sh" ]
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
FROM python:3.6
|
|
||||||
|
|
||||||
COPY ./passbook/ /app/passbook
|
|
||||||
COPY ./client-packages/ /app/client-packages
|
|
||||||
COPY ./requirements.txt /app/
|
|
||||||
COPY ./requirements-dev.txt /app/
|
|
||||||
|
|
||||||
WORKDIR /app/
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install libssl-dev libffi-dev libpq-dev -y && \
|
|
||||||
pip install -U -r requirements-dev.txt && \
|
|
||||||
rm -rf /app/*
|
|
64
Pipfile
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
boto3 = "*"
|
||||||
|
celery = "*"
|
||||||
|
defusedxml = "*"
|
||||||
|
django = "*"
|
||||||
|
django-cors-middleware = "*"
|
||||||
|
django-dbbackup = "*"
|
||||||
|
django-filter = "*"
|
||||||
|
django-guardian = "*"
|
||||||
|
django-model-utils = "*"
|
||||||
|
django-oauth-toolkit = "*"
|
||||||
|
django-oidc-provider = "*"
|
||||||
|
django-otp = "*"
|
||||||
|
django-prometheus = "*"
|
||||||
|
django-recaptcha = "*"
|
||||||
|
django-redis = "*"
|
||||||
|
django-rest-framework = "*"
|
||||||
|
django-storages = "*"
|
||||||
|
djangorestframework-guardian = "*"
|
||||||
|
drf-yasg = "*"
|
||||||
|
kombu = "*"
|
||||||
|
ldap3 = "*"
|
||||||
|
lxml = "*"
|
||||||
|
oauthlib = "*"
|
||||||
|
packaging = "*"
|
||||||
|
psycopg2-binary = "*"
|
||||||
|
pycryptodome = "*"
|
||||||
|
pyuwsgi = "*"
|
||||||
|
pyyaml = "*"
|
||||||
|
qrcode = "*"
|
||||||
|
requests-oauthlib = "*"
|
||||||
|
sentry-sdk = "*"
|
||||||
|
service_identity = "*"
|
||||||
|
signxml = "*"
|
||||||
|
structlog = "*"
|
||||||
|
swagger-spec-validator = "*"
|
||||||
|
urllib3 = {extras = ["secure"],version = "*"}
|
||||||
|
facebook-sdk = "*"
|
||||||
|
elastic-apm = "*"
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
autopep8 = "*"
|
||||||
|
bandit = "*"
|
||||||
|
bumpversion = "*"
|
||||||
|
colorama = "*"
|
||||||
|
coverage = "*"
|
||||||
|
django-debug-toolbar = "*"
|
||||||
|
pylint = "*"
|
||||||
|
pylint-django = "*"
|
||||||
|
unittest-xml-reporting = "*"
|
||||||
|
black = "*"
|
||||||
|
selenium = "*"
|
||||||
|
docker = "*"
|
||||||
|
|
||||||
|
[pipenv]
|
||||||
|
allow_prereleases = true
|
1345
Pipfile.lock
generated
Normal file
69
README.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<img src="passbook/static/static/passbook/logo.svg" height="50" alt="passbook logo"><img src="passbook/static/static/passbook/brand_inverted.svg" height="50" alt="passbook">
|
||||||
|
|
||||||
|
=======
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## What is passbook?
|
||||||
|
|
||||||
|
passbook is an open-source Identity Provider focused on flexibility and versatility. You can use passbook in an existing environment to add support for new protocols. passbook is also a great solution for implementing signup/recovery/etc in your application, so you don't have to deal with it.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
For small/test setups it is recommended to use docker-compose.
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml
|
||||||
|
# Optionally enable Error-reporting
|
||||||
|
# export PASSBOOK_ERROR_REPORTING=true
|
||||||
|
# Optionally deploy a different version
|
||||||
|
# export PASSBOOK_TAG=0.8.15-beta
|
||||||
|
# If this is a productive installation, set a different PostgreSQL Password
|
||||||
|
# export PG_PASS=$(pwgen 40 1)
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose exec server ./manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
For bigger setups, there is a Helm Chart in the `helm/` directory. This is documented [here](https://passbook.beryju.org//installation/kubernetes/)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
To develop on passbook, you need a system with Python 3.7+ (3.8 is recommended). passbook uses [pipenv](https://pipenv.pypa.io/en/latest/) for managing dependencies.
|
||||||
|
|
||||||
|
To get started, run
|
||||||
|
|
||||||
|
```
|
||||||
|
python3 -m pip install pipenv
|
||||||
|
git clone https://github.com/BeryJu/passbook.git
|
||||||
|
cd passbook
|
||||||
|
pipenv shell
|
||||||
|
pipenv sync -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Since passbook uses PostgreSQL-specific fields, you also need a local PostgreSQL instance to develop. passbook also uses redis for caching and message queueing.
|
||||||
|
For these databases you can use [Postgres.app](https://postgresapp.com/) and [Redis.app](https://jpadilla.github.io/redisapp/) on macOS or use it the docker-compose file in `scripts/docker-compose.yml`.
|
||||||
|
|
||||||
|
To tell passbook about these databases, create a file in the project root called `local.env.yml` with the following contents:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
debug: true
|
||||||
|
postgresql:
|
||||||
|
user: postgres
|
||||||
|
|
||||||
|
log_level: debug
|
||||||
|
error_reporting: false
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
See [SECURITY.md](SECURITY.md)
|
13
SECURITY.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
As passbook is currently in a pre-stable, only the latest "stable" version is supported. After passbook 1.0, this will change.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| -------- | ------------------ |
|
||||||
|
| 0.8.15 | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
To report a vulnerability, send am email to [security@beryju.org](mailto:security@beryju.org)
|
228
azure-pipelines.yml
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
trigger:
|
||||||
|
- master
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- repo: self
|
||||||
|
|
||||||
|
variables:
|
||||||
|
POSTGRES_DB: passbook
|
||||||
|
POSTGRES_USER: passbook
|
||||||
|
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- stage: Lint
|
||||||
|
jobs:
|
||||||
|
- job: pylint
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run pylint passbook
|
||||||
|
- job: black
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run black --check passbook
|
||||||
|
- job: prospector
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
pipenv install --dev prospector --skip-lock
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run prospector passbook
|
||||||
|
- job: bandit
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run bandit -r passbook
|
||||||
|
- job: pyright
|
||||||
|
pool:
|
||||||
|
vmImage: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- task: UseNode@1
|
||||||
|
inputs:
|
||||||
|
version: '12.x'
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: npm install -g pyright
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run pyright
|
||||||
|
- stage: Test
|
||||||
|
jobs:
|
||||||
|
- job: migrations
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: DockerCompose@0
|
||||||
|
displayName: Run services
|
||||||
|
inputs:
|
||||||
|
dockerComposeFile: 'scripts/docker-compose.yml'
|
||||||
|
action: 'Run services'
|
||||||
|
buildImages: false
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: pipenv run ./manage.py migrate
|
||||||
|
- job: coverage
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: UsePythonVersion@0
|
||||||
|
inputs:
|
||||||
|
versionSpec: '3.8'
|
||||||
|
- task: DockerCompose@0
|
||||||
|
displayName: Run services
|
||||||
|
inputs:
|
||||||
|
dockerComposeFile: 'scripts/docker-compose.yml'
|
||||||
|
action: 'Run services'
|
||||||
|
buildImages: false
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
sudo pip install -U wheel pipenv
|
||||||
|
pipenv install --dev
|
||||||
|
- task: DockerCompose@0
|
||||||
|
displayName: Run ChromeDriver
|
||||||
|
inputs:
|
||||||
|
dockerComposeFile: 'e2e/docker-compose.yml'
|
||||||
|
action: 'Run a specific service'
|
||||||
|
serviceName: 'chrome'
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: Build static files for e2e
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
cd passbook/static/static
|
||||||
|
yarn
|
||||||
|
- task: CmdLine@2
|
||||||
|
displayName: Run full test suite
|
||||||
|
inputs:
|
||||||
|
script: pipenv run coverage run ./manage.py test --failfast
|
||||||
|
- task: PublishBuildArtifacts@1
|
||||||
|
condition: failed()
|
||||||
|
displayName: Upload screenshots if selenium tests fail
|
||||||
|
inputs:
|
||||||
|
PathtoPublish: 'selenium_screenshots/'
|
||||||
|
ArtifactName: 'drop'
|
||||||
|
publishLocation: 'Container'
|
||||||
|
- task: CmdLine@2
|
||||||
|
inputs:
|
||||||
|
script: |
|
||||||
|
pipenv run coverage xml
|
||||||
|
pipenv run coverage html
|
||||||
|
- task: PublishCodeCoverageResults@1
|
||||||
|
inputs:
|
||||||
|
codeCoverageTool: Cobertura
|
||||||
|
summaryFileLocation: 'coverage.xml'
|
||||||
|
- task: PublishTestResults@2
|
||||||
|
condition: succeededOrFailed()
|
||||||
|
inputs:
|
||||||
|
testRunTitle: 'Publish test results for Python $(python.version)'
|
||||||
|
testResultsFiles: 'unittest.xml'
|
||||||
|
- task: CmdLine@2
|
||||||
|
env:
|
||||||
|
CODECOV_TOKEN: $(CODECOV_TOKEN)
|
||||||
|
inputs:
|
||||||
|
script: bash <(curl -s https://codecov.io/bash)
|
||||||
|
- stage: Build
|
||||||
|
jobs:
|
||||||
|
- job: build_server
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
containerRegistry: 'dockerhub'
|
||||||
|
repository: 'beryju/passbook'
|
||||||
|
command: 'buildAndPush'
|
||||||
|
Dockerfile: 'Dockerfile'
|
||||||
|
tags: 'gh-$(Build.SourceBranchName)'
|
||||||
|
- job: build_gatekeeper
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
containerRegistry: 'dockerhub'
|
||||||
|
repository: 'beryju/passbook-gatekeeper'
|
||||||
|
command: 'buildAndPush'
|
||||||
|
Dockerfile: 'gatekeeper/Dockerfile'
|
||||||
|
buildContext: 'gatekeeper/'
|
||||||
|
tags: 'gh-$(Build.SourceBranchName)'
|
||||||
|
- job: build_static
|
||||||
|
pool:
|
||||||
|
vmImage: 'ubuntu-latest'
|
||||||
|
steps:
|
||||||
|
- task: DockerCompose@0
|
||||||
|
displayName: Run services
|
||||||
|
inputs:
|
||||||
|
dockerComposeFile: 'scripts/docker-compose.yml'
|
||||||
|
action: 'Run services'
|
||||||
|
buildImages: false
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
containerRegistry: 'dockerhub'
|
||||||
|
repository: 'beryju/passbook-static'
|
||||||
|
command: 'build'
|
||||||
|
Dockerfile: 'static.Dockerfile'
|
||||||
|
tags: 'gh-$(Build.SourceBranchName)'
|
||||||
|
arguments: "--network=beryjupassbook_default"
|
||||||
|
- task: Docker@2
|
||||||
|
inputs:
|
||||||
|
containerRegistry: 'dockerhub'
|
||||||
|
repository: 'beryju/passbook-static'
|
||||||
|
command: 'push'
|
||||||
|
tags: 'gh-$(Build.SourceBranchName)'
|
@ -1,35 +0,0 @@
|
|||||||
"""passbook provider"""
|
|
||||||
from allauth.socialaccount.providers.base import ProviderAccount
|
|
||||||
from allauth.socialaccount.providers.oauth2.provider import OAuth2Provider
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookAccount(ProviderAccount):
|
|
||||||
"""passbook account"""
|
|
||||||
|
|
||||||
def to_str(self):
|
|
||||||
dflt = super().to_str()
|
|
||||||
return self.account.extra_data.get('username', dflt)
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookProvider(OAuth2Provider):
|
|
||||||
"""passbook provider"""
|
|
||||||
|
|
||||||
id = 'passbook'
|
|
||||||
name = 'passbook'
|
|
||||||
account_class = PassbookAccount
|
|
||||||
|
|
||||||
def extract_uid(self, data):
|
|
||||||
return str(data['sub'])
|
|
||||||
|
|
||||||
def extract_common_fields(self, data):
|
|
||||||
return {
|
|
||||||
'email': data.get('email'),
|
|
||||||
'username': data.get('preferred_username'),
|
|
||||||
'name': data.get('name'),
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_default_scope(self):
|
|
||||||
return ['openid:userinfo']
|
|
||||||
|
|
||||||
|
|
||||||
provider_classes = [PassbookProvider] # noqa
|
|
@ -1,6 +0,0 @@
|
|||||||
"""passbook provider"""
|
|
||||||
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
|
||||||
|
|
||||||
from allauth_passbook.provider import PassbookProvider
|
|
||||||
|
|
||||||
urlpatterns = default_urlpatterns(PassbookProvider)
|
|
@ -1,37 +0,0 @@
|
|||||||
"""passbook adapter"""
|
|
||||||
import requests
|
|
||||||
from allauth.socialaccount import app_settings
|
|
||||||
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
|
||||||
OAuth2CallbackView,
|
|
||||||
OAuth2LoginView)
|
|
||||||
|
|
||||||
from allauth_passbook.provider import PassbookProvider
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookOAuth2Adapter(OAuth2Adapter):
|
|
||||||
"""passbook OAuth2 Adapter"""
|
|
||||||
provider_id = PassbookProvider.id
|
|
||||||
# pylint: disable=no-member
|
|
||||||
settings = app_settings.PROVIDERS.get(provider_id, {}) # noqa
|
|
||||||
provider_base_url = settings.get("PASSBOOK_URL", 'https://id.beryju.org')
|
|
||||||
|
|
||||||
access_token_url = '{0}/application/oauth/token/'.format(provider_base_url)
|
|
||||||
authorize_url = '{0}/application/oauth/authorize/'.format(provider_base_url)
|
|
||||||
profile_url = '{0}/api/v1/openid/'.format(
|
|
||||||
provider_base_url)
|
|
||||||
|
|
||||||
def complete_login(self, request, app, access_token, **kwargs):
|
|
||||||
headers = {
|
|
||||||
'Authorization': 'Bearer {0}'.format(access_token.token),
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
}
|
|
||||||
extra_data = requests.get(self.profile_url, headers=headers)
|
|
||||||
|
|
||||||
return self.get_provider().sociallogin_from_response(
|
|
||||||
request,
|
|
||||||
extra_data.json()
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
oauth2_login = OAuth2LoginView.adapter_view(PassbookOAuth2Adapter) # noqa
|
|
||||||
oauth2_callback = OAuth2CallbackView.adapter_view(PassbookOAuth2Adapter) # noqa
|
|
@ -1 +0,0 @@
|
|||||||
django-allauth
|
|
@ -1,33 +0,0 @@
|
|||||||
"""passbook allauth setup.py"""
|
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='django-allauth-passbook',
|
|
||||||
version='0.1.37-beta',
|
|
||||||
description='passbook support for django-allauth',
|
|
||||||
# long_description='\n'.join(read_simple('docs/index.md')[2:]),
|
|
||||||
long_description_content_type='text/markdown',
|
|
||||||
author='BeryJu.org',
|
|
||||||
author_email='hello@beryju.org',
|
|
||||||
packages=['allauth_passbook'],
|
|
||||||
include_package_data=True,
|
|
||||||
install_requires=['django-allauth'],
|
|
||||||
keywords='django allauth passbook',
|
|
||||||
license='MIT',
|
|
||||||
classifiers=[
|
|
||||||
'Intended Audience :: Developers',
|
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
||||||
'Environment :: Web Environment',
|
|
||||||
'Topic :: Internet',
|
|
||||||
'License :: OSI Approved :: MIT License',
|
|
||||||
'Operating System :: OS Independent',
|
|
||||||
'Programming Language :: Python',
|
|
||||||
'Programming Language :: Python :: 3.4',
|
|
||||||
'Programming Language :: Python :: 3.5',
|
|
||||||
'Programming Language :: Python :: 3.6',
|
|
||||||
'Framework :: Django',
|
|
||||||
'Framework :: Django :: 1.11',
|
|
||||||
'Framework :: Django :: 2.0',
|
|
||||||
'Framework :: Django :: 2.1',
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
*.pyc
|
|
||||||
*.egg-info/
|
|
||||||
*.eggs
|
|
||||||
/dist
|
|
||||||
/build
|
|
@ -1,32 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
language: python
|
|
||||||
services:
|
|
||||||
- memcached
|
|
||||||
- postgresql
|
|
||||||
- redis-server
|
|
||||||
python:
|
|
||||||
- '2.7'
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
- "$HOME/.cache/pip"
|
|
||||||
deploy:
|
|
||||||
provider: pypi
|
|
||||||
user: getsentry
|
|
||||||
password:
|
|
||||||
secure: kVmxKHkBWRLYyZme05p+WZSJmb8GjHV9uyuaSCVMRlqWCW+GXRB7P1xXR2jb9URTlNdcs56Ab/UrwzCbMFGC8LmwCeFVgIR/ltytVZG2FgXZPWaeA4dH25qK2oGWgzJ/xeiMpmuJqN9hRl25MX6jG7FZKvrrOkG7+8tpPd1yO+uYWZQbnebZMjcPBqEpn7CC0hR39GSoyVAbydpMe5hwENGQM26CepcicdrelfawItoUrXrkJzBHkIQQTO/xRSbCtRJOtzI5lwtv3GP0hcbOy5tI5dhG/93pLwZRc5+dZaCaP7oaVeOcBjN0zfINRQobt8d6h2Qgvd/YyFkGi0/xKn1zMmKIVLOG6VsYwEAUq8wNOsP4A/jdm4Y0J/1oEZStCkpaGpx85TYi4kq1hWQdyqaVJSPhh4Tk4roIaS2zOYQl+nIpbHqmJ4FJrg1il+TCdjBXobATQ1mKRBUrjD+RDzH/r4ogbd8+UwvvvevpqS2K+/wgT6UD0MzDInv9S29CUQvuFhPoqyJb5XRddHMRE9EEK/2Z8tFN91sDATnqfXHgwnvu00q/nKP5JnijBPzGmx7ydgUViIukklDrlPvo9BbRJz0Vr2vbAvMTrLMLCXqi5CwTm+v+iaOf/YaCziaG2vx0eVASYjpOLCedSgRZBubPM8z4E/HMXhChN7sVDWk=
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
distributions: sdist bdist_wheel
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- PIP_DOWNLOAD_CACHE=".pip_download_cache"
|
|
||||||
before_install:
|
|
||||||
- pip install codecov
|
|
||||||
install:
|
|
||||||
- make develop
|
|
||||||
script:
|
|
||||||
- PYFLAKES_NODOCTEST=1 flake8
|
|
||||||
- coverage run --source=. -m py.test tests
|
|
||||||
after_success:
|
|
||||||
- codecov
|
|
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright 2016 Functional Software, Inc.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
@ -1,3 +0,0 @@
|
|||||||
include setup.py package.json webpack.config.js README.rst MANIFEST.in LICENSE AUTHORS
|
|
||||||
recursive-include sentry_auth_supervisr/templates *
|
|
||||||
global-exclude *~
|
|
@ -1,26 +0,0 @@
|
|||||||
.PHONY: clean develop install-tests lint publish test
|
|
||||||
|
|
||||||
develop:
|
|
||||||
pip install "pip>=7"
|
|
||||||
pip install -e .
|
|
||||||
make install-tests
|
|
||||||
|
|
||||||
install-tests:
|
|
||||||
pip install .[tests]
|
|
||||||
|
|
||||||
lint:
|
|
||||||
@echo "--> Linting python"
|
|
||||||
flake8
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
test:
|
|
||||||
@echo "--> Running Python tests"
|
|
||||||
py.test tests || exit 1
|
|
||||||
@echo ""
|
|
||||||
|
|
||||||
publish:
|
|
||||||
python setup.py sdist bdist_wheel upload
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf *.egg-info src/*.egg-info
|
|
||||||
rm -rf dist build
|
|
@ -1,55 +0,0 @@
|
|||||||
GitHub Auth for Sentry
|
|
||||||
======================
|
|
||||||
|
|
||||||
An SSO provider for Sentry which enables GitHub organization-restricted authentication.
|
|
||||||
|
|
||||||
Install
|
|
||||||
-------
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
$ pip install https://github.com/getsentry/sentry-auth-github/archive/master.zip
|
|
||||||
|
|
||||||
Setup
|
|
||||||
-----
|
|
||||||
|
|
||||||
Create a new application under your organization in GitHub. Enter the **Authorization
|
|
||||||
callback URL** as the prefix to your Sentry installation:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
https://example.sentry.com
|
|
||||||
|
|
||||||
|
|
||||||
Once done, grab your API keys and drop them in your ``sentry.conf.py``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
GITHUB_APP_ID = ""
|
|
||||||
|
|
||||||
GITHUB_API_SECRET = ""
|
|
||||||
|
|
||||||
|
|
||||||
Verified email addresses can optionally be required:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
GITHUB_REQUIRE_VERIFIED_EMAIL = True
|
|
||||||
|
|
||||||
|
|
||||||
Optionally you may also specify the domain (for GHE users):
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
GITHUB_BASE_DOMAIN = "git.example.com"
|
|
||||||
|
|
||||||
GITHUB_API_DOMAIN = "api.git.example.com"
|
|
||||||
|
|
||||||
|
|
||||||
If Subdomain isolation is disabled in GHE:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
GITHUB_BASE_DOMAIN = "git.example.com"
|
|
||||||
|
|
||||||
GITHUB_API_DOMAIN = "git.example.com/api/v3"
|
|
@ -1,14 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
# Run tests against sqlite for simplicity
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import sys
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__)))
|
|
||||||
|
|
||||||
os.environ.setdefault('DB', 'sqlite')
|
|
||||||
|
|
||||||
pytest_plugins = [
|
|
||||||
'sentry.utils.pytest'
|
|
||||||
]
|
|
@ -1,7 +0,0 @@
|
|||||||
from __future__ import absolute_import
|
|
||||||
|
|
||||||
from sentry.auth import register
|
|
||||||
|
|
||||||
from .provider import PassbookOAuth2Provider
|
|
||||||
|
|
||||||
register('passbook', PassbookOAuth2Provider)
|
|
@ -1,45 +0,0 @@
|
|||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
from requests.exceptions import RequestException
|
|
||||||
|
|
||||||
from sentry import http
|
|
||||||
from sentry.utils import json
|
|
||||||
|
|
||||||
from .constants import BASE_DOMAIN
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookApiError(Exception):
|
|
||||||
def __init__(self, message='', status=0):
|
|
||||||
super(PassbookApiError, self).__init__(message)
|
|
||||||
self.status = status
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookClient(object):
|
|
||||||
def __init__(self, client_id, client_secret):
|
|
||||||
self.client_id = client_id
|
|
||||||
self.client_secret = client_secret
|
|
||||||
self.http = http.build_session()
|
|
||||||
|
|
||||||
def _request(self, path, access_token):
|
|
||||||
params = {
|
|
||||||
'client_id': self.client_id,
|
|
||||||
'client_secret': self.client_secret,
|
|
||||||
}
|
|
||||||
|
|
||||||
headers = {
|
|
||||||
'Authorization': 'Bearer {0}'.format(access_token),
|
|
||||||
}
|
|
||||||
|
|
||||||
try:
|
|
||||||
req = self.http.get('https://{0}/{1}'.format(BASE_DOMAIN, path.lstrip('/')),
|
|
||||||
params=params,
|
|
||||||
headers=headers,
|
|
||||||
)
|
|
||||||
except RequestException as e:
|
|
||||||
raise PassbookApiError(unicode(e), status=getattr(e, 'status_code', 0))
|
|
||||||
if req.status_code < 200 or req.status_code >= 300:
|
|
||||||
raise PassbookApiError(req.content, status=req.status_code)
|
|
||||||
return json.loads(req.content)
|
|
||||||
|
|
||||||
def get_user(self, access_token):
|
|
||||||
return self._request('/api/v1/openid/', access_token)
|
|
@ -1,14 +0,0 @@
|
|||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
CLIENT_ID = getattr(settings, 'PASSBOOK_APP_ID', None)
|
|
||||||
|
|
||||||
CLIENT_SECRET = getattr(settings, 'PASSBOOK_API_SECRET', None)
|
|
||||||
|
|
||||||
SCOPE = 'openid:userinfo'
|
|
||||||
|
|
||||||
BASE_DOMAIN = getattr(settings, 'PASSBOOK_BASE_DOMAIN', 'id.beryju.org')
|
|
||||||
|
|
||||||
ACCESS_TOKEN_URL = 'https://{0}/application/oauth/token/'.format(BASE_DOMAIN)
|
|
||||||
AUTHORIZE_URL = 'https://{0}/application/oauth/authorize/'.format(BASE_DOMAIN)
|
|
@ -1,62 +0,0 @@
|
|||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
from sentry.auth.exceptions import IdentityNotValid
|
|
||||||
from sentry.auth.providers.oauth2 import (OAuth2Callback, OAuth2Login,
|
|
||||||
OAuth2Provider)
|
|
||||||
|
|
||||||
from .client import PassbookApiError, PassbookClient
|
|
||||||
from .constants import (ACCESS_TOKEN_URL, AUTHORIZE_URL, CLIENT_ID,
|
|
||||||
CLIENT_SECRET, SCOPE)
|
|
||||||
from .views import FetchUser, PassbookConfigureView
|
|
||||||
|
|
||||||
|
|
||||||
class PassbookOAuth2Provider(OAuth2Provider):
|
|
||||||
access_token_url = ACCESS_TOKEN_URL
|
|
||||||
authorize_url = AUTHORIZE_URL
|
|
||||||
name = 'Passbook'
|
|
||||||
client_id = CLIENT_ID
|
|
||||||
client_secret = CLIENT_SECRET
|
|
||||||
|
|
||||||
def __init__(self, **config):
|
|
||||||
super(PassbookOAuth2Provider, self).__init__(**config)
|
|
||||||
|
|
||||||
def get_configure_view(self):
|
|
||||||
return PassbookConfigureView.as_view()
|
|
||||||
|
|
||||||
def get_auth_pipeline(self):
|
|
||||||
return [
|
|
||||||
OAuth2Login(
|
|
||||||
authorize_url=self.authorize_url,
|
|
||||||
client_id=self.client_id,
|
|
||||||
scope=SCOPE,
|
|
||||||
),
|
|
||||||
OAuth2Callback(
|
|
||||||
access_token_url=self.access_token_url,
|
|
||||||
client_id=self.client_id,
|
|
||||||
client_secret=self.client_secret,
|
|
||||||
),
|
|
||||||
FetchUser(
|
|
||||||
client_id=self.client_id,
|
|
||||||
client_secret=self.client_secret,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_refresh_token_url(self):
|
|
||||||
return ACCESS_TOKEN_URL
|
|
||||||
|
|
||||||
def build_identity(self, state):
|
|
||||||
data = state['data']
|
|
||||||
user_data = state['user']
|
|
||||||
return {
|
|
||||||
'id': user_data['email'],
|
|
||||||
'email': user_data['email'],
|
|
||||||
'name': user_data['name'],
|
|
||||||
'data': self.get_oauth_data(data),
|
|
||||||
}
|
|
||||||
|
|
||||||
def build_config(self, state):
|
|
||||||
return {}
|
|
||||||
|
|
||||||
def refresh_identity(self, auth_identity):
|
|
||||||
client = PassbookClient(self.client_id, self.client_secret)
|
|
||||||
access_token = auth_identity.data['access_token']
|
|
@ -1,75 +0,0 @@
|
|||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
from django import forms
|
|
||||||
|
|
||||||
from sentry.auth.view import AuthView, ConfigureView
|
|
||||||
from sentry.models import AuthIdentity
|
|
||||||
|
|
||||||
from .client import PassbookClient
|
|
||||||
|
|
||||||
|
|
||||||
def _get_name_from_email(email):
|
|
||||||
"""
|
|
||||||
Given an email return a capitalized name. Ex. john.smith@example.com would return John Smith.
|
|
||||||
"""
|
|
||||||
name = email.rsplit('@', 1)[0]
|
|
||||||
name = ' '.join([n_part.capitalize() for n_part in name.split('.')])
|
|
||||||
return name
|
|
||||||
|
|
||||||
|
|
||||||
class FetchUser(AuthView):
|
|
||||||
def __init__(self, client_id, client_secret, *args, **kwargs):
|
|
||||||
self.client = PassbookClient(client_id, client_secret)
|
|
||||||
super(FetchUser, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def handle(self, request, helper):
|
|
||||||
access_token = helper.fetch_state('data')['access_token']
|
|
||||||
|
|
||||||
user = self.client.get_user(access_token)
|
|
||||||
|
|
||||||
# A user hasn't set their name in their Passbook profile so it isn't
|
|
||||||
# populated in the response
|
|
||||||
if not user.get('name'):
|
|
||||||
user['name'] = _get_name_from_email(user['email'])
|
|
||||||
|
|
||||||
helper.bind_state('user', user)
|
|
||||||
|
|
||||||
return helper.next_step()
|
|
||||||
|
|
||||||
|
|
||||||
class ConfirmEmailForm(forms.Form):
|
|
||||||
email = forms.EmailField(label='Email')
|
|
||||||
|
|
||||||
|
|
||||||
class ConfirmEmail(AuthView):
|
|
||||||
def handle(self, request, helper):
|
|
||||||
user = helper.fetch_state('user')
|
|
||||||
|
|
||||||
# TODO(dcramer): this isnt ideal, but our current flow doesnt really
|
|
||||||
# support this behavior;
|
|
||||||
try:
|
|
||||||
auth_identity = AuthIdentity.objects.select_related('user').get(
|
|
||||||
auth_provider=helper.auth_provider,
|
|
||||||
ident=user['id'],
|
|
||||||
)
|
|
||||||
except AuthIdentity.DoesNotExist:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
user['email'] = auth_identity.user.email
|
|
||||||
|
|
||||||
if user.get('email'):
|
|
||||||
return helper.next_step()
|
|
||||||
|
|
||||||
form = ConfirmEmailForm(request.POST or None)
|
|
||||||
if form.is_valid():
|
|
||||||
user['email'] = form.cleaned_data['email']
|
|
||||||
helper.bind_state('user', user)
|
|
||||||
return helper.next_step()
|
|
||||||
|
|
||||||
return self.respond('sentry_auth_passbook/enter-email.html', {
|
|
||||||
'form': form,
|
|
||||||
})
|
|
||||||
|
|
||||||
class PassbookConfigureView(ConfigureView):
|
|
||||||
def dispatch(self, request, organization, auth_provider):
|
|
||||||
return self.render('sentry_auth_passbook/configure.html')
|
|
@ -1,12 +0,0 @@
|
|||||||
[wheel]
|
|
||||||
universal = 1
|
|
||||||
|
|
||||||
[pytest]
|
|
||||||
python_files = test*.py
|
|
||||||
addopts = --tb=native -p no:doctest
|
|
||||||
norecursedirs = bin dist docs htmlcov script hooks node_modules .* {args}
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
ignore = F999,E501,E128,E124,E402,W503,E731,C901
|
|
||||||
max-line-length = 100
|
|
||||||
exclude = .tox,.git,*/migrations/*,node_modules/*,docs/*
|
|
@ -1,45 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
"""
|
|
||||||
sentry-auth-passbook
|
|
||||||
==================
|
|
||||||
|
|
||||||
:copyright: (c) 2016 Functional Software, Inc
|
|
||||||
"""
|
|
||||||
from setuptools import find_packages, setup
|
|
||||||
|
|
||||||
install_requires = [
|
|
||||||
'sentry>=7.0.0',
|
|
||||||
]
|
|
||||||
|
|
||||||
tests_require = [
|
|
||||||
'mock',
|
|
||||||
'flake8>=2.0,<2.1',
|
|
||||||
]
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name='sentry-auth-passbook',
|
|
||||||
version='0.1.37-beta',
|
|
||||||
author='BeryJu.org',
|
|
||||||
author_email='support@beryju.org',
|
|
||||||
url='https://passbook.beryju.org',
|
|
||||||
description='passbook authentication provider for Sentry',
|
|
||||||
long_description=__doc__,
|
|
||||||
license='MIT',
|
|
||||||
packages=find_packages(exclude=['tests']),
|
|
||||||
zip_safe=False,
|
|
||||||
install_requires=install_requires,
|
|
||||||
tests_require=tests_require,
|
|
||||||
extras_require={'tests': tests_require},
|
|
||||||
include_package_data=True,
|
|
||||||
entry_points={
|
|
||||||
'sentry.apps': [
|
|
||||||
'auth_passbook = sentry_auth_passbook',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
classifiers=[
|
|
||||||
'Intended Audience :: Developers',
|
|
||||||
'Intended Audience :: System Administrators',
|
|
||||||
'Operating System :: OS Independent',
|
|
||||||
'Topic :: Software Development'
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,6 +0,0 @@
|
|||||||
from sentry.testutils import TestCase
|
|
||||||
|
|
||||||
|
|
||||||
class GitHubOAuth2ProviderTest(TestCase):
|
|
||||||
def test_simple(self):
|
|
||||||
pass
|
|
@ -1,17 +0,0 @@
|
|||||||
from __future__ import absolute_import, print_function
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from sentry_auth_sentry.views import _get_name_from_email
|
|
||||||
|
|
||||||
expected_data = [
|
|
||||||
('john.smith@example.com', 'John Smith'),
|
|
||||||
('john@example.com', 'John'),
|
|
||||||
('XYZ-234=3523@example.com', 'Xyz-234=3523'),
|
|
||||||
('XYZ.1111@example.com', 'Xyz 1111'),
|
|
||||||
('JOHN@example.com', 'John'),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("email,expected_name", expected_data)
|
|
||||||
def test_get_name_from_email(email, expected_name):
|
|
||||||
assert _get_name_from_email(email) == expected_name
|
|
85
docker-compose.yml
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
version: '3.2'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgresql:
|
||||||
|
image: postgres
|
||||||
|
volumes:
|
||||||
|
- database:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
environment:
|
||||||
|
- POSTGRES_PASSWORD=${PG_PASS:-thisisnotagoodpassword}
|
||||||
|
- POSTGRES_USER=passbook
|
||||||
|
- POSTGRES_DB=passbook
|
||||||
|
labels:
|
||||||
|
- traefik.enable=false
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
labels:
|
||||||
|
- traefik.enable=false
|
||||||
|
server:
|
||||||
|
image: beryju/passbook:${PASSBOOK_TAG:-latest}
|
||||||
|
command:
|
||||||
|
- uwsgi
|
||||||
|
- uwsgi.ini
|
||||||
|
environment:
|
||||||
|
- PASSBOOK_REDIS__HOST=redis
|
||||||
|
- PASSBOOK_ERROR_REPORTING=${PASSBOOK_ERROR_REPORTING:-false}
|
||||||
|
- PASSBOOK_POSTGRESQL__HOST=postgresql
|
||||||
|
- PASSBOOK_POSTGRESQL__PASSWORD=${PG_PASS:-thisisnotagoodpassword}
|
||||||
|
ports:
|
||||||
|
- 8000
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
labels:
|
||||||
|
- traefik.port=8000
|
||||||
|
- traefik.docker.network=internal
|
||||||
|
- traefik.frontend.rule=PathPrefix:/
|
||||||
|
worker:
|
||||||
|
image: beryju/passbook:${PASSBOOK_TAG:-latest}
|
||||||
|
command:
|
||||||
|
- celery
|
||||||
|
- worker
|
||||||
|
- --autoscale=10,3
|
||||||
|
- -E
|
||||||
|
- -B
|
||||||
|
- -A=passbook.root.celery
|
||||||
|
- -s=/tmp/celerybeat-schedule
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
labels:
|
||||||
|
- traefik.enable=false
|
||||||
|
environment:
|
||||||
|
- PASSBOOK_REDIS__HOST=redis
|
||||||
|
- PASSBOOK_ERROR_REPORTING=${PASSBOOK_ERROR_REPORTING:-false}
|
||||||
|
- PASSBOOK_POSTGRESQL__HOST=postgresql
|
||||||
|
- PASSBOOK_POSTGRESQL__PASSWORD=${PG_PASS:-thisisnotagoodpassword}
|
||||||
|
static:
|
||||||
|
image: beryju/passbook-static:latest
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
labels:
|
||||||
|
- traefik.frontend.rule=PathPrefix:/static, /robots.txt
|
||||||
|
- traefik.port=80
|
||||||
|
- traefik.docker.network=internal
|
||||||
|
traefik:
|
||||||
|
image: traefik:1.7
|
||||||
|
command: --api --docker --defaultentrypoints=https --entryPoints='Name:http Address::80 Redirect.EntryPoint:https' --entryPoints='Name:https Address::443 TLS'
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:80:80"
|
||||||
|
- "0.0.0.0:443:443"
|
||||||
|
- "127.0.0.1:8080:8080"
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
database:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal: {}
|
9
docker.env.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
debug: true
|
||||||
|
postgresql:
|
||||||
|
user: postgres
|
||||||
|
host: postgresql
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: redis
|
||||||
|
|
||||||
|
log_level: debug
|
3
docker/bootstrap.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash -ex
|
||||||
|
/app/wait_for_db.py
|
||||||
|
"$@"
|
10
docker/uwsgi.ini
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[uwsgi]
|
||||||
|
http = 0.0.0.0:8000
|
||||||
|
wsgi-file = passbook/root/wsgi.py
|
||||||
|
processes = 2
|
||||||
|
master = true
|
||||||
|
threads = 2
|
||||||
|
enable-threads = true
|
||||||
|
uid = passbook
|
||||||
|
gid = passbook
|
||||||
|
disable-logging = True
|
41
docker/wait_for_db.py
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""This file needs to be run from the root of the project to correctly
|
||||||
|
import passbook. This is done by the dockerfile."""
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from psycopg2 import OperationalError, connect
|
||||||
|
from redis import Redis
|
||||||
|
from redis.exceptions import RedisError
|
||||||
|
from structlog import get_logger
|
||||||
|
|
||||||
|
from passbook.lib.config import CONFIG
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
conn = connect(
|
||||||
|
dbname=CONFIG.y("postgresql.name"),
|
||||||
|
user=CONFIG.y("postgresql.user"),
|
||||||
|
password=CONFIG.y("postgresql.password"),
|
||||||
|
host=CONFIG.y("postgresql.host"),
|
||||||
|
)
|
||||||
|
conn.cursor()
|
||||||
|
break
|
||||||
|
except OperationalError:
|
||||||
|
sleep(1)
|
||||||
|
LOGGER.warning("PostgreSQL Connection failed, retrying...")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
redis = Redis(
|
||||||
|
host=CONFIG.y("redis.host"),
|
||||||
|
port=6379,
|
||||||
|
db=CONFIG.y("redis.message_queue_db"),
|
||||||
|
password=CONFIG.y("redis.password"),
|
||||||
|
)
|
||||||
|
redis.ping()
|
||||||
|
break
|
||||||
|
except RedisError:
|
||||||
|
sleep(1)
|
||||||
|
LOGGER.warning("Redis Connection failed, retrying...")
|
3
docs/build.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash -x
|
||||||
|
pip install -U mkdocs mkdocs-material
|
||||||
|
mkdocs gh-deploy
|
55
docs/expressions/index.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Expressions
|
||||||
|
|
||||||
|
Expressions allow you to write custom logic using Python code.
|
||||||
|
|
||||||
|
Expressions are used in different places throughout passbook, and can do different things.
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
These functions/objects are available wherever expressions are used. For more specific information, see [Expression Policies](../policies/expression.md) and [Property Mappings](../property-mappings/expression.md)
|
||||||
|
|
||||||
|
## Global objects
|
||||||
|
|
||||||
|
- `pb_logger`: structlog BoundLogger. ([ref](https://www.structlog.org/en/stable/api.html#structlog.BoundLogger))
|
||||||
|
- `requests`: requests Session object. ([ref](https://requests.readthedocs.io/en/master/user/advanced/))
|
||||||
|
|
||||||
|
## Generally available functions
|
||||||
|
|
||||||
|
### `regex_match(value: Any, regex: str) -> bool`
|
||||||
|
|
||||||
|
Check if `value` matches Regular Expression `regex`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
return regex_match(request.user.username, '.*admin.*')
|
||||||
|
```
|
||||||
|
|
||||||
|
### `regex_replace(value: Any, regex: str, repl: str) -> str`
|
||||||
|
|
||||||
|
Replace anything matching `regex` within `value` with `repl` and return it.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
user_email_local = regex_replace(request.user.email, '(.+)@.+', '')
|
||||||
|
```
|
||||||
|
|
||||||
|
### `pb_is_group_member(user: User, **group_filters) -> bool`
|
||||||
|
|
||||||
|
Check if `user` is member of a group matching `**group_filters`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
return pb_is_group_member(request.user, name="test_group")
|
||||||
|
```
|
||||||
|
|
||||||
|
### `pb_user_by(**filters) -> Optional[User]`
|
||||||
|
|
||||||
|
Fetch a user matching `**filters`. Returns "None" if no user was found.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
other_user = pb_user_by(username="other_user")
|
||||||
|
```
|
21
docs/expressions/reference/user-object.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Passbook User Object
|
||||||
|
|
||||||
|
The User object has the following attributes:
|
||||||
|
|
||||||
|
- `username`: User's username.
|
||||||
|
- `email` User's email.
|
||||||
|
- `name` User's display mame.
|
||||||
|
- `is_staff` Boolean field if user is staff.
|
||||||
|
- `is_active` Boolean field if user is active.
|
||||||
|
- `date_joined` Date user joined/was created.
|
||||||
|
- `password_change_date` Date password was last changed.
|
||||||
|
- `attributes` Dynamic attributes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
List all the User's group names:
|
||||||
|
|
||||||
|
```python
|
||||||
|
for group in user.groups.all():
|
||||||
|
yield group.name
|
||||||
|
```
|
36
docs/flow/examples/login.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Login Flow
|
||||||
|
|
||||||
|
This document describes how a simple authentication flow can be created.
|
||||||
|
|
||||||
|
This flow is created automatically when passbook is installed.
|
||||||
|
|
||||||
|
1. Create an **Identification** stage
|
||||||
|
|
||||||
|
> Here you can select whichever fields the user can identify themselves with
|
||||||
|
> Select the Template **Default Login**, as this template shows the (optional) Flows
|
||||||
|
> Here you can also link optional enrollment and recovery flows.
|
||||||
|
|
||||||
|
2. Create a **Password** stage
|
||||||
|
|
||||||
|
> Select the Backend you want the password to be checked against. Select "passbook-internal Userdatabase".
|
||||||
|
|
||||||
|
3. Create a **User Login** stage
|
||||||
|
|
||||||
|
> This stage doesn't have any options.
|
||||||
|
|
||||||
|
4. Create a flow
|
||||||
|
|
||||||
|
> Create a flow with the delegation of **Authentication**
|
||||||
|
> Assign a name and a slug. The slug is used in the URL when the flow is executed.
|
||||||
|
|
||||||
|
5. Bind the stages to the flow
|
||||||
|
|
||||||
|
> Bind the **Identification** Stage with an order of 0
|
||||||
|
> Bind the **Password** Stage with an order of 1
|
||||||
|
> Bind the **User Login** Stage with an order of 2
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
!!! notice
|
||||||
|
|
||||||
|
This flow can used by any user, authenticated and un-authenticated. This means any authenticated user that visits this flow can login again.
|
BIN
docs/flow/examples/login.png
Normal file
After Width: | Height: | Size: 110 KiB |
45
docs/flow/flows.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Flows
|
||||||
|
|
||||||
|
Flows are a method of describing a sequence of stages. A stage represents a single verification or logic step. They are used to authenticate users, enroll them, and more.
|
||||||
|
|
||||||
|
Upon flow execution, a plan containing all stages is generated. This means that all attached policies are evaluated upon execution. This behaviour can be altered by enabling the **Re-evaluate Policies** option on the binding.
|
||||||
|
|
||||||
|
To determine which flow is linked, passbook searches all flows with the required designation and chooses the first instance the current user has access to.
|
||||||
|
|
||||||
|
## Permissions
|
||||||
|
|
||||||
|
Flows can have policies assigned to them. These policies determine if the current user is allowed to see and use this flow.
|
||||||
|
|
||||||
|
## Designation
|
||||||
|
|
||||||
|
Flows are designated for a single purpose. This designation changes when a flow is used. The following designations are available:
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
|
||||||
|
This is designates a flow to be used for authentication.
|
||||||
|
|
||||||
|
The authentication flow should always contain a [**User Login**](stages/user_login.md) stage, which attaches the staged user to the current session.
|
||||||
|
|
||||||
|
### Invalidation
|
||||||
|
|
||||||
|
This designates a flow to be used to invalidate a session.
|
||||||
|
|
||||||
|
This stage should always contain a [**User Logout**](stages/user_logout.md) stage, which resets the current session.
|
||||||
|
|
||||||
|
### Enrollment
|
||||||
|
|
||||||
|
This designates a flow for enrollment. This flow can contain any amount of verification stages, such as [**email**](stages/email/index.md) or [**captcha**](stages/captcha/index.md). At the end, to create the user, you can use the [**user_write**](stages/user_write.md) stage, which either updates the currently staged user, or if none exists, creates a new one.
|
||||||
|
|
||||||
|
### Unenrollment
|
||||||
|
|
||||||
|
This designates a flow for unenrollment. This flow can contain any amount of verification stages, such as [**email**](stages/email/index.md) or [**captcha**](stages/captcha/index.md). As a final stage, to delete the account, use the [**user_delete**](stages/user_delete.md) stage.
|
||||||
|
|
||||||
|
### Recovery
|
||||||
|
|
||||||
|
This designates a flow for recovery. This flow normally contains an [**identification**](stages/identification/index.md) stage to find the user. It can also contain any amount of verification stages, such as [**email**](stages/email/index.md) or [**captcha**](stages/captcha/index.md).
|
||||||
|
Afterwards, use the [**prompt**](stages/prompt/index.md) stage to ask the user for a new password and the [**user_write**](stages/user_write.md) stage to update the password.
|
||||||
|
|
||||||
|
### Change Password
|
||||||
|
|
||||||
|
This designates a flow for password changes. This flow can contain any amount of verification stages, such as [**email**](stages/email/index.md) or [**captcha**](stages/captcha/index.md).
|
||||||
|
Afterwards, use the [**prompt**](stages/prompt/index.md) stage to ask the user for a new password and the [**user_write**](stages/user_write.md) stage to update the password.
|
BIN
docs/flow/stages/captcha/captcha-admin.png
Normal file
After Width: | Height: | Size: 140 KiB |
7
docs/flow/stages/captcha/index.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Captcha stage
|
||||||
|
|
||||||
|
This stage adds a form of verification using [Google's ReCaptcha](https://www.google.com/recaptcha/intro/v3.html).
|
||||||
|
|
||||||
|
This stage has two required fields: Public key and private key. These can both be acquired at https://www.google.com/recaptcha/admin.
|
||||||
|
|
||||||
|

|
BIN
docs/flow/stages/dummy/dummy.png
Normal file
After Width: | Height: | Size: 1.3 MiB |
5
docs/flow/stages/dummy/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Dummy stage
|
||||||
|
|
||||||
|
This stage is used for development and has no function. It presents the user with a form which requires a single confirmation.
|
||||||
|
|
||||||
|

|
BIN
docs/flow/stages/email/email-recovery.png
Normal file
After Width: | Height: | Size: 51 KiB |
5
docs/flow/stages/email/index.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Email
|
||||||
|
|
||||||
|
This stage can be used for email verification. passbook's background worker will send an email using the specified connection details. When an email can't be delivered, delivery is automatically retried periodically.
|
||||||
|
|
||||||
|

|
25
docs/flow/stages/identification/index.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Identification
|
||||||
|
|
||||||
|
This stage provides a ready-to-go form for users to identify themselves.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### User Fields
|
||||||
|
|
||||||
|
Select which fields the user can use to identify themselves. Multiple fields can be specified and separated with a comma.
|
||||||
|
Valid choices:
|
||||||
|
|
||||||
|
- email
|
||||||
|
- username
|
||||||
|
|
||||||
|
### Template
|
||||||
|
|
||||||
|
This specifies which template is rendered. Currently there are two templates:
|
||||||
|
|
||||||
|
The `Login` template shows configured Sources below the login form, as well as linking to the defined Enrollment and Recovery flows.
|
||||||
|
|
||||||
|
The `Recovery` template shows only the form.
|
||||||
|
|
||||||
|
### Enrollment/Recovery Flow
|
||||||
|
|
||||||
|
These fields specify if and which flows are linked on the form. The enrollment flow is linked as `Need an account? Sign up.`, and the recovery flow is linked as `Forgot username or password?`.
|
7
docs/flow/stages/invitation/index.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Invitation Stage
|
||||||
|
|
||||||
|
This stage can be used to invite users. You can use this to enroll users with preset values.
|
||||||
|
|
||||||
|
If the option `Continue Flow without Invitation` is enabled, this stage will continue even when no invitation token is present.
|
||||||
|
|
||||||
|
To check if a user has used an invitation within a policy, you can check `request.context.invitation_in_effect`.
|
7
docs/flow/stages/otp/index.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# OTP Stage
|
||||||
|
|
||||||
|
This stage offers a generic Time-based One-time Password authentication step.
|
||||||
|
|
||||||
|
You can optionally enforce this step, which will force every user without OTP setup to configure it.
|
||||||
|
|
||||||
|
This stage uses a 6-digit Code with a 30 second time-drift. This is currently not changeable.
|
3
docs/flow/stages/password/index.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Password Stage
|
||||||
|
|
||||||
|
This is a generic password prompt which authenticates the current `pending_user`. This stage allows the selection of the source the user is authenticated against.
|
42
docs/flow/stages/prompt/index.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Prompt Stage
|
||||||
|
|
||||||
|
This stage is used to show the user arbitrary prompts.
|
||||||
|
|
||||||
|
## Prompt
|
||||||
|
|
||||||
|
The prompt can be any of the following types:
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|----------|------------------------------------------------------------------|
|
||||||
|
| text | Arbitrary text. No client-side validation is done. |
|
||||||
|
| email | Email input. Requires a valid email adress. |
|
||||||
|
| password | Password input. |
|
||||||
|
| number | Number input. Any number is allowed. |
|
||||||
|
| checkbox | Simple checkbox. |
|
||||||
|
| hidden | Hidden input field. Allows for the pre-setting of default values.|
|
||||||
|
|
||||||
|
A prompt has the following attributes:
|
||||||
|
|
||||||
|
### `field_key`
|
||||||
|
|
||||||
|
The HTML name used for the prompt. This key is also used to later retrieve the data in expression policies:
|
||||||
|
|
||||||
|
```python
|
||||||
|
request.context.get('prompt_data').get('<field_key>')
|
||||||
|
```
|
||||||
|
|
||||||
|
### `label`
|
||||||
|
|
||||||
|
The label used to describe the field. Depending on the selected template, this may not be shown.
|
||||||
|
|
||||||
|
### `required`
|
||||||
|
|
||||||
|
A flag which decides whether or not this field is required.
|
||||||
|
|
||||||
|
### `placeholder`
|
||||||
|
|
||||||
|
A field placeholder, shown within the input field. This field is also used by the `hidden` type as the actual value.
|
||||||
|
|
||||||
|
### `order`
|
||||||
|
|
||||||
|
The numerical index of the prompt. This applies to all stages which this prompt is a part of.
|
16
docs/flow/stages/prompt/validation.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Prompt Validation
|
||||||
|
|
||||||
|
Further validation of prompts can be done using policies.
|
||||||
|
|
||||||
|
To validate that two password fields are identical, create the following expression policy:
|
||||||
|
|
||||||
|
```python
|
||||||
|
if request.context.get('prompt_data').get('password') == request.context.get('prompt_data').get('password_repeat'):
|
||||||
|
return True
|
||||||
|
|
||||||
|
pb_message("Passwords don't match.")
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
This policy expects you to have two password fields with `field_key` set to `password` and `password_repeat`.
|
||||||
|
|
||||||
|
Afterwards, bind this policy to the prompt stage you want to validate.
|
8
docs/flow/stages/user_delete.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# User Delete Stage
|
||||||
|
|
||||||
|
!!! danger
|
||||||
|
This stage deletes the `pending_user` without any confirmation. You have to make sure the user is aware of this.
|
||||||
|
|
||||||
|
This stage is intended for an unenrollment flow. It deletes the currently pending user.
|
||||||
|
|
||||||
|
The pending user is also removed from the current session.
|
5
docs/flow/stages/user_login.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# User Login Stage
|
||||||
|
|
||||||
|
This stage attaches a currently pending user to the current session.
|
||||||
|
|
||||||
|
It can be used after `user_write` during an enrollment flow, or after a `password` stage during an authentication flow.
|
3
docs/flow/stages/user_logout.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# User Logout Stage
|
||||||
|
|
||||||
|
Opposite stage of [User Login Stages](user_login.md). It removes the user from the current session.
|
3
docs/flow/stages/user_write.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# User Write Stage
|
||||||
|
|
||||||
|
This stages writes data from the current context to the current pending user. If no user is pending, a new one is created.
|
@ -1,2 +1,2 @@
|
|||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
width="270px" height="20px" viewBox="0 0 270 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>
|
width="120px" height="20px" viewBox="15 0 10 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
2
docs/images/brand_inverted.svg
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="120px" height="20px" viewBox="15 0 10 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#000;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>
|
After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
docs/images/screen_admin.png
Normal file
After Width: | Height: | Size: 175 KiB |
BIN
docs/images/screen_apps.png
Normal file
After Width: | Height: | Size: 160 KiB |
16
docs/index.md
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#
|
||||||
|
{: style="height:50px"}
|
||||||
|
{: style="height:50px"}
|
||||||
|
|
||||||
|
## What is passbook?
|
||||||
|
|
||||||
|
passbook is an open-source Identity Provider focused on flexibility and versatility. You can use passbook in an existing environment to add support for new protocols. passbook is also a great solution for implementing signup/recovery/etc in your application, so you don't have to deal with it.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
See [Docker-compose](installation/docker-compose.md) or [Kubernetes](installation/kubernetes.md)
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|

|
35
docs/installation/docker-compose.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# docker-compose
|
||||||
|
|
||||||
|
This installation method is for test-setups and small-scale productive setups.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- docker
|
||||||
|
- docker-compose
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml). Place it in a directory of your choice.
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://raw.githubusercontent.com/BeryJu/passbook/master/docker-compose.yml
|
||||||
|
# Optionally enable Error-reporting
|
||||||
|
# export PASSBOOK_ERROR_REPORTING=true
|
||||||
|
# Optionally deploy a different version
|
||||||
|
# export PASSBOOK_TAG=0.8.15-beta
|
||||||
|
# If this is a productive installation, set a different PostgreSQL Password
|
||||||
|
# export PG_PASS=$(pwgen 40 1)
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
docker-compose exec server ./manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
The compose file references the current latest version, which can be overridden with the `SERVER_TAG` environment variable.
|
||||||
|
|
||||||
|
If you plan to use this setup for production, it is also advised to change the PostgreSQL password by setting `PG_PASS` to a password of your choice.
|
||||||
|
|
||||||
|
Now you can pull the Docker images needed by running `docker-compose pull`. After this has finished, run `docker-compose up -d` to start passbook.
|
||||||
|
|
||||||
|
passbook will then be reachable via HTTP on port 80, and HTTPS on port 443. You can optionally configure the packaged traefik to use Let's Encrypt certificates for TLS Encryption.
|
||||||
|
|
||||||
|
The initial setup process also creates a default admin user, the username and password for which is `pbadmin`. It is highly recommended to change this password as soon as you log in.
|
69
docs/installation/kubernetes.md
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
# Kubernetes
|
||||||
|
|
||||||
|
For a mid to high-load installation, Kubernetes is recommended. passbook is installed using a helm-chart.
|
||||||
|
|
||||||
|
This installation automatically applies database migrations on startup. After the installation is done, you can use `pbadmin` as username and password.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Default values for passbook.
|
||||||
|
# This is a YAML-formatted file.
|
||||||
|
# Declare variables to be passed into your templates.
|
||||||
|
# passbook version to use. Defaults to latest stable version
|
||||||
|
# image:
|
||||||
|
# tag:
|
||||||
|
|
||||||
|
nameOverride: ""
|
||||||
|
|
||||||
|
config:
|
||||||
|
# Optionally specify fixed secret_key, otherwise generated automatically
|
||||||
|
# secret_key: _k*@6h2u2@q-dku57hhgzb7tnx*ba9wodcb^s9g0j59@=y(@_o
|
||||||
|
# Enable error reporting
|
||||||
|
error_reporting: false
|
||||||
|
# Log level used by web and worker
|
||||||
|
# Can be either debug, info, warning, error
|
||||||
|
log_level: warning
|
||||||
|
# Optionally enable Elastic APM Support
|
||||||
|
apm:
|
||||||
|
enabled: false
|
||||||
|
server_url: ""
|
||||||
|
secret_token: ""
|
||||||
|
verify_server_cert: true
|
||||||
|
|
||||||
|
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
|
||||||
|
# This requires the CoreOS Prometheus Operator.
|
||||||
|
monitoring:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
# Enable Database Backups to S3
|
||||||
|
# backup:
|
||||||
|
# access_key: access-key
|
||||||
|
# secret_key: secret-key
|
||||||
|
# bucket: s3-bucket
|
||||||
|
# host: s3-host
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
annotations: {}
|
||||||
|
# kubernetes.io/ingress.class: nginx
|
||||||
|
# kubernetes.io/tls-acme: "true"
|
||||||
|
path: /
|
||||||
|
hosts:
|
||||||
|
- passbook.k8s.local
|
||||||
|
tls: []
|
||||||
|
# - secretName: chart-example-tls
|
||||||
|
# hosts:
|
||||||
|
# - passbook.k8s.local
|
||||||
|
|
||||||
|
# These settings configure the packaged PostgreSQL and Redis chart.
|
||||||
|
postgresql:
|
||||||
|
postgresqlDatabase: passbook
|
||||||
|
|
||||||
|
redis:
|
||||||
|
cluster:
|
||||||
|
enabled: false
|
||||||
|
master:
|
||||||
|
persistence:
|
||||||
|
enabled: false
|
||||||
|
# https://stackoverflow.com/a/59189742
|
||||||
|
disableCommands: []
|
||||||
|
```
|
32
docs/integrations/services/aws/index.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Amazon Web Services Integration
|
||||||
|
|
||||||
|
## What is AWS
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Amazon Web Services (AWS) is the world’s most comprehensive and broadly adopted cloud platform, offering over 175 fully featured services from data centers globally. Millions of customers—including the fastest-growing startups, largest enterprises, and leading government agencies—are using AWS to lower costs, become more agile, and innovate faster.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `passbook.company` is the FQDN of the passbook install.
|
||||||
|
|
||||||
|
Create an application in passbook and note the slug, as this will be used later. Create a SAML provider with the following parameters:
|
||||||
|
|
||||||
|
- ACS URL: `https://signin.aws.amazon.com/saml`
|
||||||
|
- Audience: `urn:amazon:webservices`
|
||||||
|
- Issuer: `passbook`
|
||||||
|
|
||||||
|
You can of course use a custom signing certificate, and adjust durations.
|
||||||
|
|
||||||
|
## AWS
|
||||||
|
|
||||||
|
Create a role with the permissions you desire, and note the ARN.
|
||||||
|
|
||||||
|
AWS requires two custom PropertyMappings; `Role` and `RoleSessionName`. Create them as following:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Afterwards export the metadata from passbook, and create an Identity Provider [here](https://console.aws.amazon.com/iam/home#/providers).
|
After Width: | Height: | Size: 65 KiB |
BIN
docs/integrations/services/aws/property-mapping-role.png
Normal file
After Width: | Height: | Size: 66 KiB |
58
docs/integrations/services/gitlab/index.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# GitLab Integration
|
||||||
|
|
||||||
|
## What is GitLab
|
||||||
|
|
||||||
|
From https://about.gitlab.com/what-is-gitlab/
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
GitLab is a complete DevOps platform, delivered as a single application. This makes GitLab unique and makes Concurrent DevOps possible, unlocking your organization from the constraints of a pieced together toolchain. Join us for a live Q&A to learn how GitLab can give you unmatched visibility and higher levels of efficiency in a single application across the DevOps lifecycle.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `gitlab.company` is the FQDN of the GitLab Install
|
||||||
|
- `passbook.company` is the FQDN of the passbook Install
|
||||||
|
|
||||||
|
Create an application in passbook and note the slug, as this will be used later. Create a SAML provider with the following parameters:
|
||||||
|
|
||||||
|
- ACS URL: `https://gitlab.company/users/auth/saml/callback`
|
||||||
|
- Audience: `https://gitlab.company`
|
||||||
|
- Issuer: `https://gitlab.company`
|
||||||
|
|
||||||
|
You can of course use a custom signing certificate, and adjust durations. To get the value for `idp_cert_fingerprint`, you can use a tool like [this](https://www.samltool.com/fingerprint.php).
|
||||||
|
|
||||||
|
## GitLab Configuration
|
||||||
|
|
||||||
|
Paste the following block in your `gitlab.rb` file, after replacing the placeholder values from above. The file is located in `/etc/gitlab`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
gitlab_rails['omniauth_enabled'] = true
|
||||||
|
gitlab_rails['omniauth_allow_single_sign_on'] = ['saml']
|
||||||
|
gitlab_rails['omniauth_sync_email_from_provider'] = 'saml'
|
||||||
|
gitlab_rails['omniauth_sync_profile_from_provider'] = ['saml']
|
||||||
|
gitlab_rails['omniauth_sync_profile_attributes'] = ['email']
|
||||||
|
gitlab_rails['omniauth_auto_sign_in_with_provider'] = 'saml'
|
||||||
|
gitlab_rails['omniauth_block_auto_created_users'] = false
|
||||||
|
gitlab_rails['omniauth_auto_link_saml_user'] = true
|
||||||
|
gitlab_rails['omniauth_providers'] = [
|
||||||
|
{
|
||||||
|
name: 'saml',
|
||||||
|
args: {
|
||||||
|
assertion_consumer_service_url: 'https://gitlab.company/users/auth/saml/callback',
|
||||||
|
idp_cert_fingerprint: '4E:1E:CD:67:4A:67:5A:E9:6A:D0:3C:E6:DD:7A:F2:44:2E:76:00:6A',
|
||||||
|
idp_sso_target_url: 'https://passbook.company/application/saml/<passbook application slug>/login/',
|
||||||
|
issuer: 'https://gitlab.company',
|
||||||
|
name_identifier_format: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
|
||||||
|
attribute_statements: {
|
||||||
|
email: ['urn:oid:1.3.6.1.4.1.5923.1.1.1.6'],
|
||||||
|
first_name: ['urn:oid:2.5.4.3'],
|
||||||
|
nickname: ['urn:oid:2.16.840.1.113730.3.1.241']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label: 'passbook'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards, either run `gitlab-ctl reconfigure` if you're running GitLab Omnibus, or restart the container if you're using the container.
|
BIN
docs/integrations/services/harbor/harbor.png
Normal file
After Width: | Height: | Size: 348 KiB |
27
docs/integrations/services/harbor/index.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# Harbor Integration
|
||||||
|
|
||||||
|
## What is Harbor
|
||||||
|
|
||||||
|
From https://goharbor.io
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Harbor is an open source container image registry that secures images with role-based access control, scans images for vulnerabilities, and signs images as trusted. A CNCF Incubating project, Harbor delivers compliance, performance, and interoperability to help you consistently and securely manage images across cloud native compute platforms like Kubernetes and Docker.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `harbor.company` is the FQDN of the Harbor install.
|
||||||
|
- `passbook.company` is the FQDN of the passbook install.
|
||||||
|
|
||||||
|
Create an application in passbook. Create an OpenID provider with the following parameters:
|
||||||
|
|
||||||
|
- Client Type: `Confidential`
|
||||||
|
- Response types: `code (Authorization Code Flow)`
|
||||||
|
- JWT Algorithm: `RS256`
|
||||||
|
- Redirect URIs: `https://harbor.company/c/oidc/callback`
|
||||||
|
- Scopes: `openid`
|
||||||
|
|
||||||
|
## Harbor
|
||||||
|
|
||||||
|

|
28
docs/integrations/services/rancher/index.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Rancher Integration
|
||||||
|
|
||||||
|
## What is Rancher
|
||||||
|
|
||||||
|
From https://rancher.com/products/rancher
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
An enterprise platform for managing Kubernetes Everywhere
|
||||||
|
Rancher is a platform built to address the needs of the DevOps teams deploying applications with Kubernetes, and the IT staff responsible for delivering an enterprise-critical service.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `rancher.company` is the FQDN of the Rancher install.
|
||||||
|
- `passbook.company` is the FQDN of the passbook install.
|
||||||
|
|
||||||
|
Create an application in passbook and note the slug, as this will be used later. Create a SAML provider with the following parameters:
|
||||||
|
|
||||||
|
- ACS URL: `https://rancher.company/v1-saml/adfs/saml/acs`
|
||||||
|
- Audience: `https://rancher.company/v1-saml/adfs/saml/metadata`
|
||||||
|
- Issuer: `passbook`
|
||||||
|
|
||||||
|
You can of course use a custom signing certificate, and adjust durations.
|
||||||
|
|
||||||
|
## Rancher
|
||||||
|
|
||||||
|

|
BIN
docs/integrations/services/rancher/rancher.png
Normal file
After Width: | Height: | Size: 525 KiB |
41
docs/integrations/services/sentry/index.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Sentry Integration
|
||||||
|
|
||||||
|
## What is Sentry
|
||||||
|
|
||||||
|
From https://sentry.io
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Sentry provides self-hosted and cloud-based error monitoring that helps all software
|
||||||
|
teams discover, triage, and prioritize errors in real-time.
|
||||||
|
|
||||||
|
One million developers at over fifty thousand companies already ship
|
||||||
|
better software faster with Sentry. Won’t you join them?
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `sentry.company` is the FQDN of the Sentry install.
|
||||||
|
- `passbook.company` is the FQDN of the passbook install.
|
||||||
|
|
||||||
|
Create an application in passbook. Create an OpenID provider with the following parameters:
|
||||||
|
|
||||||
|
- Client Type: `Confidential`
|
||||||
|
- Response types: `code (Authorization Code Flow)`
|
||||||
|
- JWT Algorithm: `RS256`
|
||||||
|
- Redirect URIs: `https://sentry.company/auth/sso/`
|
||||||
|
- Scopes: `openid email`
|
||||||
|
|
||||||
|
## Sentry
|
||||||
|
|
||||||
|
**This guide assumes you've installed Sentry using [getsentry/onpremise](https://github.com/getsentry/onpremise)**
|
||||||
|
|
||||||
|
- Add `sentry-auth-oidc` to `onpremise/sentry/requirements.txt` (Create the file if it doesn't exist yet)
|
||||||
|
- Add the following block to your `onpremise/sentry/sentry.conf.py`:
|
||||||
|
```
|
||||||
|
OIDC_ISSUER = "passbook"
|
||||||
|
OIDC_CLIENT_ID = "<Client ID from passbook>"
|
||||||
|
OIDC_CLIENT_SECRET = "<Client Secret from passbook>"
|
||||||
|
OIDC_SCOPE = "openid email"
|
||||||
|
OIDC_DOMAIN = "https://passbook.company/application/oidc/"
|
||||||
|
```
|
74
docs/integrations/services/tower-awx/index.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Ansible Tower / AWX Integration
|
||||||
|
|
||||||
|
## What is Tower
|
||||||
|
|
||||||
|
From https://docs.ansible.com/ansible/2.5/reference_appendices/tower.html
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
Ansible Tower (formerly ‘AWX’) is a web-based solution that makes Ansible even more easy to use for IT teams of all kinds. It’s designed to be the hub for all of your automation tasks.
|
||||||
|
|
||||||
|
Tower allows you to control access to who can access what, even allowing sharing of SSH credentials without someone being able to transfer those credentials. Inventory can be graphically managed or synced with a wide variety of cloud sources. It logs all of your jobs, integrates well with LDAP, and has an amazing browsable REST API. Command line tools are available for easy integration with Jenkins as well. Provisioning callbacks provide great support for autoscaling topologies.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
AWX is the open-source version of Tower. The term "AWX" will be used interchangeably throughout this document.
|
||||||
|
|
||||||
|
## Preparation
|
||||||
|
|
||||||
|
The following placeholders will be used:
|
||||||
|
|
||||||
|
- `awx.company` is the FQDN of the AWX/Tower install.
|
||||||
|
- `passbook.company` is the FQDN of the passbook install.
|
||||||
|
|
||||||
|
Create an application in passbook and note the slug, as this will be used later. Create a SAML provider with the following parameters:
|
||||||
|
|
||||||
|
- ACS URL: `https://awx.company/sso/complete/saml/`
|
||||||
|
- Audience: `awx`
|
||||||
|
- Issuer: `https://awx.company/sso/metadata/saml/`
|
||||||
|
|
||||||
|
You can of course use a custom signing certificate, and adjust durations.
|
||||||
|
|
||||||
|
## AWX Configuration
|
||||||
|
|
||||||
|
Navigate to `https://awx.company/#/settings/auth` to configure SAML. Set the Field `SAML SERVICE PROVIDER ENTITY ID` to `awx`.
|
||||||
|
|
||||||
|
For the fields `SAML SERVICE PROVIDER PUBLIC CERTIFICATE` and `SAML SERVICE PROVIDER PRIVATE KEY`, you can either use custom certificates, or use the self-signed pair generated by passbook.
|
||||||
|
|
||||||
|
Provide metadata in the `SAML Service Provider Organization Info` field:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"en-US": {
|
||||||
|
"name": "passbook",
|
||||||
|
"url": "https://passbook.company",
|
||||||
|
"displayname": "passbook"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Provide metadata in the `SAML Service Provider Technical Contact` and `SAML Service Provider Technical Contact` fields:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"givenName": "Admin Name",
|
||||||
|
"emailAddress": "admin@company"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the `SAML Enabled Identity Providers` paste the following configuration:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"passbook": {
|
||||||
|
"attr_username": "urn:oid:2.16.840.1.113730.3.1.241",
|
||||||
|
"attr_user_permanent_id": "urn:oid:0.9.2342.19200300.100.1.1",
|
||||||
|
"x509cert": "MIIDEjCCAfqgAwIBAgIRAJZ9pOZ1g0xjiHtQAAejsMEwDQYJKoZIhvcNAQELBQAwMDEuMCwGA1UEAwwlcGFzc2Jvb2sgU2VsZi1zaWduZWQgU0FNTCBDZXJ0aWZpY2F0ZTAeFw0xOTEyMjYyMDEwNDFaFw0yMDEyMjYyMDEwNDFaMFkxLjAsBgNVBAMMJXBhc3Nib29rIFNlbGYtc2lnbmVkIFNBTUwgQ2VydGlmaWNhdGUxETAPBgNVBAoMCHBhc3Nib29rMRQwEgYDVQQLDAtTZWxmLXNpZ25lZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO/ktBYZkY9xAijF4acvzX6Q1K8KoIZeyde8fVgcWBz4L5FgDQ4/dni4k2YAcPdwteGL4nKVzetUzjbRCBUNuO6lqU4J4WNNX4Xg4Ir7XLRoAQeo+omTPBdpJ1p02HjtN5jT01umN3bK2yto1e37CJhK6WJiaXqRewPxh4lI4aqdj3BhFkJ3I3r2qxaWOAXQ6X7fg3w/ny7QP53//ouZo7hSLY3GIcRKgvdjjVM3OW5C3WLpOq5Dez5GWVJ17aeFCfGQ8bwFKde6qfYqyGcU9xHB36TtVHB9hSFP/tUFhkiSOxtsrYwCgCyXm4UTSpP+wiNyjKfFw7qGLBvA2hGTNw8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAh9PeAqPRQk1/SSygIFADZBi08O/DPCshFwEHvJATIcTzcDD8UGAjXh+H5OlkDyX7KyrcaNvYaafCUo63A+WprdtdY5Ty6SBEwTYyiQyQfwM9BfK+imCoif1Ai7xAelD7p9lNazWq7JU+H/Ep7U7Q7LvpxAbK0JArt+IWTb2NcMb3OWE1r0gFbs44O1l6W9UbJTbyLMzbGbe5i+NHlgnwPwuhtRMh0NUYabGHKcHbhwyFhfGAQv2dAp5KF1E5gu6ZzCiFePzc0FrqXQyb2zpFYcJHXquiqaOeG7cZxRHYcjrl10Vxzki64XVA9BpdELgKSnupDGUEJsRUt3WVOmvZuA==",
|
||||||
|
"url": "https://passbook.company/application/saml/awx/login/",
|
||||||
|
"attr_last_name": "User.LastName",
|
||||||
|
"entity_id": "https://awx.company/sso/metadata/saml/",
|
||||||
|
"attr_email": "urn:oid:0.9.2342.19200300.100.1.3",
|
||||||
|
"attr_first_name": "urn:oid:2.5.4.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`x509cert` is the certificate configured in passbook. Remove the `--BEGIN CERTIFICATE--` and `--END CERTIFICATE--` headers, then enter the cert as one non-breaking string.
|
30
docs/policies/expression.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Expression Policies
|
||||||
|
|
||||||
|
!!! notice
|
||||||
|
These variables are available in addition to the common variables/functions defined in [**Expressions**](../expressions/index.md)
|
||||||
|
|
||||||
|
The passing of the policy is determined by the return value of the code. Use `return True` to pass a policy and `return False` to fail it.
|
||||||
|
|
||||||
|
### Available Functions
|
||||||
|
|
||||||
|
#### `pb_message(message: str)`
|
||||||
|
|
||||||
|
Add a message, visible by the end user. This can be used to show the reason why they were denied.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
pb_message("Access denied")
|
||||||
|
return False
|
||||||
|
```
|
||||||
|
|
||||||
|
### Context variables
|
||||||
|
|
||||||
|
- `request`: A PolicyRequest object, which has the following properties:
|
||||||
|
- `request.user`: The current user, against which the policy is applied. ([ref](../expressions/reference/user-object.md))
|
||||||
|
- `request.http_request`: The Django HTTP Request. ([ref](https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects))
|
||||||
|
- `request.obj`: A Django Model instance. This is only set if the policy is ran against an object.
|
||||||
|
- `request.context`: A dictionary with dynamic data. This depends on the origin of the execution.
|
||||||
|
- `pb_is_sso_flow`: Boolean which is true if request was initiated by authenticating through an external provider.
|
||||||
|
- `pb_client_ip`: Client's IP Address or '255.255.255.255' if no IP Address could be extracted.
|
||||||
|
- `pb_flow_plan`: Current Plan if Policy is called from the Flow Planner.
|
42
docs/policies/index.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Policies
|
||||||
|
|
||||||
|
## Kinds
|
||||||
|
|
||||||
|
There are two different kinds of policies; Standard Policy and Password Policy. Normal policies evaluate to True or False, and can be used everywhere. Password policies apply when a password is set (during user enrollment, recovery or anywhere else). These policies can be used to apply password rules such as length, complexity, etc. They can also be used to expire passwords after a certain amount of time.
|
||||||
|
|
||||||
|
## Standard Policies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Reputation Policy
|
||||||
|
|
||||||
|
passbook keeps track of failed login attempts by source IP and attempted username. These values are saved as scores. Each failed login decreases the score for the client IP as well as the targeted username by 1 (one).
|
||||||
|
|
||||||
|
This policy can be used, for example, to prompt clients with a low score to pass a captcha before they can continue.
|
||||||
|
|
||||||
|
## Expression Policy
|
||||||
|
|
||||||
|
See [Expression Policy](expression.md).
|
||||||
|
|
||||||
|
## Password Policies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Password Policy
|
||||||
|
|
||||||
|
This policy allows you to specify password rules, such as length and required characters.
|
||||||
|
The following rules can be set:
|
||||||
|
|
||||||
|
- Minimum amount of uppercase characters.
|
||||||
|
- Minimum amount of lowercase characters.
|
||||||
|
- Minimum amount of symbols characters.
|
||||||
|
- Minimum length.
|
||||||
|
- Symbol charset (define which characters are counted as symbols).
|
||||||
|
|
||||||
|
### Have I Been Pwned Policy
|
||||||
|
|
||||||
|
This policy checks the hashed password against the [Have I Been Pwned](https://haveibeenpwned.com/) API. This only sends the first 5 characters of the hashed password. The remaining comparison is done within passbook.
|
||||||
|
|
||||||
|
### Password-Expiry Policy
|
||||||
|
|
||||||
|
This policy can enforce regular password rotation by expiring set passwords after a finite amount of time. This forces users to set a new password.
|
12
docs/property-mappings/expression.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Property Mapping Expressions
|
||||||
|
|
||||||
|
The property mapping should return a value that is expected by the Provider/Source. Supported types are documented in the individual Provider/Source. Returning `None` is always accepted and would simply skip the mapping for which `None` was returned.
|
||||||
|
|
||||||
|
!!! notice
|
||||||
|
These variables are available in addition to the common variables/functions defined in [**Expressions**](../expressions/index.md)
|
||||||
|
|
||||||
|
### Context Variables
|
||||||
|
|
||||||
|
- `user`: The current user. This may be `None` if there is no contextual user. ([ref](../expressions/reference/user-object.md))
|
||||||
|
- `request`: The current request. This may be `None` if there is no contextual request. ([ref](https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects))
|
||||||
|
- Other arbitrary arguments given by the provider, this is documented on the Provider/Source.
|
21
docs/property-mappings/index.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Property Mappings
|
||||||
|
|
||||||
|
Property Mappings allow you to pass information to external applications. For example, pass the current user's groups as a SAML parameter. Property Mappings are also used to map Source fields to passbook fields, for example when using LDAP.
|
||||||
|
|
||||||
|
## SAML Property Mapping
|
||||||
|
|
||||||
|
SAML Property Mappings allow you embed information into the SAML AuthN request. This information can then be used by the application to, for example, assign permissions to the object.
|
||||||
|
|
||||||
|
You can find examples [here](integrations/).
|
||||||
|
|
||||||
|
## LDAP Property Mapping
|
||||||
|
|
||||||
|
LDAP Property Mappings are used when you define a LDAP Source. These mappings define which LDAP property maps to which passbook property. By default, the following mappings are created:
|
||||||
|
|
||||||
|
- Autogenerated LDAP Mapping: givenName -> first_name
|
||||||
|
- Autogenerated LDAP Mapping: mail -> email
|
||||||
|
- Autogenerated LDAP Mapping: name -> name
|
||||||
|
- Autogenerated LDAP Mapping: sAMAccountName -> username
|
||||||
|
- Autogenerated LDAP Mapping: sn -> last_name
|
||||||
|
|
||||||
|
These are configured with most common LDAP setups.
|
24
docs/providers.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Providers
|
||||||
|
|
||||||
|
Providers allow external applications to authenticate against passbook and use its user information.
|
||||||
|
|
||||||
|
## OpenID Provider
|
||||||
|
|
||||||
|
This provider utilises the commonly used OpenID Connect variation of OAuth2.
|
||||||
|
|
||||||
|
## OAuth2 Provider
|
||||||
|
|
||||||
|
This provider is slightly different than the OpenID Provider. While it uses the same basic OAuth2 Protocol, it provides a GitHub-compatible endpoint. This allows you to integrate applications which don't support custom OpenID providers.
|
||||||
|
The API exposes username, email, name, and groups in a GitHub-compatible format.
|
||||||
|
This provider currently supports the following scopes:
|
||||||
|
|
||||||
|
- `openid`: Access OpenID Userinfo
|
||||||
|
- `userinfo`: Access OpenID Userinfo
|
||||||
|
- `email`: Access OpenID Email
|
||||||
|
- `user:email`: GitHub Compatibility: User Email
|
||||||
|
- `read:org`: GitHub Compatibility: User Groups
|
||||||
|
|
||||||
|
## SAML Provider
|
||||||
|
|
||||||
|
This provider allows you to integrate enterprise software using the SAML2 Protocol. It supports signed requests and uses [Property Mappings](property-mappings/index.md#saml-property-mapping) to determine which fields are exposed and what values they return. This makes it possible to expose vendor-specific fields.
|
||||||
|
Default fields are exposed through auto-generated Property Mappings, which are prefixed with "Autogenerated".
|
2
docs/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
mkdocs
|
||||||
|
mkdocs-material
|
1
docs/runtime.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.7
|
39
docs/sources.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
Sources allow you to connect passbook to an existing user directory. They can also be used for social logins, using external providers such as Facebook, Twitter, etc.
|
||||||
|
|
||||||
|
## Generic OAuth Source
|
||||||
|
|
||||||
|
**All Integration-specific Sources are documented in the Integrations Section**
|
||||||
|
|
||||||
|
This source allows users to enroll themselves with an external OAuth-based Identity Provider. The generic provider expects the endpoint to return OpenID-Connect compatible information. Vendor-specific implementations have their own OAuth Source.
|
||||||
|
|
||||||
|
- Policies: Allow/Forbid users from linking their accounts with this provider.
|
||||||
|
- Request Token URL: This field is used for OAuth v1 implementations and will be provided by the provider.
|
||||||
|
- Authorization URL: This value will be provided by the provider.
|
||||||
|
- Access Token URL: This value will be provided by the provider.
|
||||||
|
- Profile URL: This URL is called by passbook to retrieve user information upon successful authentication.
|
||||||
|
- Consumer key/Consumer secret: These values will be provided by the provider.
|
||||||
|
|
||||||
|
## SAML Source
|
||||||
|
|
||||||
|
This source allows passbook to act as a SAML Service Provider. Just like the SAML Provider, it supports signed requests. Vendor-specific documentation can be found in the Integrations Section.
|
||||||
|
|
||||||
|
## LDAP Source
|
||||||
|
|
||||||
|
This source allows you to import users and groups from an LDAP Server.
|
||||||
|
|
||||||
|
- Server URI: URI to your LDAP server/Domain Controller.
|
||||||
|
- Bind CN: CN of the bind user. This can also be a UPN in the format of `user@domain.tld`.
|
||||||
|
- Bind password: Password used during the bind process.
|
||||||
|
- Enable StartTLS: Enables StartTLS functionality. To use LDAPS instead, use port `636`.
|
||||||
|
- Base DN: Base DN used for all LDAP queries.
|
||||||
|
- Addition User DN: Prepended to the base DN for user queries.
|
||||||
|
- Addition Group DN: Prepended to the base DN for group queries.
|
||||||
|
- User object filter: Consider objects matching this filter to be users.
|
||||||
|
- Group object filter: Consider objects matching this filter to be groups.
|
||||||
|
- User group membership field: This field contains the user's group memberships.
|
||||||
|
- Object uniqueness field: This field contains a unique identifier.
|
||||||
|
- Sync groups: Enable/disable group synchronization. Groups are synced in the background every 5 minutes.
|
||||||
|
- Sync parent group: Optionally set this group as the parent group for all synced groups. An example use case of this would be to import Active Directory groups under a root `imported-from-ad` group.
|
||||||
|
- Property mappings: Define which LDAP properties map to which passbook properties. The default set of property mappings is generated for Active Directory. See also [LDAP Property Mappings](property-mappings/index.md#ldap-property-mapping)
|
27
docs/terminology.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
### Policy
|
||||||
|
|
||||||
|
At a base level a policy is a yes/no gate. It will either evaluate to True or False depending on the Policy Kind and settings. For example, a "Group Membership Policy" evaluates to True if the user is member of the specified Group and False if not. This can be used to conditionally apply Stages, grant/deny access to various objects, and for other custom logic.
|
||||||
|
|
||||||
|
### Provider
|
||||||
|
|
||||||
|
A Provider is a way for other applications to authenticate against passbook. Common Providers are OpenID Connect (OIDC) and SAML.
|
||||||
|
|
||||||
|
### Source
|
||||||
|
|
||||||
|
Sources are locations from which users can be added to passbook. For example, an LDAP Connection to import Users from Active Directory, or an OAuth2 Connection to allow Social Logins.
|
||||||
|
|
||||||
|
### Application
|
||||||
|
|
||||||
|
An application links together Policies with a Provider, allowing you to control access. It also holds Information like UI Name, Icon and more.
|
||||||
|
|
||||||
|
### Stages
|
||||||
|
|
||||||
|
A stage represents a single verification or logic step. They are used to authenticate users, enroll users, and more. These stages can optionally be applied to a flow via policies.
|
||||||
|
|
||||||
|
### Flows
|
||||||
|
|
||||||
|
Flows are an ordered sequence of stages. These flows can be used to define how a user authenticates, enrolls, etc.
|
||||||
|
|
||||||
|
### Property Mappings
|
||||||
|
|
||||||
|
Property Mappings allow you to make information available for external applications. For example, if you want to login to AWS with passbook, you'd use Property Mappings to set the user's roles in AWS based on their group memberships in passbook.
|
33
docs/upgrading-from-0.8.x.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Upgrading from 0.8.x
|
||||||
|
|
||||||
|
Due to some database changes that had to be rather sooner than later, there is no possibility to directly upgrade. You must extract the data before hand and import it again. It is recommended to spin up a second instance of passbook to do this.
|
||||||
|
|
||||||
|
To export data from your old instance, run this command:
|
||||||
|
|
||||||
|
- docker-compose
|
||||||
|
```
|
||||||
|
docker-compose exec server ./manage.py dumpdata -o /tmp/passbook_dump.json passbook_core.User passbook_core.Group passbook_crypto.CertificateKeyPair passbook_audit.Event otp_totp.totpdevice otp_static.staticdevice otp_static.statictoken
|
||||||
|
docker cp passbook_server_1:/tmp/passbook_dump.json passbook_dump.json
|
||||||
|
```
|
||||||
|
|
||||||
|
- kubernetes
|
||||||
|
```
|
||||||
|
kubectl exec -it passbook-web-... -- ./manage.py dumpdata -o /tmp/passbook_dump.json passbook_core.User passbook_core.Group passbook_crypto.CertificateKeyPair passbook_audit.Event otp_totp.totpdevice otp_static.staticdevice otp_static.statictoken
|
||||||
|
kubectl cp passbook-web-...:/tmp/passbook_dump.json passbook_dump.json
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, create a new passbook instance in a different namespace (kubernetes) or in a different folder (docker-compose). Once this instance is running, you can use the following commands to restore the data. On docker-compose, you still have to run the `migrate` command, to create all database structures.
|
||||||
|
|
||||||
|
- docker-compose
|
||||||
|
```
|
||||||
|
docker cp passbook_dump.json new_passbook_server_1:/tmp/passbook_dump.json
|
||||||
|
docker-compose exec server ./manage.py loaddata /tmp/passbook_dump.json
|
||||||
|
```
|
||||||
|
|
||||||
|
- kubernetes
|
||||||
|
```
|
||||||
|
kubectl cp passbook_dump.json passbook-web-...:/tmp/passbook_dump.json
|
||||||
|
kubectl exec -it passbook-web-... -- ./manage.py loaddata /tmp/passbook_dump.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, you should be able to login to the new passbook instance, and migrate the rest of the data over.
|
20
e2e/docker-compose.yml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
version: '3.7'
|
||||||
|
|
||||||
|
services:
|
||||||
|
chrome:
|
||||||
|
image: selenium/standalone-chrome-debug:3.141.59-20200525
|
||||||
|
volumes:
|
||||||
|
- /dev/shm:/dev/shm
|
||||||
|
network_mode: host
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
image: postgres:11
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_HOST_AUTH_METHOD: trust
|
||||||
|
POSTGRES_DB: passbook
|
||||||
|
network_mode: host
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
restart: always
|
||||||
|
network_mode: host
|