Compare commits
27 Commits
version/0.
...
version/0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.7.13-beta
|
||||
current_version = 0.7.16-beta
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -56,7 +56,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pipenv-
|
||||
- name: Install dependencies
|
||||
run: pip install -U pip pipenv && pipenv install --dev
|
||||
run: pip install -U pip pipenv && pipenv install --dev && pipenv install --dev prospector --skip-lock
|
||||
- name: Lint with prospector
|
||||
run: pipenv run prospector
|
||||
bandit:
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@ -16,11 +16,11 @@ jobs:
|
||||
- name: Building Docker Image
|
||||
run: docker build
|
||||
--no-cache
|
||||
-t beryju/passbook:0.7.13-beta
|
||||
-t beryju/passbook:0.7.16-beta
|
||||
-t beryju/passbook:latest
|
||||
-f Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/passbook:0.7.13-beta
|
||||
run: docker push beryju/passbook:0.7.16-beta
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/passbook:latest
|
||||
build-gatekeeper:
|
||||
@ -37,11 +37,11 @@ jobs:
|
||||
cd gatekeeper
|
||||
docker build \
|
||||
--no-cache \
|
||||
-t beryju/passbook-gatekeeper:0.7.13-beta \
|
||||
-t beryju/passbook-gatekeeper:0.7.16-beta \
|
||||
-t beryju/passbook-gatekeeper:latest \
|
||||
-f Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/passbook-gatekeeper:0.7.13-beta
|
||||
run: docker push beryju/passbook-gatekeeper:0.7.16-beta
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/passbook-gatekeeper:latest
|
||||
build-static:
|
||||
@ -66,11 +66,11 @@ jobs:
|
||||
run: docker build
|
||||
--no-cache
|
||||
--network=$(docker network ls | grep github | awk '{print $1}')
|
||||
-t beryju/passbook-static:0.7.13-beta
|
||||
-t beryju/passbook-static:0.7.16-beta
|
||||
-t beryju/passbook-static:latest
|
||||
-f static.Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/passbook-static:0.7.13-beta
|
||||
run: docker push beryju/passbook-static:0.7.16-beta
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/passbook-static:latest
|
||||
test-release:
|
||||
|
||||
2
Pipfile
2
Pipfile
@ -40,6 +40,7 @@ signxml = "*"
|
||||
structlog = "*"
|
||||
swagger-spec-validator = "*"
|
||||
urllib3 = {extras = ["secure"],version = "*"}
|
||||
jinja2 = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.8"
|
||||
@ -51,7 +52,6 @@ bumpversion = "*"
|
||||
colorama = "*"
|
||||
coverage = "*"
|
||||
django-debug-toolbar = "*"
|
||||
prospector = "*"
|
||||
pylint = "*"
|
||||
pylint-django = "*"
|
||||
unittest-xml-reporting = "*"
|
||||
|
||||
324
Pipfile.lock
generated
324
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "3693ac70f66ada5c8c8784e6e2d5c2f0ee75219e7141dde1075347234366e314"
|
||||
"sha256": "c9232d99b062ee14eda43d176481f16da78ce53f912c844db3f33f1b3e8a47b7"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -23,6 +23,13 @@
|
||||
],
|
||||
"version": "==2.5.2"
|
||||
},
|
||||
"asgiref": {
|
||||
"hashes": [
|
||||
"sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0",
|
||||
"sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5"
|
||||
],
|
||||
"version": "==3.2.3"
|
||||
},
|
||||
"asn1crypto": {
|
||||
"hashes": [
|
||||
"sha256:5a215cb8dc12f892244e3a113fe05397ee23c5c4ca7a69cd6e69811755efc42d",
|
||||
@ -46,18 +53,18 @@
|
||||
},
|
||||
"boto3": {
|
||||
"hashes": [
|
||||
"sha256:7aaccacc199cd633b5ac14f0d544c9d592c53275a79cf4d230a9f66215331665",
|
||||
"sha256:ca36aabfa5e7fa9ee8f84f82c3faffb4ffe078923f935f572f70dc49154ef6a0"
|
||||
"sha256:33462a79d57c9c4a215e075472509537d03545f54566fc4f776fb0f4cfa616f6",
|
||||
"sha256:34f9a04f529dc849f0e427782d6f3c6b62f7fb734d8f4859b17e5dee0855323e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.11.5"
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"botocore": {
|
||||
"hashes": [
|
||||
"sha256:2538065f9f5023eae3607e78fc5d8c595c9173ec02bc92410652078617c44ac1",
|
||||
"sha256:554231b1690c8521e05a41e50184e43d62941fdf9351e658aea894649b879985"
|
||||
"sha256:055da4826f6c9158e4a61549d57a2ce449c27d44ce34ab4c96c7bb7b5c993efc",
|
||||
"sha256:1f7cecfcd38c7cac17b5386014eb04626d1c7559ee8d8ec1526058cd23f6d1d4"
|
||||
],
|
||||
"version": "==1.14.15"
|
||||
"version": "==1.15.0"
|
||||
},
|
||||
"celery": {
|
||||
"hashes": [
|
||||
@ -164,11 +171,11 @@
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a",
|
||||
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038"
|
||||
"sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283",
|
||||
"sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.2.10"
|
||||
"version": "==3.0.3"
|
||||
},
|
||||
"django-cors-middleware": {
|
||||
"hashes": [
|
||||
@ -195,11 +202,11 @@
|
||||
},
|
||||
"django-guardian": {
|
||||
"hashes": [
|
||||
"sha256:8cf4efd67a863eb32beafd4335a38ffb083630f8ab2045212d27f8f9c3abe5a6",
|
||||
"sha256:e638c9a23eeac534bb68b133975539ed8782f733ab6f35c0b23b4c39cd06b1bb"
|
||||
"sha256:8cacf49ebcc1e545f0a8997971eec0fe109f5ed31fc2a569a7bf5615453696e2",
|
||||
"sha256:ac81e88372fdf1795d84ba065550e739b42e9c6d07cdf201cf5bbf9efa7f396c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.1.0"
|
||||
"version": "==2.2.0"
|
||||
},
|
||||
"django-model-utils": {
|
||||
"hashes": [
|
||||
@ -225,27 +232,26 @@
|
||||
},
|
||||
"django-otp": {
|
||||
"hashes": [
|
||||
"sha256:1f16c2b93fe484706ff16ac6f5e64ecc73dd240318c333e0560384ba548d3837",
|
||||
"sha256:cd4975539be478417033561e9832a1a69a583189f680e92a649f412c661f90aa"
|
||||
"sha256:523a87f8d0c52ce9a9f0a5e248c59dab3e85cdda5bbcd106cf49138a8f3f3209",
|
||||
"sha256:ad3206e4a6f461c8968a2366a7cccfb340b93294e604b278aa9ab8b26f1017a1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.5"
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"django-prometheus": {
|
||||
"hashes": [
|
||||
"sha256:f0657d4b887309086b71b55f6aa4a95f967b35fe115128b501f95422c423b12c",
|
||||
"sha256:f645016ae5270ac2025a70788cd2bd636244a0c5705b323cc086994bf828181e"
|
||||
"sha256:362ea45e5ee26bdba85ce978aeb370659ca6bbc0d6bac69868a055179e053bd1",
|
||||
"sha256:facaa677386899303ea26c45552371cc43f476e42a81c081011a49cb5564af0b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.0.dev124"
|
||||
"version": "==2.1.0.dev5"
|
||||
},
|
||||
"django-recaptcha": {
|
||||
"hashes": [
|
||||
"sha256:3b19b9d972ca802b683eed5fd51ed84b0798f2a52f8d057a912eb7d99cff3779",
|
||||
"sha256:b6ce959cd7c0af7501698fab5f52ca1bcb6d9402cb3b8b42a4c4cb13d89cfbfa"
|
||||
"sha256:567784963fd5400feaf92e8951d8dbbbdb4b4c48a76e225d4baa63a2c9d2cd8c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.5"
|
||||
"version": "==2.0.6"
|
||||
},
|
||||
"django-redis": {
|
||||
"hashes": [
|
||||
@ -264,11 +270,11 @@
|
||||
},
|
||||
"django-storages": {
|
||||
"hashes": [
|
||||
"sha256:0a9b7e620e969fb0797523695329ed223bf540bbfdf6cd163b061fc11dab2d1c",
|
||||
"sha256:9322ab74ba6371e2e0fccc350c741686ade829e43085597b26b07ae8955a0a00"
|
||||
"sha256:3103991c2ee8cef8a2ff096709973ffe7106183d211a79f22cf855f33533d924",
|
||||
"sha256:a59e9923cbce7068792f75344ed7727021ee4ac20f227cf17297d0d03d141e91"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.8"
|
||||
"version": "==1.9.1"
|
||||
},
|
||||
"djangorestframework": {
|
||||
"hashes": [
|
||||
@ -295,11 +301,11 @@
|
||||
},
|
||||
"drf-yasg": {
|
||||
"hashes": [
|
||||
"sha256:4cfec631880ae527a91ec7cd3241aea2f82189f59e2f089119aa687761afb227",
|
||||
"sha256:504cce09035cf1bace63b84d9d778b772f86bb37d8a71ed6f723346362e633b2"
|
||||
"sha256:5572e9d5baab9f6b49318169df9789f7399d0e3c7bdac8fdb8dfccf1d5d2b1ca",
|
||||
"sha256:7d7af27ad16e18507e9392b2afd6b218fbffc432ec8dbea053099a2241e184ff"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.17.0"
|
||||
"version": "==1.17.1"
|
||||
},
|
||||
"eight": {
|
||||
"hashes": [
|
||||
@ -338,6 +344,7 @@
|
||||
"sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484",
|
||||
"sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.0a1"
|
||||
},
|
||||
"jmespath": {
|
||||
@ -372,35 +379,36 @@
|
||||
},
|
||||
"lxml": {
|
||||
"hashes": [
|
||||
"sha256:00ac0d64949fef6b3693813fe636a2d56d97a5a49b5bbb86e4cc4cc50ebc9ea2",
|
||||
"sha256:0571e607558665ed42e450d7bf0e2941d542c18e117b1ebbf0ba72f287ad841c",
|
||||
"sha256:0e3f04a7615fdac0be5e18b2406529521d6dbdb0167d2a690ee328bef7807487",
|
||||
"sha256:13cf89be53348d1c17b453867da68704802966c433b2bb4fa1f970daadd2ef70",
|
||||
"sha256:217262fcf6a4c2e1c7cb1efa08bd9ebc432502abc6c255c4abab611e8be0d14d",
|
||||
"sha256:223e544828f1955daaf4cefbb4853bc416b2ec3fd56d4f4204a8b17007c21250",
|
||||
"sha256:277cb61fede2f95b9c61912fefb3d43fbd5f18bf18a14fae4911b67984486f5d",
|
||||
"sha256:3213f753e8ae86c396e0e066866e64c6b04618e85c723b32ecb0909885211f74",
|
||||
"sha256:4690984a4dee1033da0af6df0b7a6bde83f74e1c0c870623797cec77964de34d",
|
||||
"sha256:4fcc472ef87f45c429d3b923b925704aa581f875d65bac80f8ab0c3296a63f78",
|
||||
"sha256:61409bd745a265a742f2693e4600e4dbd45cc1daebe1d5fad6fcb22912d44145",
|
||||
"sha256:678f1963f755c5d9f5f6968dded7b245dd1ece8cf53c1aa9d80e6734a8c7f41d",
|
||||
"sha256:6c6d03549d4e2734133badb9ab1c05d9f0ef4bcd31d83e5d2b4747c85cfa21da",
|
||||
"sha256:6e74d5f4d6ecd6942375c52ffcd35f4318a61a02328f6f1bd79fcb4ffedf969e",
|
||||
"sha256:7b4fc7b1ecc987ca7aaf3f4f0e71bbfbd81aaabf87002558f5bc95da3a865bcd",
|
||||
"sha256:7ed386a40e172ddf44c061ad74881d8622f791d9af0b6f5be20023029129bc85",
|
||||
"sha256:8f54f0924d12c47a382c600c880770b5ebfc96c9fd94cf6f6bdc21caf6163ea7",
|
||||
"sha256:ad9b81351fdc236bda538efa6879315448411a81186c836d4b80d6ca8217cdb9",
|
||||
"sha256:bbd00e21ea17f7bcc58dccd13869d68441b32899e89cf6cfa90d624a9198ce85",
|
||||
"sha256:c3c289762cc09735e2a8f8a49571d0e8b4f57ea831ea11558247b5bdea0ac4db",
|
||||
"sha256:cf4650942de5e5685ad308e22bcafbccfe37c54aa7c0e30cd620c2ee5c93d336",
|
||||
"sha256:cfcbc33c9c59c93776aa41ab02e55c288a042211708b72fdb518221cc803abc8",
|
||||
"sha256:e301055deadfedbd80cf94f2f65ff23126b232b0d1fea28f332ce58137bcdb18",
|
||||
"sha256:ebbfe24df7f7b5c6c7620702496b6419f6a9aa2fd7f005eb731cc80d7b4692b9",
|
||||
"sha256:eff69ddbf3ad86375c344339371168640951c302450c5d3e9936e98d6459db06",
|
||||
"sha256:f6ed60a62c5f1c44e789d2cf14009423cb1646b44a43e40a9cf6a21f077678a1"
|
||||
"sha256:06d4e0bbb1d62e38ae6118406d7cdb4693a3fa34ee3762238bcb96c9e36a93cd",
|
||||
"sha256:0701f7965903a1c3f6f09328c1278ac0eee8f56f244e66af79cb224b7ef3801c",
|
||||
"sha256:1f2c4ec372bf1c4a2c7e4bb20845e8bcf8050365189d86806bad1e3ae473d081",
|
||||
"sha256:4235bc124fdcf611d02047d7034164897ade13046bda967768836629bc62784f",
|
||||
"sha256:5828c7f3e615f3975d48f40d4fe66e8a7b25f16b5e5705ffe1d22e43fb1f6261",
|
||||
"sha256:585c0869f75577ac7a8ff38d08f7aac9033da2c41c11352ebf86a04652758b7a",
|
||||
"sha256:5d467ce9c5d35b3bcc7172c06320dddb275fea6ac2037f72f0a4d7472035cea9",
|
||||
"sha256:63dbc21efd7e822c11d5ddbedbbb08cd11a41e0032e382a0fd59b0b08e405a3a",
|
||||
"sha256:7bc1b221e7867f2e7ff1933165c0cec7153dce93d0cdba6554b42a8beb687bdb",
|
||||
"sha256:8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60",
|
||||
"sha256:8a0ebda56ebca1a83eb2d1ac266649b80af8dd4b4a3502b2c1e09ac2f88fe128",
|
||||
"sha256:90ed0e36455a81b25b7034038e40880189169c308a3df360861ad74da7b68c1a",
|
||||
"sha256:95e67224815ef86924fbc2b71a9dbd1f7262384bca4bc4793645794ac4200717",
|
||||
"sha256:afdb34b715daf814d1abea0317b6d672476b498472f1e5aacbadc34ebbc26e89",
|
||||
"sha256:b4b2c63cc7963aedd08a5f5a454c9f67251b1ac9e22fd9d72836206c42dc2a72",
|
||||
"sha256:d068f55bda3c2c3fcaec24bd083d9e2eede32c583faf084d6e4b9daaea77dde8",
|
||||
"sha256:d5b3c4b7edd2e770375a01139be11307f04341ec709cf724e0f26ebb1eef12c3",
|
||||
"sha256:deadf4df349d1dcd7b2853a2c8796593cc346600726eff680ed8ed11812382a7",
|
||||
"sha256:df533af6f88080419c5a604d0d63b2c33b1c0c4409aba7d0cb6de305147ea8c8",
|
||||
"sha256:e4aa948eb15018a657702fee0b9db47e908491c64d36b4a90f59a64741516e77",
|
||||
"sha256:e5d842c73e4ef6ed8c1bd77806bf84a7cb535f9c0cf9b2c74d02ebda310070e1",
|
||||
"sha256:ebec08091a22c2be870890913bdadd86fcd8e9f0f22bcb398abd3af914690c15",
|
||||
"sha256:edc15fcfd77395e24543be48871c251f38132bb834d9fdfdad756adb6ea37679",
|
||||
"sha256:f2b74784ed7e0bc2d02bd53e48ad6ba523c9b36c194260b7a5045071abbb1012",
|
||||
"sha256:fa071559f14bd1e92077b1b5f6c22cf09756c6de7139370249eb372854ce51e6",
|
||||
"sha256:fd52e796fee7171c4361d441796b64df1acfceb51f29e545e812f16d023c4bbc",
|
||||
"sha256:fe976a0f1ef09b3638778024ab9fb8cde3118f203364212c198f71341c0715ca"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.4.2"
|
||||
"version": "==4.5.0"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
@ -450,11 +458,11 @@
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb",
|
||||
"sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8"
|
||||
"sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73",
|
||||
"sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==20.0"
|
||||
"version": "==20.1"
|
||||
},
|
||||
"prometheus-client": {
|
||||
"hashes": [
|
||||
@ -522,41 +530,39 @@
|
||||
},
|
||||
"pycryptodome": {
|
||||
"hashes": [
|
||||
"sha256:042ae873baadd0c33b4d699a5c5b976ade3233a979d972f98ca82314632d868c",
|
||||
"sha256:0502876279772b1384b660ccc91563d04490d562799d8e2e06b411e2d81128a9",
|
||||
"sha256:2de33ed0a95855735d5a0fc0c39603314df9e78ee8bbf0baa9692fb46b3b8bbb",
|
||||
"sha256:319e568baf86620b419d53063b18c216abf924875966efdfe06891b987196a45",
|
||||
"sha256:4372ec7518727172e1605c0843cdc5375d4771e447b8148c787b860260aae151",
|
||||
"sha256:48821950ffb9c836858d8fa09d7840b6df52eadd387a3c5acece55cb387743f9",
|
||||
"sha256:4b9533d4166ca07abdd49ce9d516666b1df944997fe135d4b21ac376aa624aff",
|
||||
"sha256:54456cf85130e01674d21fb1ab89ffccacb138a8ade88d72fa2b0ac898d2798b",
|
||||
"sha256:56fdd0e425f1b8fd3a00b6d96351f86226674974814c50534864d0124d48871f",
|
||||
"sha256:57b1b707363490c495ad0eeb38bd1b0e1697c497af25fad78d3a1ebf0477fd5b",
|
||||
"sha256:5c485ed6e9718ebcaa81138fa70ace9c563d202b56a8cee119b4085b023931f5",
|
||||
"sha256:63c103a22cbe9752f6ea9f1a0de129995bad91c4d03a66c67cffcf6ee0c9f1e1",
|
||||
"sha256:68fab8455efcbfe87c5d75015476f9b606227ffe244d57bfd66269451706e899",
|
||||
"sha256:6c2720696b10ae356040e888bde1239b8957fe18885ccf5e7b4e8dec882f0856",
|
||||
"sha256:72166c2ac520a5dbd2d90208b9c279161ec0861662a621892bd52fb6ca13ab91",
|
||||
"sha256:7c52308ac5b834331b2f107a490b2c27de024a229b61df4cdc5c131d563dfe98",
|
||||
"sha256:87d8d85b4792ca5e730fb7a519fbc3ed976c59dcf79c5204589c59afd56b9926",
|
||||
"sha256:896e9b6fd0762aa07b203c993fbbee7a1f1a4674c6886afd7bfa86f3d1be98a8",
|
||||
"sha256:8a799bea3c6617736e914a2e77c409f52893d382f619f088f8a80e2e21f573c1",
|
||||
"sha256:9d9945ac8375d5d8e60bd2a2e1df5882eaa315522eedf3ca868b1546dfa34eba",
|
||||
"sha256:9ef966c727de942de3e41aa8462c4b7b4bca70f19af5a3f99e31376589c11aac",
|
||||
"sha256:a168e73879619b467072509a223282a02c8047d932a48b74fbd498f27224aa04",
|
||||
"sha256:a30f501bbb32e01a49ef9e09ca1260e5ab49bf33a257080ec553e08997acc487",
|
||||
"sha256:a8ca2450394d3699c9f15ef25e8de9a24b401933716a1e39d37fa01f5fe3c58b",
|
||||
"sha256:aec4d42deb836b8fb3ba32f2ba1ef0d33dd3dc9d430b1479ee7a914490d15b5e",
|
||||
"sha256:b4af098f2a50f8d048ab12cabb59456585c0acf43d90ee79782d2d6d0ed59dba",
|
||||
"sha256:b55c60c321ac91945c60a40ac9896ac7a3d432bb3e8c14006dfd82ad5871c331",
|
||||
"sha256:c53348358408d94869059e16fba5ff3bef8c52c25b18421472aba272b9bb450f",
|
||||
"sha256:cbfd97f9e060f0d30245cd29fa267a9a84de9da97559366fca0a3f7655acc63f",
|
||||
"sha256:d3fe3f33ad52bf0c19ee6344b695ba44ffbfa16f3c29ca61116b48d97bd970fb",
|
||||
"sha256:e3a79a30d15d9c7c284a7734036ee8abdb5ca3a6f5774d293cdc9e1358c1dc10",
|
||||
"sha256:eec0689509389f19875f66ae8dedd59f982240cdab31b9f78a8dc266011df93a"
|
||||
"sha256:012ca77c2105600e3c6aef43188101ac1d95052c633a4ae8fbebffab20c25f8a",
|
||||
"sha256:05b4d865710f9a6378d3ada28195ff78e52642d3ecffe6fa9d379d870b9bf29d",
|
||||
"sha256:07daddb98f98f771ba027f8f835bdb675aeb84effe41ed5221f520b267429354",
|
||||
"sha256:09bf05a489fe10f9280a5e0163f195e7b9630cafb15f7d72fb9c8f5eb2afa84f",
|
||||
"sha256:0a8d5f2dbb4bbe830ace54286b829bfa529f0853bedaab6225fcb2e6d1f7e356",
|
||||
"sha256:1259b8ca49662b8a941177357f08147d858595c0042e63ff81e9628e925b5c9d",
|
||||
"sha256:238d8b6dd27bd1a04816a68aa90a739e6dd23b192fcd83b50f9360958bff192a",
|
||||
"sha256:2a57daef18a2022a5e4b6f7376c9ddd0c2d946e4b1f1e59b837f5bf295be7380",
|
||||
"sha256:39e5ca2f66d1eac7abcba5ce1a03370d123dc6085620f1cd532dfee27e650178",
|
||||
"sha256:3d516df693c195b8da3795e381429bd420e87081b7e6c2871c62c9897c812cda",
|
||||
"sha256:3e486c5b7228e864665fc479e9f596b2547b5fe29c6f5c8ed3807784d06faed7",
|
||||
"sha256:5029c46b0d41dfb763c3981c0af68eab029f06fe2b94f2299112fc18cf9e8d6d",
|
||||
"sha256:5817c0b3c263025d851da96b90cbc7e95348008f88b990e90d10683dba376666",
|
||||
"sha256:79320f1fc5c9ca682869087c565bb29ca6f334692e940d7365771e9a94382e12",
|
||||
"sha256:887d08beca6368d3d70dc75126607ad76317a9fd07fe61323d8c3cb42add12b6",
|
||||
"sha256:9163fec630495c10c767991e3f8dab32f4427bfb2dfeaa59bb28fe3e52ba66f2",
|
||||
"sha256:95d324e603c5cec5d89e8595236bbf59ade5fe3a72d100ce61eebb323d598750",
|
||||
"sha256:9927aa8a8cb4af681279b6f28a1dcb14e0eb556c1aea8413a1e27608a8516e0c",
|
||||
"sha256:9948c2d5c5c0ee45ed44cee0e2eba2ce60a03be006ed3074521f3da3be162e72",
|
||||
"sha256:a719bd708207fa219fcbf4c8ebbcbc52846045f78179d00445b429fdabdbc1c4",
|
||||
"sha256:bc22ced26ebc46546798fa0141f4418f1db116dec517f0aeaecec87cf7b2416c",
|
||||
"sha256:c41b7e10b72cef00cd63410f31fe50e72dc3a40eafbd146e288384fbe4208064",
|
||||
"sha256:cdb0ad83a5d6bac986a37fcb7562bcbef0aabae8ea19505bab5cf83c4d18af12",
|
||||
"sha256:d8e480f65ac7105cbc288eec2417dc61eaac6ed6e75595aa15b8c7c77c53a68b",
|
||||
"sha256:da2d581da279bc7408d38e16ff77754f5448c4352f2acfe530a5d14d8fc6934a",
|
||||
"sha256:de61091dd68326b600422cf731eb4810c4c6363f18a65bccd6061784b7454f5b",
|
||||
"sha256:ec7d39589f9cfc2a8b83b1d2fc673441757c99d43283e97b2dd46e0e23730db8",
|
||||
"sha256:f3204006869ab037604b1d9f045c4e84882ddd365e4ee8caa5eb1ff47a59188e",
|
||||
"sha256:f4d2174e168d0eabd1fffaf88b4f62c2b6f30a67b8816f31024b8e48be3e2d75",
|
||||
"sha256:fcff8c9d88d58880f7eda2139c7c444552a38f98a9e77ba5970b6e78f54ac358"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.9.4"
|
||||
"version": "==3.9.6"
|
||||
},
|
||||
"pycryptodomex": {
|
||||
"hashes": [
|
||||
@ -714,10 +720,10 @@
|
||||
},
|
||||
"ruamel.yaml": {
|
||||
"hashes": [
|
||||
"sha256:ee3264b83c3309b4ae7978afa185da6a1d278e3abc9fb942f1a0b57c622092f8",
|
||||
"sha256:fd16843ff0ba45fa5e1ea9ea7038428b4a46f2c39deea9aa67f9eaa34823dc11"
|
||||
"sha256:0962fd7999e064c4865f96fb1e23079075f4a2a14849bcdc5cdba53a24f9759b",
|
||||
"sha256:099c644a778bf72ffa00524f78dd0b6476bca94a1da344130f4bf3381ce5b954"
|
||||
],
|
||||
"version": "==0.16.9"
|
||||
"version": "==0.16.10"
|
||||
},
|
||||
"ruamel.yaml.clib": {
|
||||
"hashes": [
|
||||
@ -753,11 +759,11 @@
|
||||
},
|
||||
"sentry-sdk": {
|
||||
"hashes": [
|
||||
"sha256:8e2d38dc58dc992280487e553ec3d97a424e4d179f4fad802ef3b08f64ccf4d8",
|
||||
"sha256:9b59e155229ea7d46a52b5c025d8c3c6d591e9dd9bb5f5f47310b2bb430038a8"
|
||||
"sha256:b06dd27391fd11fb32f84fe054e6a64736c469514a718a99fb5ce1dff95d6b28",
|
||||
"sha256:e023da07cfbead3868e1e2ba994160517885a32dfd994fc455b118e37989479b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.14.0"
|
||||
"version": "==0.14.1"
|
||||
},
|
||||
"service-identity": {
|
||||
"hashes": [
|
||||
@ -791,11 +797,11 @@
|
||||
},
|
||||
"structlog": {
|
||||
"hashes": [
|
||||
"sha256:4287058cf4ce1a59bc5dea290d6386d37f29a37529c9a51cdf7387e51710152b",
|
||||
"sha256:6640e6690fc31d5949bc614c1a630464d3aaa625284aeb7c6e486c3010d73e12"
|
||||
"sha256:7a48375db6274ed1d0ae6123c486472aa1d0890b08d314d2b016f3aa7f35990b",
|
||||
"sha256:8a672be150547a93d90a7d74229a29e765be05bd156a35cdcc527ebf68e9af92"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==19.2.0"
|
||||
"version": "==20.1.0"
|
||||
},
|
||||
"swagger-spec-validator": {
|
||||
"hashes": [
|
||||
@ -817,12 +823,12 @@
|
||||
"secure"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293",
|
||||
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745"
|
||||
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
|
||||
"sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
|
||||
],
|
||||
"index": "pypi",
|
||||
"markers": null,
|
||||
"version": "==1.25.7"
|
||||
"version": "==1.25.8"
|
||||
},
|
||||
"vine": {
|
||||
"hashes": [
|
||||
@ -863,10 +869,10 @@
|
||||
},
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee"
|
||||
"sha256:0f592a0447acea0c2b0a9602be1e4e3d86db52badd2e3c84f0193bfd89fd3a43"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.4"
|
||||
"version": "==1.5"
|
||||
},
|
||||
"bandit": {
|
||||
"hashes": [
|
||||
@ -946,40 +952,33 @@
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a",
|
||||
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038"
|
||||
"sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283",
|
||||
"sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.2.10"
|
||||
"version": "==3.0.3"
|
||||
},
|
||||
"django-debug-toolbar": {
|
||||
"hashes": [
|
||||
"sha256:24c157bc6c0e1648e0a6587511ecb1b007a00a354ce716950bff2de12693e7a8",
|
||||
"sha256:77cfba1d6e91b9bc3d36dc7dc74a9bb80be351948db5f880f2562a0cbf20b6c5"
|
||||
"sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943",
|
||||
"sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.1"
|
||||
},
|
||||
"dodgy": {
|
||||
"hashes": [
|
||||
"sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a",
|
||||
"sha256:51f54c0fd886fa3854387f354b19f429d38c04f984f38bc572558b703c0542a6"
|
||||
],
|
||||
"version": "==0.2.1"
|
||||
"version": "==2.2"
|
||||
},
|
||||
"gitdb2": {
|
||||
"hashes": [
|
||||
"sha256:1b6df1433567a51a4a9c1a5a0de977aa351a405cc56d7d35f3388bad1f630350",
|
||||
"sha256:96bbb507d765a7f51eb802554a9cfe194a174582f772e0d89f4e87288c288b7b"
|
||||
"sha256:0375d983fd887d03c8942e81b1b0abc6c320cfb500cd3fe0d9c0eac87fbf2b52",
|
||||
"sha256:b2b3a67090c17dc61f8407ca485e79ae811225ab5ebcd98ac5ee01448e8987b5"
|
||||
],
|
||||
"version": "==2.0.6"
|
||||
"version": "==3.0.2"
|
||||
},
|
||||
"gitpython": {
|
||||
"hashes": [
|
||||
"sha256:99c77677f31f255e130f3fed4c8e0eebb35f1a09df98ff965fff6774f71688cf",
|
||||
"sha256:99cd0403cecd8a13b95d2e045b9fcaa7837137fcc5ec3105f2c413305d82c143"
|
||||
"sha256:620b3c729bbc143b498cfea77e302999deedc55faec5b1067086c9ef90e101bc",
|
||||
"sha256:a43a5d88a5bbc3cf32bb5223e4b4e68fd716db5e9996cad6e561bbfee6e5f4af"
|
||||
],
|
||||
"version": "==3.0.7"
|
||||
"version": "==3.0.8"
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
@ -1035,40 +1034,12 @@
|
||||
],
|
||||
"version": "==5.4.4"
|
||||
},
|
||||
"pep8-naming": {
|
||||
"hashes": [
|
||||
"sha256:1b419fa45b68b61cd8c5daf4e0c96d28915ad14d3d5f35fcc1e7e95324a33a2e",
|
||||
"sha256:4eedfd4c4b05e48796f74f5d8628c068ff788b9c2b08471ad408007fc6450e5a"
|
||||
],
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"prospector": {
|
||||
"hashes": [
|
||||
"sha256:ea910794b53cfefcb5dfb6b4eb0323e42d1a88132e165b85b016cc7f0b6ae635"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
|
||||
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
|
||||
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||
],
|
||||
"version": "==2.4.0"
|
||||
},
|
||||
"pydocstyle": {
|
||||
"hashes": [
|
||||
"sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586",
|
||||
"sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"
|
||||
],
|
||||
"version": "==5.0.2"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pylint": {
|
||||
"hashes": [
|
||||
@ -1078,25 +1049,13 @@
|
||||
"index": "pypi",
|
||||
"version": "==2.4.4"
|
||||
},
|
||||
"pylint-celery": {
|
||||
"hashes": [
|
||||
"sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"pylint-django": {
|
||||
"hashes": [
|
||||
"sha256:9bdb0e022b19881218a25ffb8ad05e83b83bc5cdbc58e5ee8ffbe99965193f6c",
|
||||
"sha256:9eea6a026eaa5ecfad5fed7a33faf77ef55a43cc78afbcaf2f6ddd071156b3f8"
|
||||
"sha256:440beb814464928aedd2e21196bb6e47a83b63e2cbe886a701ba0f4a64206bbb",
|
||||
"sha256:d5d113605a64cf0e638b707d4cb42106e626f8851bc30a44d5b22bd698ad8483"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.12"
|
||||
},
|
||||
"pylint-flask": {
|
||||
"hashes": [
|
||||
"sha256:f4d97de2216bf7bfce07c9c08b166e978fe9f2725de2a50a9845a97de7e31517"
|
||||
],
|
||||
"version": "==0.6"
|
||||
"version": "==2.0.13"
|
||||
},
|
||||
"pylint-plugin-utils": {
|
||||
"hashes": [
|
||||
@ -1155,18 +1114,6 @@
|
||||
],
|
||||
"version": "==2020.1.8"
|
||||
},
|
||||
"requirements-detector": {
|
||||
"hashes": [
|
||||
"sha256:9fbc4b24e8b7c3663aff32e3eba34596848c6b91bd425079b386973bd8d08931"
|
||||
],
|
||||
"version": "==0.6"
|
||||
},
|
||||
"setoptconf": {
|
||||
"hashes": [
|
||||
"sha256:5b0b5d8e0077713f5d5152d4f63be6f048d9a1bb66be15d089a11c898c3cf49c"
|
||||
],
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
|
||||
@ -1181,13 +1128,6 @@
|
||||
],
|
||||
"version": "==2.0.5"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
|
||||
"sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"sqlparse": {
|
||||
"hashes": [
|
||||
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
|
||||
@ -1237,11 +1177,11 @@
|
||||
},
|
||||
"unittest-xml-reporting": {
|
||||
"hashes": [
|
||||
"sha256:358bbdaf24a26d904cc1c26ef3078bca7fc81541e0a54c8961693cc96a6f35e0",
|
||||
"sha256:9d28ddf6524cf0ff9293f61bd12e792de298f8561a5c945acea63fb437789e0e"
|
||||
"sha256:6584562cde8226fc79fa29e38903c669a02799074a563bb0b70fcd3a8e87829c",
|
||||
"sha256:dd8046a64dc62f3d30301523a54992e0be75a945194491e0a3b718130cb429e0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.5.2"
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"wrapt": {
|
||||
"hashes": [
|
||||
|
||||
@ -7,4 +7,4 @@ threads = 2
|
||||
enable-threads = true
|
||||
uid = passbook
|
||||
gid = passbook
|
||||
disable-logging=True
|
||||
disable-logging = True
|
||||
|
||||
20
docs/reference/property-mappings/user-object.md
Normal file
20
docs/reference/property-mappings/user-object.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Passbook User Object
|
||||
|
||||
The User object has the following attributes:
|
||||
|
||||
- `username`: User's Username
|
||||
- `email` User's E-Mail
|
||||
- `name` User's Display Name
|
||||
- `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
|
||||
|
||||
```jinja2
|
||||
[{% for group in user.groups.all() %}'{{ group.name }}',{% endfor %}]
|
||||
```
|
||||
@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
appVersion: "0.7.13-beta"
|
||||
appVersion: "0.7.16-beta"
|
||||
description: A Helm chart for passbook.
|
||||
name: passbook
|
||||
version: "0.7.13-beta"
|
||||
version: "0.7.16-beta"
|
||||
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
image:
|
||||
tag: 0.7.13-beta
|
||||
tag: 0.7.16-beta
|
||||
|
||||
nameOverride: ""
|
||||
|
||||
|
||||
@ -19,6 +19,9 @@ nav:
|
||||
- Rancher: integrations/services/rancher/index.md
|
||||
- Harbor: integrations/services/harbor/index.md
|
||||
- Sentry: integrations/services/sentry/index.md
|
||||
- Reference:
|
||||
- Property Mappings:
|
||||
- User Object: reference/property-mappings/user-object.md
|
||||
|
||||
repo_name: "BeryJu.org/passbook"
|
||||
repo_url: https://github.com/BeryJu/passbook
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
"""passbook"""
|
||||
__version__ = "0.7.13-beta"
|
||||
__version__ = "0.7.16-beta"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{% extends "generic/form.html" %}
|
||||
{% extends base_template|default:"generic/form.html" %}
|
||||
|
||||
{% load utils %}
|
||||
{% load i18n %}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
<link rel="stylesheet" href="{% static 'codemirror/lib/codemirror.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'codemirror/theme/monokai.css' %}">
|
||||
<script src="{% static 'codemirror/mode/yaml/yaml.js' %}"></script>
|
||||
<script src="{% static 'codemirror/mode/jinja2/jinja2.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -29,21 +30,33 @@
|
||||
<div class="">
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% include 'partials/form.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<a class="btn btn-default" href="{% back %}">{% trans "Cancel" %}</a>
|
||||
<input type="submit" class="btn btn-primary" value="{% block action %}{% endblock %}" />
|
||||
</form>
|
||||
</div>
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<script>
|
||||
let attributes = document.getElementsByName('attributes');
|
||||
const attributes = document.getElementsByName('attributes');
|
||||
if (attributes.length > 0) {
|
||||
let myCodeMirror = CodeMirror.fromTextArea(attributes[0], {
|
||||
// https://github.com/codemirror/CodeMirror/issues/5092
|
||||
attributes[0].removeAttribute("required");
|
||||
const attributesCM = CodeMirror.fromTextArea(attributes[0], {
|
||||
mode: 'yaml',
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
});
|
||||
}
|
||||
const expressions = document.getElementsByName('expression');
|
||||
if (expressions.length > 0) {
|
||||
// https://github.com/codemirror/CodeMirror/issues/5092
|
||||
expressions[0].removeAttribute("required");
|
||||
const expressionCM = CodeMirror.fromTextArea(expressions[0], {
|
||||
mode: 'jinja2',
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{% extends "generic/form.html" %}
|
||||
{% extends base_template|default:"generic/form.html" %}
|
||||
|
||||
{% load utils %}
|
||||
{% load i18n %}
|
||||
|
||||
@ -66,6 +66,9 @@ class PropertyMappingCreateView(
|
||||
if x.__name__ == property_mapping_type
|
||||
)
|
||||
kwargs["type"] = model._meta.verbose_name
|
||||
form_cls = self.get_form_class()
|
||||
if hasattr(form_cls, "template_name"):
|
||||
kwargs["base_template"] = form_cls.template_name
|
||||
return kwargs
|
||||
|
||||
def get_form_class(self):
|
||||
@ -92,6 +95,13 @@ class PropertyMappingUpdateView(
|
||||
success_url = reverse_lazy("passbook_admin:property-mappings")
|
||||
success_message = _("Successfully updated Property Mapping")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
kwargs = super().get_context_data(**kwargs)
|
||||
form_cls = self.get_form_class()
|
||||
if hasattr(form_cls, "template_name"):
|
||||
kwargs["base_template"] = form_cls.template_name
|
||||
return kwargs
|
||||
|
||||
def get_form_class(self):
|
||||
form_class_path = self.get_object().form
|
||||
form_class = path_to_class(form_class_path)
|
||||
|
||||
19
passbook/core/migrations/0006_propertymapping_template.py
Normal file
19
passbook/core/migrations/0006_propertymapping_template.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 16:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_core", "0005_merge_20191025_2022"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="propertymapping",
|
||||
name="template",
|
||||
field=models.TextField(default=""),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
16
passbook/core/migrations/0007_auto_20200217_1934.py
Normal file
16
passbook/core/migrations/0007_auto_20200217_1934.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 19:34
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_core", "0006_propertymapping_template"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="propertymapping", old_name="template", new_name="expression",
|
||||
),
|
||||
]
|
||||
@ -2,15 +2,17 @@
|
||||
from datetime import timedelta
|
||||
from random import SystemRandom
|
||||
from time import sleep
|
||||
from typing import Optional
|
||||
from typing import Optional, Any
|
||||
from uuid import uuid4
|
||||
|
||||
from jinja2.nativetypes import NativeEnvironment
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from django.db import models
|
||||
from django.urls import reverse_lazy
|
||||
from django.http import HttpRequest
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_prometheus.models import ExportModelOperationsMixin
|
||||
from guardian.mixins import GuardianUserMixin
|
||||
from model_utils.managers import InheritanceManager
|
||||
@ -22,6 +24,7 @@ from passbook.policies.exceptions import PolicyException
|
||||
from passbook.policies.struct import PolicyRequest, PolicyResult
|
||||
|
||||
LOGGER = get_logger()
|
||||
NATIVE_ENVIRONMENT = NativeEnvironment()
|
||||
|
||||
|
||||
def default_nonce_duration():
|
||||
@ -293,10 +296,16 @@ class PropertyMapping(UUIDModel):
|
||||
"""User-defined key -> x mapping which can be used by providers to expose extra data."""
|
||||
|
||||
name = models.TextField()
|
||||
expression = models.TextField()
|
||||
|
||||
form = ""
|
||||
objects = InheritanceManager()
|
||||
|
||||
def evaluate(self, user: User, request: HttpRequest, **kwargs) -> Any:
|
||||
"""Evaluate `self.expression` using `**kwargs` as Context."""
|
||||
expression = NATIVE_ENVIRONMENT.from_string(self.expression)
|
||||
return expression.render(user=user, request=request, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return f"Property Mapping {self.name}"
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@ from urllib.parse import urlparse
|
||||
|
||||
import yaml
|
||||
from django.conf import ImproperlyConfigured
|
||||
from django.utils.autoreload import autoreload_started
|
||||
from structlog import get_logger
|
||||
|
||||
SEARCH_PATHS = ["passbook/lib/default.yml", "/etc/passbook/config.yml", "",] + glob(
|
||||
@ -142,12 +141,3 @@ class ConfigLoader:
|
||||
|
||||
|
||||
CONFIG = ConfigLoader()
|
||||
|
||||
|
||||
def signal_handler(sender, **_):
|
||||
"""Add all loaded config files to autoreload watcher"""
|
||||
for path in CONFIG.loaded_file:
|
||||
sender.watch_file(path)
|
||||
|
||||
|
||||
autoreload_started.connect(signal_handler)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
"""passbook policy engine"""
|
||||
from multiprocessing import Pipe
|
||||
from multiprocessing import Pipe, set_start_method
|
||||
from multiprocessing.connection import Connection
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
@ -12,6 +12,9 @@ from passbook.policies.process import PolicyProcess, cache_key
|
||||
from passbook.policies.struct import PolicyRequest, PolicyResult
|
||||
|
||||
LOGGER = get_logger()
|
||||
# This is only really needed for macOS, because Python 3.8 changed the default to spawn
|
||||
# spawn causes issues with objects that aren't picklable, and also the django setup
|
||||
set_start_method("fork")
|
||||
|
||||
|
||||
class PolicyProcessInfo:
|
||||
@ -36,13 +39,15 @@ class PolicyEngine:
|
||||
policies: List[Policy] = []
|
||||
request: PolicyRequest
|
||||
|
||||
__processes: List[PolicyProcessInfo] = []
|
||||
__cached_policies: List[PolicyResult]
|
||||
__processes: List[PolicyProcessInfo]
|
||||
|
||||
def __init__(self, policies, user: User, request: HttpRequest = None):
|
||||
self.policies = policies
|
||||
self.request = PolicyRequest(user)
|
||||
if request:
|
||||
self.request.http_request = request
|
||||
self.__cached_policies = []
|
||||
self.__processes = []
|
||||
|
||||
def _select_subclasses(self) -> List[Policy]:
|
||||
@ -55,13 +60,12 @@ class PolicyEngine:
|
||||
|
||||
def build(self) -> "PolicyEngine":
|
||||
"""Build task group"""
|
||||
cached_policies = []
|
||||
for policy in self._select_subclasses():
|
||||
cached_policy = cache.get(cache_key(policy, self.request.user), None)
|
||||
if cached_policy and self.use_cache:
|
||||
LOGGER.debug("Taking result from cache", policy=policy)
|
||||
cached_policies.append(cached_policy)
|
||||
else:
|
||||
self.__cached_policies.append(cached_policy)
|
||||
continue
|
||||
LOGGER.debug("Evaluating policy", policy=policy)
|
||||
our_end, task_end = Pipe(False)
|
||||
task = PolicyProcess(policy, self.request, task_end)
|
||||
@ -82,13 +86,14 @@ class PolicyEngine:
|
||||
def result(self) -> Tuple[bool, List[str]]:
|
||||
"""Get policy-checking result"""
|
||||
messages: List[str] = []
|
||||
for proc_info in self.__processes:
|
||||
LOGGER.debug(
|
||||
"Result", policy=proc_info.policy, passing=proc_info.result.passing
|
||||
)
|
||||
if proc_info.result.messages:
|
||||
messages += proc_info.result.messages
|
||||
if not proc_info.result.passing:
|
||||
process_results: List[PolicyResult] = [
|
||||
x.result for x in self.__processes if x.result
|
||||
]
|
||||
for result in process_results + self.__cached_policies:
|
||||
LOGGER.debug("result", passing=result.passing)
|
||||
if result.messages:
|
||||
messages += result.messages
|
||||
if not result.passing:
|
||||
return False, messages
|
||||
return True, messages
|
||||
|
||||
|
||||
@ -14,12 +14,16 @@ class SAMLProviderSerializer(ModelSerializer):
|
||||
fields = [
|
||||
"pk",
|
||||
"name",
|
||||
"property_mappings",
|
||||
"processor_path",
|
||||
"acs_url",
|
||||
"audience",
|
||||
"processor_path",
|
||||
"issuer",
|
||||
"assertion_valid_for",
|
||||
"assertion_valid_not_before",
|
||||
"assertion_valid_not_on_or_after",
|
||||
"session_valid_not_on_or_after",
|
||||
"property_mappings",
|
||||
"digest_algorithm",
|
||||
"signature_algorithm",
|
||||
"signing",
|
||||
"signing_cert",
|
||||
"signing_key",
|
||||
@ -39,7 +43,7 @@ class SAMLPropertyMappingSerializer(ModelSerializer):
|
||||
class Meta:
|
||||
|
||||
model = SAMLPropertyMapping
|
||||
fields = ["pk", "name", "saml_name", "friendly_name", "values"]
|
||||
fields = ["pk", "name", "saml_name", "friendly_name", "expression"]
|
||||
|
||||
|
||||
class SAMLPropertyMappingViewSet(ModelViewSet):
|
||||
|
||||
@ -4,7 +4,6 @@ from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from passbook.lib.fields import DynamicArrayField
|
||||
from passbook.providers.saml.models import (
|
||||
SAMLPropertyMapping,
|
||||
SAMLProvider,
|
||||
@ -40,14 +39,12 @@ class SAMLProviderForm(forms.ModelForm):
|
||||
"assertion_valid_not_on_or_after",
|
||||
"session_valid_not_on_or_after",
|
||||
"property_mappings",
|
||||
"digest_algorithm",
|
||||
"signature_algorithm",
|
||||
"signing",
|
||||
"signing_cert",
|
||||
"signing_key",
|
||||
]
|
||||
labels = {
|
||||
"acs_url": "ACS URL",
|
||||
"signing_cert": "Singing Certificate",
|
||||
}
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"audience": forms.TextInput(),
|
||||
@ -62,16 +59,14 @@ class SAMLProviderForm(forms.ModelForm):
|
||||
class SAMLPropertyMappingForm(forms.ModelForm):
|
||||
"""SAML Property Mapping form"""
|
||||
|
||||
template_name = "saml/idp/property_mapping_form.html"
|
||||
|
||||
class Meta:
|
||||
|
||||
model = SAMLPropertyMapping
|
||||
fields = ["name", "saml_name", "friendly_name", "values"]
|
||||
fields = ["name", "saml_name", "friendly_name", "expression"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"saml_name": forms.TextInput(),
|
||||
"friendly_name": forms.TextInput(),
|
||||
}
|
||||
field_classes = {"values": DynamicArrayField}
|
||||
help_texts = {
|
||||
"values": 'String substitution uses a syntax like "{variable} test}".'
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
# Generated by Django 2.2.9 on 2020-02-16 11:09
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_providers_saml", "0002_auto_20200214_1354"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="samlpropertymapping",
|
||||
name="saml_name",
|
||||
field=models.TextField(verbose_name="SAML Name"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlpropertymapping",
|
||||
name="values",
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=models.TextField(),
|
||||
help_text="This string can contain string substitutions delimited by {}. The following Variables are available: user, request",
|
||||
size=None,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlprovider",
|
||||
name="acs_url",
|
||||
field=models.URLField(verbose_name="ACS URL"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlprovider",
|
||||
name="signing_cert",
|
||||
field=models.TextField(verbose_name="Singing Certificate"),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,41 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 15:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_providers_saml", "0003_auto_20200216_1109"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="samlprovider",
|
||||
name="digest_algorithm",
|
||||
field=models.CharField(
|
||||
choices=[("sha1", "SHA1"), ("sha256", "SHA256")],
|
||||
default="sha256",
|
||||
max_length=50,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="samlprovider",
|
||||
name="signature_algorithm",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("rsa-sha1", "RSA-SHA1"),
|
||||
("rsa-sha256", "RSA-SHA256"),
|
||||
("ecdsa-sha256", "ECDSA-SHA256"),
|
||||
("dsa-sha1", "DSA-SHA1"),
|
||||
],
|
||||
default="rsa-sha256",
|
||||
max_length=50,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlprovider",
|
||||
name="processor_path",
|
||||
field=models.CharField(choices=[], max_length=255),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,76 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 16:15
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def cleanup_old_autogenerated(apps, schema_editor):
|
||||
SAMLPropertyMapping = apps.get_model(
|
||||
"passbook_providers_saml", "SAMLPropertyMapping"
|
||||
)
|
||||
db_alias = schema_editor.connection.alias
|
||||
SAMLPropertyMapping.objects.using(db_alias).filter(
|
||||
name__startswith="Autogenerated"
|
||||
).delete()
|
||||
|
||||
|
||||
def create_default_property_mappings(apps, schema_editor):
|
||||
"""Create default SAML Property Mappings"""
|
||||
SAMLPropertyMapping = apps.get_model(
|
||||
"passbook_providers_saml", "SAMLPropertyMapping"
|
||||
)
|
||||
db_alias = schema_editor.connection.alias
|
||||
defaults = [
|
||||
{
|
||||
"FriendlyName": "eduPersonPrincipalName",
|
||||
"Name": "urn:oid:1.3.6.1.4.1.5923.1.1.1.6",
|
||||
"Expression": "{{ user.email }}",
|
||||
},
|
||||
{
|
||||
"FriendlyName": "cn",
|
||||
"Name": "urn:oid:2.5.4.3",
|
||||
"Expression": "{{ user.name }}",
|
||||
},
|
||||
{
|
||||
"FriendlyName": "mail",
|
||||
"Name": "urn:oid:0.9.2342.19200300.100.1.3",
|
||||
"Expression": "{{ user.email }}",
|
||||
},
|
||||
{
|
||||
"FriendlyName": "displayName",
|
||||
"Name": "urn:oid:2.16.840.1.113730.3.1.241",
|
||||
"Expression": "{{ user.username }}",
|
||||
},
|
||||
{
|
||||
"FriendlyName": "uid",
|
||||
"Name": "urn:oid:0.9.2342.19200300.100.1.1",
|
||||
"Expression": "{{ user.pk }}",
|
||||
},
|
||||
{
|
||||
"FriendlyName": "member-of",
|
||||
"Name": "member-of",
|
||||
"Expression": "[{% for group in user.groups.all() %}'{{ group.name }}',{% endfor %}]",
|
||||
},
|
||||
]
|
||||
for default in defaults:
|
||||
SAMLPropertyMapping.objects.using(db_alias).get_or_create(
|
||||
saml_name=default["Name"],
|
||||
friendly_name=default["FriendlyName"],
|
||||
expression=default["Expression"],
|
||||
defaults={
|
||||
"name": f"Autogenerated SAML Mapping: {default['FriendlyName']} -> {default['Expression']}"
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_providers_saml", "0004_auto_20200217_1526"),
|
||||
("passbook_core", "0007_auto_20200217_1934"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(cleanup_old_autogenerated),
|
||||
migrations.RemoveField(model_name="samlpropertymapping", name="values",),
|
||||
migrations.RunPython(create_default_property_mappings),
|
||||
]
|
||||
@ -1,8 +1,7 @@
|
||||
"""passbook saml_idp Models"""
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.shortcuts import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from structlog import get_logger
|
||||
|
||||
from passbook.core.models import PropertyMapping, Provider
|
||||
@ -19,7 +18,7 @@ class SAMLProvider(Provider):
|
||||
name = models.TextField()
|
||||
processor_path = models.CharField(max_length=255, choices=[])
|
||||
|
||||
acs_url = models.URLField()
|
||||
acs_url = models.URLField(verbose_name=_("ACS URL"))
|
||||
audience = models.TextField(default="")
|
||||
issuer = models.TextField()
|
||||
|
||||
@ -55,8 +54,24 @@ class SAMLProvider(Provider):
|
||||
),
|
||||
)
|
||||
|
||||
digest_algorithm = models.CharField(
|
||||
max_length=50,
|
||||
choices=(("sha1", _("SHA1")), ("sha256", _("SHA256")),),
|
||||
default="sha256",
|
||||
)
|
||||
signature_algorithm = models.CharField(
|
||||
max_length=50,
|
||||
choices=(
|
||||
("rsa-sha1", _("RSA-SHA1")),
|
||||
("rsa-sha256", _("RSA-SHA256")),
|
||||
("ecdsa-sha256", _("ECDSA-SHA256")),
|
||||
("dsa-sha1", _("DSA-SHA1")),
|
||||
),
|
||||
default="rsa-sha256",
|
||||
)
|
||||
|
||||
signing = models.BooleanField(default=True)
|
||||
signing_cert = models.TextField()
|
||||
signing_cert = models.TextField(verbose_name=_("Singing Certificate"))
|
||||
signing_key = models.TextField()
|
||||
|
||||
form = "passbook.providers.saml.forms.SAMLProviderForm"
|
||||
@ -100,9 +115,8 @@ class SAMLProvider(Provider):
|
||||
class SAMLPropertyMapping(PropertyMapping):
|
||||
"""SAML Property mapping, allowing Name/FriendlyName mapping to a list of strings"""
|
||||
|
||||
saml_name = models.TextField()
|
||||
saml_name = models.TextField(verbose_name="SAML Name")
|
||||
friendly_name = models.TextField(default=None, blank=True, null=True)
|
||||
values = ArrayField(models.TextField())
|
||||
|
||||
form = "passbook.providers.saml.forms.SAMLPropertyMappingForm"
|
||||
|
||||
|
||||
@ -33,7 +33,6 @@ class Processor:
|
||||
|
||||
_assertion_params: Dict[str, Union[str, List[Dict[str, str]]]]
|
||||
_request_params: Dict[str, str]
|
||||
_system_params: Dict[str, str]
|
||||
_response_params: Dict[str, str]
|
||||
|
||||
@property
|
||||
@ -45,9 +44,6 @@ class Processor:
|
||||
self.name = remote.name
|
||||
self._remote = remote
|
||||
self._logger = get_logger()
|
||||
self._system_params = {
|
||||
"ISSUER": self._remote.issuer,
|
||||
}
|
||||
|
||||
def _build_assertion(self):
|
||||
"""Builds _assertion_params."""
|
||||
@ -70,8 +66,8 @@ class Processor:
|
||||
"SP_NAME_QUALIFIER": self._remote.audience,
|
||||
"SUBJECT": self._http_request.user.email,
|
||||
"SUBJECT_FORMAT": self.subject_format,
|
||||
"ISSUER": self._remote.issuer,
|
||||
}
|
||||
self._assertion_params.update(self._system_params)
|
||||
self._assertion_params.update(self._request_params)
|
||||
|
||||
def _build_response(self):
|
||||
@ -81,8 +77,8 @@ class Processor:
|
||||
"ISSUE_INSTANT": get_time_string(),
|
||||
"RESPONSE_ID": get_random_id(),
|
||||
"RESPONSE_SIGNATURE": "", # initially unsigned
|
||||
"ISSUER": self._remote.issuer,
|
||||
}
|
||||
self._response_params.update(self._system_params)
|
||||
self._response_params.update(self._request_params)
|
||||
|
||||
def _encode_response(self):
|
||||
@ -97,49 +93,26 @@ class Processor:
|
||||
def _format_assertion(self):
|
||||
"""Formats _assertion_params as _assertion_xml."""
|
||||
# https://commons.lbl.gov/display/IDMgmt/Attribute+Definitions
|
||||
self._assertion_params["ATTRIBUTES"] = [
|
||||
{
|
||||
"FriendlyName": "eduPersonPrincipalName",
|
||||
"Name": "urn:oid:1.3.6.1.4.1.5923.1.1.1.6",
|
||||
"Value": self._http_request.user.email,
|
||||
},
|
||||
{
|
||||
"FriendlyName": "cn",
|
||||
"Name": "urn:oid:2.5.4.3",
|
||||
"Value": self._http_request.user.name,
|
||||
},
|
||||
{
|
||||
"FriendlyName": "mail",
|
||||
"Name": "urn:oid:0.9.2342.19200300.100.1.3",
|
||||
"Value": self._http_request.user.email,
|
||||
},
|
||||
{
|
||||
"FriendlyName": "displayName",
|
||||
"Name": "urn:oid:2.16.840.1.113730.3.1.241",
|
||||
"Value": self._http_request.user.username,
|
||||
},
|
||||
{
|
||||
"FriendlyName": "uid",
|
||||
"Name": "urn:oid:0.9.2342.19200300.100.1.1",
|
||||
"Value": self._http_request.user.pk,
|
||||
},
|
||||
]
|
||||
attributes = []
|
||||
from passbook.providers.saml.models import SAMLPropertyMapping
|
||||
|
||||
for mapping in self._remote.property_mappings.all().select_subclasses():
|
||||
if isinstance(mapping, SAMLPropertyMapping):
|
||||
value = mapping.evaluate(
|
||||
user=self._http_request.user,
|
||||
request=self._http_request,
|
||||
provider=self._remote,
|
||||
)
|
||||
mapping_payload = {
|
||||
"Name": mapping.saml_name,
|
||||
"ValueArray": [],
|
||||
"FriendlyName": mapping.friendly_name,
|
||||
}
|
||||
for value in mapping.values:
|
||||
mapping_payload["ValueArray"].append(
|
||||
value.format(
|
||||
user=self._http_request.user, request=self._http_request
|
||||
)
|
||||
)
|
||||
self._assertion_params["ATTRIBUTES"].append(mapping_payload)
|
||||
if isinstance(value, list):
|
||||
mapping_payload["ValueArray"] = value
|
||||
else:
|
||||
mapping_payload["Value"] = value
|
||||
attributes.append(mapping_payload)
|
||||
self._assertion_params["ATTRIBUTES"] = attributes
|
||||
self._assertion_xml = get_assertion_xml(
|
||||
"saml/xml/assertions/generic.xml", self._assertion_params, signed=True
|
||||
)
|
||||
@ -188,8 +161,9 @@ class Processor:
|
||||
request_acs_url = self._request_params["ACS_URL"]
|
||||
|
||||
if self._remote.acs_url != request_acs_url:
|
||||
msg = "couldn't find ACS url '{}' in SAML2IDP_REMOTES " "setting.".format(
|
||||
request_acs_url
|
||||
msg = (
|
||||
f"ACS URL of {request_acs_url} doesn't match Provider "
|
||||
f"ACS URL of {self._remote.acs_url}."
|
||||
)
|
||||
self._logger.info(msg)
|
||||
raise CannotHandleAssertion(msg)
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
{% extends "generic/form.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block beneath_form %}
|
||||
<div class="form-group ">
|
||||
<label class="col-sm-2 control-label" for="friendly_name-2">
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<p>
|
||||
Expression using <a href="https://jinja.palletsprojects.com/en/2.11.x/templates/">Jinja</a>. Following variables are available:
|
||||
<ul>
|
||||
<li><code>user</code>: Passbook User Object (<a href="https://beryju.github.io/passbook/reference/property-mappings/user-object/">Reference</a>)</li>
|
||||
<li><code>request</code>: Django HTTP Request Object (<a href="https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects">Reference</a>) </li>
|
||||
<li><code>provider</code>: Passbook SAML Provider Object (<a href="https://github.com/BeryJu/passbook/blob/master/passbook/providers/saml/models.py#L16">Reference</a>) </li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -6,7 +6,10 @@ import zlib
|
||||
def decode_base64_and_inflate(b64string):
|
||||
"""Base64 decode and ZLib decompress b64string"""
|
||||
decoded_data = base64.b64decode(b64string)
|
||||
try:
|
||||
return zlib.decompress(decoded_data, -15)
|
||||
except zlib.error:
|
||||
return decoded_data
|
||||
|
||||
|
||||
def deflate_and_base64_encode(string_val):
|
||||
|
||||
@ -88,10 +88,5 @@ def get_response_xml(parameters, saml_provider: SAMLProvider, assertion_id=""):
|
||||
signature_xml = get_signature_xml()
|
||||
params["RESPONSE_SIGNATURE"] = signature_xml
|
||||
|
||||
signed = sign_with_signxml(
|
||||
saml_provider.signing_key,
|
||||
raw_response,
|
||||
saml_provider.signing_cert,
|
||||
reference_uri=assertion_id,
|
||||
)
|
||||
signed = sign_with_signxml(raw_response, saml_provider, reference_uri=assertion_id,)
|
||||
return signed
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
"""Signing code goes here."""
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from lxml import etree # nosec
|
||||
@ -7,25 +9,34 @@ from structlog import get_logger
|
||||
|
||||
from passbook.lib.utils.template import render_to_string
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from passbook.providers.saml.models import SAMLProvider
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
|
||||
def sign_with_signxml(private_key, data, cert, reference_uri=None):
|
||||
def sign_with_signxml(data: str, provider: "SAMLProvider", reference_uri=None) -> str:
|
||||
"""Sign Data with signxml"""
|
||||
key = serialization.load_pem_private_key(
|
||||
str.encode("\n".join([x.strip() for x in private_key.split("\n")])),
|
||||
str.encode("\n".join([x.strip() for x in provider.signing_key.split("\n")])),
|
||||
password=None,
|
||||
backend=default_backend(),
|
||||
)
|
||||
# defused XML is not used here because it messes up XML namespaces
|
||||
# Data is trusted, so lxml is ok
|
||||
root = etree.fromstring(data) # nosec
|
||||
signer = XMLSigner(c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#")
|
||||
signed = signer.sign(root, key=key, cert=[cert], reference_uri=reference_uri)
|
||||
XMLVerifier().verify(signed, x509_cert=cert)
|
||||
signer = XMLSigner(
|
||||
c14n_algorithm="http://www.w3.org/2001/10/xml-exc-c14n#",
|
||||
signature_algorithm=provider.signature_algorithm,
|
||||
digest_algorithm=provider.digest_algorithm,
|
||||
)
|
||||
signed = signer.sign(
|
||||
root, key=key, cert=[provider.signing_cert], reference_uri=reference_uri
|
||||
)
|
||||
XMLVerifier().verify(signed, x509_cert=provider.signing_cert)
|
||||
return etree.tostring(signed).decode("utf-8") # nosec
|
||||
|
||||
|
||||
def get_signature_xml():
|
||||
def get_signature_xml() -> str:
|
||||
"""Returns XML Signature for subject."""
|
||||
return render_to_string("saml/xml/signature.xml", {})
|
||||
|
||||
@ -5,7 +5,7 @@ from django.contrib.auth import logout
|
||||
from django.contrib.auth.mixins import AccessMixin
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import URLValidator
|
||||
from django.http import HttpResponse, HttpResponseBadRequest, HttpRequest
|
||||
from django.http import HttpRequest, HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import get_object_or_404, redirect, render, reverse
|
||||
from django.utils.datastructures import MultiValueDictKeyError
|
||||
from django.utils.decorators import method_decorator
|
||||
@ -27,7 +27,7 @@ LOGGER = get_logger()
|
||||
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
|
||||
|
||||
|
||||
def _generate_response(request: HttpRequest, provider: SAMLProvider):
|
||||
def _generate_response(request: HttpRequest, provider: SAMLProvider) -> HttpResponse:
|
||||
"""Generate a SAML response using processor_instance and return it in the proper Django
|
||||
response."""
|
||||
try:
|
||||
@ -58,13 +58,16 @@ class AccessRequiredView(AccessMixin, View):
|
||||
|
||||
def _has_access(self) -> bool:
|
||||
"""Check if user has access to application"""
|
||||
LOGGER.debug(
|
||||
"_has_access", user=self.request.user, app=self.provider.application
|
||||
)
|
||||
policy_engine = PolicyEngine(
|
||||
self.provider.application.policies.all(), self.request.user, self.request
|
||||
)
|
||||
policy_engine.build()
|
||||
return policy_engine.passing
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||
if not request.user.is_authenticated:
|
||||
return self.handle_no_permission()
|
||||
if not self._has_access():
|
||||
@ -84,7 +87,7 @@ class LoginBeginView(AccessRequiredView):
|
||||
stores it in the session prior to enforcing login."""
|
||||
|
||||
@method_decorator(csrf_exempt)
|
||||
def dispatch(self, request, application):
|
||||
def dispatch(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
if request.method == "POST":
|
||||
source = request.POST
|
||||
else:
|
||||
@ -108,7 +111,9 @@ class LoginBeginView(AccessRequiredView):
|
||||
class RedirectToSPView(AccessRequiredView):
|
||||
"""Return autosubmit form"""
|
||||
|
||||
def get(self, request, acs_url, saml_response, relay_state):
|
||||
def get(
|
||||
self, request: HttpRequest, acs_url: str, saml_response: str, relay_state: str
|
||||
) -> HttpResponse:
|
||||
"""Return autosubmit form"""
|
||||
return render(
|
||||
request,
|
||||
@ -149,7 +154,7 @@ class LoginProcessView(AccessRequiredView):
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request, application: str) -> HttpResponse:
|
||||
def post(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
"""Handle post request, return back to ACS"""
|
||||
# User access gets checked in dispatch
|
||||
if request.POST.get("ACSUrl", None):
|
||||
@ -178,7 +183,7 @@ class LogoutView(CSRFExemptMixin, AccessRequiredView):
|
||||
though it's technically not SAML 2.0)."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def get(self, request, application):
|
||||
def get(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
"""Perform logout"""
|
||||
logout(request)
|
||||
|
||||
@ -199,7 +204,7 @@ class SLOLogout(CSRFExemptMixin, AccessRequiredView):
|
||||
logs out the user and returns a standard logged-out page."""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def post(self, request, application):
|
||||
def post(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
"""Perform logout"""
|
||||
request.session["SAMLRequest"] = request.POST["SAMLRequest"]
|
||||
# TODO: Parse SAML LogoutRequest from POST data, similar to login_process().
|
||||
@ -214,7 +219,7 @@ class SLOLogout(CSRFExemptMixin, AccessRequiredView):
|
||||
class DescriptorDownloadView(AccessRequiredView):
|
||||
"""Replies with the XML Metadata IDSSODescriptor."""
|
||||
|
||||
def get(self, request, application):
|
||||
def get(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
"""Replies with the XML Metadata IDSSODescriptor."""
|
||||
entity_id = self.provider.issuer
|
||||
slo_url = request.build_absolute_uri(
|
||||
@ -250,7 +255,7 @@ class InitiateLoginView(AccessRequiredView):
|
||||
"""IdP-initiated Login"""
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def get(self, request, application):
|
||||
def get(self, request: HttpRequest, application: str) -> HttpResponse:
|
||||
"""Initiates an IdP-initiated link to a simple SP resource/target URL."""
|
||||
self.provider.processor.init_deep_link(request, "")
|
||||
self.provider.processor.is_idp_initiated = True
|
||||
|
||||
@ -62,7 +62,8 @@ class WSGILogger:
|
||||
if environ.get("QUERY_STRING") != "":
|
||||
query_string = f"?{environ.get('QUERY_STRING')}"
|
||||
self.logger.info(
|
||||
f"{environ.get('PATH_INFO', '')}{query_string}",
|
||||
"request",
|
||||
path=f"{environ.get('PATH_INFO', '')}{query_string}",
|
||||
host=host,
|
||||
method=environ.get("REQUEST_METHOD", ""),
|
||||
protocol=environ.get("SERVER_PROTOCOL", ""),
|
||||
|
||||
@ -35,7 +35,7 @@ class LDAPPropertyMappingSerializer(ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = LDAPPropertyMapping
|
||||
fields = ["pk", "name", "ldap_property", "object_field"]
|
||||
fields = ["pk", "name", "expression", "object_field"]
|
||||
|
||||
|
||||
class LDAPSourceViewSet(ModelViewSet):
|
||||
|
||||
@ -6,7 +6,7 @@ import ldap3.core.exceptions
|
||||
from structlog import get_logger
|
||||
|
||||
from passbook.core.models import Group, User
|
||||
from passbook.sources.ldap.models import LDAPSource
|
||||
from passbook.sources.ldap.models import LDAPSource, LDAPPropertyMapping
|
||||
|
||||
LOGGER = get_logger()
|
||||
|
||||
@ -154,7 +154,10 @@ class Connector:
|
||||
) -> Dict[str, Dict[Any, Any]]:
|
||||
properties = {"attributes": {}}
|
||||
for mapping in self._source.property_mappings.all().select_subclasses():
|
||||
properties[mapping.object_field] = attributes.get(mapping.ldap_property, "")
|
||||
mapping: LDAPPropertyMapping
|
||||
properties[mapping.object_field] = mapping.evaluate(
|
||||
user=None, request=None, ldap=attributes
|
||||
)
|
||||
if self._source.object_uniqueness_field in attributes:
|
||||
properties["attributes"]["ldap_uniq"] = attributes.get(
|
||||
self._source.object_uniqueness_field
|
||||
|
||||
@ -45,23 +45,17 @@ class LDAPSourceForm(forms.ModelForm):
|
||||
"policies": FilteredSelectMultiple(_("policies"), False),
|
||||
"property_mappings": FilteredSelectMultiple(_("Property Mappings"), False),
|
||||
}
|
||||
labels = {
|
||||
"server_uri": _("Server URI"),
|
||||
"bind_cn": _("Bind CN"),
|
||||
"start_tls": _("Enable Start TLS"),
|
||||
"base_dn": _("Base DN"),
|
||||
"additional_user_dn": _("Addition User DN"),
|
||||
"additional_group_dn": _("Addition Group DN"),
|
||||
}
|
||||
|
||||
|
||||
class LDAPPropertyMappingForm(forms.ModelForm):
|
||||
"""LDAP Property Mapping form"""
|
||||
|
||||
template_name = "ldap/property_mapping_form.html"
|
||||
|
||||
class Meta:
|
||||
|
||||
model = LDAPPropertyMapping
|
||||
fields = ["name", "ldap_property", "object_field"]
|
||||
fields = ["name", "object_field", "expression"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"ldap_property": forms.TextInput(),
|
||||
|
||||
@ -13,8 +13,9 @@ def create_default_ad_property_mappings(apps: Apps, schema_editor):
|
||||
"sAMAccountName": "username",
|
||||
"mail": "email",
|
||||
}
|
||||
db_alias = schema_editor.connection.alias
|
||||
for ldap_property, object_field in mapping.items():
|
||||
LDAPPropertyMapping.objects.get_or_create(
|
||||
LDAPPropertyMapping.objects.using(db_alias).get_or_create(
|
||||
ldap_property=ldap_property,
|
||||
object_field=object_field,
|
||||
defaults={
|
||||
|
||||
60
passbook/sources/ldap/migrations/0006_auto_20200216_1116.py
Normal file
60
passbook/sources/ldap/migrations/0006_auto_20200216_1116.py
Normal file
@ -0,0 +1,60 @@
|
||||
# Generated by Django 2.2.9 on 2020-02-16 11:16
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_sources_ldap", "0005_auto_20191011_1059"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ldappropertymapping",
|
||||
name="ldap_property",
|
||||
field=models.TextField(verbose_name="LDAP Property"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="additional_group_dn",
|
||||
field=models.TextField(
|
||||
help_text="Prepended to Base DN for Group-queries.",
|
||||
verbose_name="Addition Group DN",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="additional_user_dn",
|
||||
field=models.TextField(
|
||||
help_text="Prepended to Base DN for User-queries.",
|
||||
verbose_name="Addition User DN",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="base_dn",
|
||||
field=models.TextField(verbose_name="Base DN"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="bind_cn",
|
||||
field=models.TextField(verbose_name="Bind CN"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="server_uri",
|
||||
field=models.TextField(
|
||||
validators=[
|
||||
django.core.validators.URLValidator(schemes=["ldap", "ldaps"])
|
||||
],
|
||||
verbose_name="Server URI",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ldapsource",
|
||||
name="start_tls",
|
||||
field=models.BooleanField(default=False, verbose_name="Enable Start TLS"),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,46 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 16:19
|
||||
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def cleanup_old_autogenerated(apps, schema_editor):
|
||||
LDAPPropertyMapping = apps.get_model("passbook_sources_ldap", "LDAPPropertyMapping")
|
||||
db_alias = schema_editor.connection.alias
|
||||
LDAPPropertyMapping.objects.using(db_alias).filter(
|
||||
name__startswith="Autogenerated"
|
||||
).delete()
|
||||
|
||||
|
||||
def create_default_ad_property_mappings(apps: Apps, schema_editor):
|
||||
LDAPPropertyMapping = apps.get_model("passbook_sources_ldap", "LDAPPropertyMapping")
|
||||
mapping = {
|
||||
"name": "{{ ldap.name }}",
|
||||
"first_name": "{{ ldap.givenName }}",
|
||||
"last_name": "{{ ldap.sn }}",
|
||||
"username": "{{ ldap.sAMAccountName }}",
|
||||
"email": "{{ ldap.mail }}",
|
||||
}
|
||||
db_alias = schema_editor.connection.alias
|
||||
for object_field, expression in mapping.items():
|
||||
LDAPPropertyMapping.objects.using(db_alias).get_or_create(
|
||||
expression=expression,
|
||||
object_field=object_field,
|
||||
defaults={
|
||||
"name": f"Autogenerated LDAP Mapping: {expression} -> {object_field}"
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_sources_ldap", "0006_auto_20200216_1116"),
|
||||
("passbook_core", "0007_auto_20200217_1934"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(cleanup_old_autogenerated),
|
||||
migrations.RemoveField(model_name="ldappropertymapping", name="ldap_property",),
|
||||
migrations.RunPython(create_default_ad_property_mappings),
|
||||
]
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
from django.core.validators import URLValidator
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.core.models import Group, PropertyMapping, Source
|
||||
|
||||
@ -10,17 +10,22 @@ from passbook.core.models import Group, PropertyMapping, Source
|
||||
class LDAPSource(Source):
|
||||
"""LDAP Authentication source"""
|
||||
|
||||
server_uri = models.TextField(validators=[URLValidator(schemes=["ldap", "ldaps"])])
|
||||
bind_cn = models.TextField()
|
||||
server_uri = models.TextField(
|
||||
validators=[URLValidator(schemes=["ldap", "ldaps"])],
|
||||
verbose_name=_("Server URI"),
|
||||
)
|
||||
bind_cn = models.TextField(verbose_name=_("Bind CN"))
|
||||
bind_password = models.TextField()
|
||||
start_tls = models.BooleanField(default=False)
|
||||
start_tls = models.BooleanField(default=False, verbose_name=_("Enable Start TLS"))
|
||||
|
||||
base_dn = models.TextField()
|
||||
base_dn = models.TextField(verbose_name=_("Base DN"))
|
||||
additional_user_dn = models.TextField(
|
||||
help_text=_("Prepended to Base DN for User-queries.")
|
||||
help_text=_("Prepended to Base DN for User-queries."),
|
||||
verbose_name=_("Addition User DN"),
|
||||
)
|
||||
additional_group_dn = models.TextField(
|
||||
help_text=_("Prepended to Base DN for Group-queries.")
|
||||
help_text=_("Prepended to Base DN for Group-queries."),
|
||||
verbose_name=_("Addition Group DN"),
|
||||
)
|
||||
|
||||
user_object_filter = models.TextField(
|
||||
@ -54,13 +59,12 @@ class LDAPSource(Source):
|
||||
class LDAPPropertyMapping(PropertyMapping):
|
||||
"""Map LDAP Property to User or Group object"""
|
||||
|
||||
ldap_property = models.TextField()
|
||||
object_field = models.TextField()
|
||||
|
||||
form = "passbook.sources.ldap.forms.LDAPPropertyMappingForm"
|
||||
|
||||
def __str__(self):
|
||||
return f"LDAP Property Mapping {self.ldap_property} -> {self.object_field}"
|
||||
return f"LDAP Property Mapping {self.expression} -> {self.object_field}"
|
||||
|
||||
class Meta:
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
{% extends "generic/form.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
|
||||
{% block beneath_form %}
|
||||
<div class="form-group ">
|
||||
<label class="col-sm-2 control-label" for="friendly_name-2">
|
||||
</label>
|
||||
<div class="col-sm-10">
|
||||
<p>
|
||||
Expression using <a href="https://jinja.palletsprojects.com/en/2.11.x/templates/">Jinja</a>. Following variables are available:
|
||||
<ul>
|
||||
<li><code>ldap</code>: A Dictionary of all values retrieved from LDAP.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -38,12 +38,6 @@ class OAuthSourceForm(forms.ModelForm):
|
||||
"provider_type": forms.Select(choices=MANAGER.get_name_tuple()),
|
||||
"policies": FilteredSelectMultiple(_("policies"), False),
|
||||
}
|
||||
labels = {
|
||||
"request_token_url": _("Request Token URL"),
|
||||
"authorization_url": _("Authorization URL"),
|
||||
"access_token_url": _("Access Token URL"),
|
||||
"profile_url": _("Profile URL"),
|
||||
}
|
||||
|
||||
|
||||
class GitHubOAuthSourceForm(OAuthSourceForm):
|
||||
|
||||
35
passbook/sources/oauth/migrations/0002_auto_20200217_1526.py
Normal file
35
passbook/sources/oauth/migrations/0002_auto_20200217_1526.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 15:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_sources_oauth", "0001_initial"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="oauthsource",
|
||||
name="access_token_url",
|
||||
field=models.CharField(max_length=255, verbose_name="Access Token URL"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="oauthsource",
|
||||
name="authorization_url",
|
||||
field=models.CharField(max_length=255, verbose_name="Authorization URL"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="oauthsource",
|
||||
name="profile_url",
|
||||
field=models.CharField(max_length=255, verbose_name="Profile URL"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="oauthsource",
|
||||
name="request_token_url",
|
||||
field=models.CharField(
|
||||
blank=True, max_length=255, verbose_name="Request Token URL"
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.core.models import Source, UserSettings, UserSourceConnection
|
||||
from passbook.sources.oauth.clients import get_client
|
||||
@ -12,10 +12,16 @@ class OAuthSource(Source):
|
||||
"""Configuration for OAuth provider."""
|
||||
|
||||
provider_type = models.CharField(max_length=255)
|
||||
request_token_url = models.CharField(blank=True, max_length=255)
|
||||
authorization_url = models.CharField(max_length=255)
|
||||
access_token_url = models.CharField(max_length=255)
|
||||
profile_url = models.CharField(max_length=255)
|
||||
request_token_url = models.CharField(
|
||||
blank=True, max_length=255, verbose_name=_("Request Token URL")
|
||||
)
|
||||
authorization_url = models.CharField(
|
||||
max_length=255, verbose_name=_("Authorization URL")
|
||||
)
|
||||
access_token_url = models.CharField(
|
||||
max_length=255, verbose_name=_("Access Token URL")
|
||||
)
|
||||
profile_url = models.CharField(max_length=255, verbose_name=_("Profile URL"))
|
||||
consumer_key = models.TextField()
|
||||
consumer_secret = models.TextField()
|
||||
|
||||
|
||||
@ -28,11 +28,6 @@ class SAMLSourceForm(forms.ModelForm):
|
||||
"auto_logout",
|
||||
"signing_cert",
|
||||
]
|
||||
labels = {
|
||||
"entity_id": "Entity ID",
|
||||
"idp_url": "IDP URL",
|
||||
"idp_logout_url": "IDP Logout URL",
|
||||
}
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"policies": FilteredSelectMultiple(_("policies"), False),
|
||||
|
||||
30
passbook/sources/saml/migrations/0004_auto_20200217_1526.py
Normal file
30
passbook/sources/saml/migrations/0004_auto_20200217_1526.py
Normal file
@ -0,0 +1,30 @@
|
||||
# Generated by Django 3.0.3 on 2020-02-17 15:26
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_sources_saml", "0003_auto_20191107_1550"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="samlsource",
|
||||
name="entity_id",
|
||||
field=models.TextField(blank=True, default=None, verbose_name="Entity ID"),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlsource",
|
||||
name="idp_logout_url",
|
||||
field=models.URLField(
|
||||
blank=True, default=None, null=True, verbose_name="IDP Logout URL"
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="samlsource",
|
||||
name="idp_url",
|
||||
field=models.URLField(verbose_name="IDP URL"),
|
||||
),
|
||||
]
|
||||
@ -1,7 +1,7 @@
|
||||
"""saml sp models"""
|
||||
from django.db import models
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from passbook.core.models import Source
|
||||
|
||||
@ -9,9 +9,11 @@ from passbook.core.models import Source
|
||||
class SAMLSource(Source):
|
||||
"""SAML2 Source"""
|
||||
|
||||
entity_id = models.TextField(blank=True, default=None)
|
||||
idp_url = models.URLField()
|
||||
idp_logout_url = models.URLField(default=None, blank=True, null=True)
|
||||
entity_id = models.TextField(blank=True, default=None, verbose_name=_("Entity ID"))
|
||||
idp_url = models.URLField(verbose_name=_("IDP URL"))
|
||||
idp_logout_url = models.URLField(
|
||||
default=None, blank=True, null=True, verbose_name=_("IDP Logout URL")
|
||||
)
|
||||
auto_logout = models.BooleanField(default=False)
|
||||
signing_cert = models.TextField()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user