Merge pull request #4 from BeryJu/propertymapping-jinja

PropertyMappings using Jinja
This commit is contained in:
Jens L 2020-02-17 20:45:04 +01:00 committed by GitHub
commit 49e915f98b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 421 additions and 273 deletions

View File

@ -56,7 +56,7 @@ jobs:
restore-keys: | restore-keys: |
${{ runner.os }}-pipenv- ${{ runner.os }}-pipenv-
- name: Install dependencies - 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 - name: Lint with prospector
run: pipenv run prospector run: pipenv run prospector
bandit: bandit:

View File

@ -40,6 +40,7 @@ signxml = "*"
structlog = "*" structlog = "*"
swagger-spec-validator = "*" swagger-spec-validator = "*"
urllib3 = {extras = ["secure"],version = "*"} urllib3 = {extras = ["secure"],version = "*"}
jinja2 = "*"
[requires] [requires]
python_version = "3.8" python_version = "3.8"
@ -51,7 +52,6 @@ bumpversion = "*"
colorama = "*" colorama = "*"
coverage = "*" coverage = "*"
django-debug-toolbar = "*" django-debug-toolbar = "*"
prospector = "*"
pylint = "*" pylint = "*"
pylint-django = "*" pylint-django = "*"
unittest-xml-reporting = "*" unittest-xml-reporting = "*"

324
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "3693ac70f66ada5c8c8784e6e2d5c2f0ee75219e7141dde1075347234366e314" "sha256": "c9232d99b062ee14eda43d176481f16da78ce53f912c844db3f33f1b3e8a47b7"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -23,6 +23,13 @@
], ],
"version": "==2.5.2" "version": "==2.5.2"
}, },
"asgiref": {
"hashes": [
"sha256:7e06d934a7718bf3975acbf87780ba678957b87c7adc056f13b6215d610695a0",
"sha256:ea448f92fc35a0ef4b1508f53a04c4670255a3f33d22a81c8fc9c872036adbe5"
],
"version": "==3.2.3"
},
"asn1crypto": { "asn1crypto": {
"hashes": [ "hashes": [
"sha256:5a215cb8dc12f892244e3a113fe05397ee23c5c4ca7a69cd6e69811755efc42d", "sha256:5a215cb8dc12f892244e3a113fe05397ee23c5c4ca7a69cd6e69811755efc42d",
@ -46,18 +53,18 @@
}, },
"boto3": { "boto3": {
"hashes": [ "hashes": [
"sha256:7aaccacc199cd633b5ac14f0d544c9d592c53275a79cf4d230a9f66215331665", "sha256:33462a79d57c9c4a215e075472509537d03545f54566fc4f776fb0f4cfa616f6",
"sha256:ca36aabfa5e7fa9ee8f84f82c3faffb4ffe078923f935f572f70dc49154ef6a0" "sha256:34f9a04f529dc849f0e427782d6f3c6b62f7fb734d8f4859b17e5dee0855323e"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.11.5" "version": "==1.12.0"
}, },
"botocore": { "botocore": {
"hashes": [ "hashes": [
"sha256:2538065f9f5023eae3607e78fc5d8c595c9173ec02bc92410652078617c44ac1", "sha256:055da4826f6c9158e4a61549d57a2ce449c27d44ce34ab4c96c7bb7b5c993efc",
"sha256:554231b1690c8521e05a41e50184e43d62941fdf9351e658aea894649b879985" "sha256:1f7cecfcd38c7cac17b5386014eb04626d1c7559ee8d8ec1526058cd23f6d1d4"
], ],
"version": "==1.14.15" "version": "==1.15.0"
}, },
"celery": { "celery": {
"hashes": [ "hashes": [
@ -164,11 +171,11 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a", "sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283",
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038" "sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.2.10" "version": "==3.0.3"
}, },
"django-cors-middleware": { "django-cors-middleware": {
"hashes": [ "hashes": [
@ -195,11 +202,11 @@
}, },
"django-guardian": { "django-guardian": {
"hashes": [ "hashes": [
"sha256:8cf4efd67a863eb32beafd4335a38ffb083630f8ab2045212d27f8f9c3abe5a6", "sha256:8cacf49ebcc1e545f0a8997971eec0fe109f5ed31fc2a569a7bf5615453696e2",
"sha256:e638c9a23eeac534bb68b133975539ed8782f733ab6f35c0b23b4c39cd06b1bb" "sha256:ac81e88372fdf1795d84ba065550e739b42e9c6d07cdf201cf5bbf9efa7f396c"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.1.0" "version": "==2.2.0"
}, },
"django-model-utils": { "django-model-utils": {
"hashes": [ "hashes": [
@ -225,27 +232,26 @@
}, },
"django-otp": { "django-otp": {
"hashes": [ "hashes": [
"sha256:1f16c2b93fe484706ff16ac6f5e64ecc73dd240318c333e0560384ba548d3837", "sha256:523a87f8d0c52ce9a9f0a5e248c59dab3e85cdda5bbcd106cf49138a8f3f3209",
"sha256:cd4975539be478417033561e9832a1a69a583189f680e92a649f412c661f90aa" "sha256:ad3206e4a6f461c8968a2366a7cccfb340b93294e604b278aa9ab8b26f1017a1"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.7.5" "version": "==0.8.1"
}, },
"django-prometheus": { "django-prometheus": {
"hashes": [ "hashes": [
"sha256:f0657d4b887309086b71b55f6aa4a95f967b35fe115128b501f95422c423b12c", "sha256:362ea45e5ee26bdba85ce978aeb370659ca6bbc0d6bac69868a055179e053bd1",
"sha256:f645016ae5270ac2025a70788cd2bd636244a0c5705b323cc086994bf828181e" "sha256:facaa677386899303ea26c45552371cc43f476e42a81c081011a49cb5564af0b"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.0.dev124" "version": "==2.1.0.dev5"
}, },
"django-recaptcha": { "django-recaptcha": {
"hashes": [ "hashes": [
"sha256:3b19b9d972ca802b683eed5fd51ed84b0798f2a52f8d057a912eb7d99cff3779", "sha256:567784963fd5400feaf92e8951d8dbbbdb4b4c48a76e225d4baa63a2c9d2cd8c"
"sha256:b6ce959cd7c0af7501698fab5f52ca1bcb6d9402cb3b8b42a4c4cb13d89cfbfa"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.5" "version": "==2.0.6"
}, },
"django-redis": { "django-redis": {
"hashes": [ "hashes": [
@ -264,11 +270,11 @@
}, },
"django-storages": { "django-storages": {
"hashes": [ "hashes": [
"sha256:0a9b7e620e969fb0797523695329ed223bf540bbfdf6cd163b061fc11dab2d1c", "sha256:3103991c2ee8cef8a2ff096709973ffe7106183d211a79f22cf855f33533d924",
"sha256:9322ab74ba6371e2e0fccc350c741686ade829e43085597b26b07ae8955a0a00" "sha256:a59e9923cbce7068792f75344ed7727021ee4ac20f227cf17297d0d03d141e91"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.8" "version": "==1.9.1"
}, },
"djangorestframework": { "djangorestframework": {
"hashes": [ "hashes": [
@ -295,11 +301,11 @@
}, },
"drf-yasg": { "drf-yasg": {
"hashes": [ "hashes": [
"sha256:4cfec631880ae527a91ec7cd3241aea2f82189f59e2f089119aa687761afb227", "sha256:5572e9d5baab9f6b49318169df9789f7399d0e3c7bdac8fdb8dfccf1d5d2b1ca",
"sha256:504cce09035cf1bace63b84d9d778b772f86bb37d8a71ed6f723346362e633b2" "sha256:7d7af27ad16e18507e9392b2afd6b218fbffc432ec8dbea053099a2241e184ff"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.17.0" "version": "==1.17.1"
}, },
"eight": { "eight": {
"hashes": [ "hashes": [
@ -338,6 +344,7 @@
"sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484", "sha256:c10142f819c2d22bdcd17548c46fa9b77cf4fda45097854c689666bf425e7484",
"sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668" "sha256:c922560ac46888d47384de1dbdc3daaa2ea993af4b26a436dec31fa2c19ec668"
], ],
"index": "pypi",
"version": "==3.0.0a1" "version": "==3.0.0a1"
}, },
"jmespath": { "jmespath": {
@ -372,35 +379,36 @@
}, },
"lxml": { "lxml": {
"hashes": [ "hashes": [
"sha256:00ac0d64949fef6b3693813fe636a2d56d97a5a49b5bbb86e4cc4cc50ebc9ea2", "sha256:06d4e0bbb1d62e38ae6118406d7cdb4693a3fa34ee3762238bcb96c9e36a93cd",
"sha256:0571e607558665ed42e450d7bf0e2941d542c18e117b1ebbf0ba72f287ad841c", "sha256:0701f7965903a1c3f6f09328c1278ac0eee8f56f244e66af79cb224b7ef3801c",
"sha256:0e3f04a7615fdac0be5e18b2406529521d6dbdb0167d2a690ee328bef7807487", "sha256:1f2c4ec372bf1c4a2c7e4bb20845e8bcf8050365189d86806bad1e3ae473d081",
"sha256:13cf89be53348d1c17b453867da68704802966c433b2bb4fa1f970daadd2ef70", "sha256:4235bc124fdcf611d02047d7034164897ade13046bda967768836629bc62784f",
"sha256:217262fcf6a4c2e1c7cb1efa08bd9ebc432502abc6c255c4abab611e8be0d14d", "sha256:5828c7f3e615f3975d48f40d4fe66e8a7b25f16b5e5705ffe1d22e43fb1f6261",
"sha256:223e544828f1955daaf4cefbb4853bc416b2ec3fd56d4f4204a8b17007c21250", "sha256:585c0869f75577ac7a8ff38d08f7aac9033da2c41c11352ebf86a04652758b7a",
"sha256:277cb61fede2f95b9c61912fefb3d43fbd5f18bf18a14fae4911b67984486f5d", "sha256:5d467ce9c5d35b3bcc7172c06320dddb275fea6ac2037f72f0a4d7472035cea9",
"sha256:3213f753e8ae86c396e0e066866e64c6b04618e85c723b32ecb0909885211f74", "sha256:63dbc21efd7e822c11d5ddbedbbb08cd11a41e0032e382a0fd59b0b08e405a3a",
"sha256:4690984a4dee1033da0af6df0b7a6bde83f74e1c0c870623797cec77964de34d", "sha256:7bc1b221e7867f2e7ff1933165c0cec7153dce93d0cdba6554b42a8beb687bdb",
"sha256:4fcc472ef87f45c429d3b923b925704aa581f875d65bac80f8ab0c3296a63f78", "sha256:8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60",
"sha256:61409bd745a265a742f2693e4600e4dbd45cc1daebe1d5fad6fcb22912d44145", "sha256:8a0ebda56ebca1a83eb2d1ac266649b80af8dd4b4a3502b2c1e09ac2f88fe128",
"sha256:678f1963f755c5d9f5f6968dded7b245dd1ece8cf53c1aa9d80e6734a8c7f41d", "sha256:90ed0e36455a81b25b7034038e40880189169c308a3df360861ad74da7b68c1a",
"sha256:6c6d03549d4e2734133badb9ab1c05d9f0ef4bcd31d83e5d2b4747c85cfa21da", "sha256:95e67224815ef86924fbc2b71a9dbd1f7262384bca4bc4793645794ac4200717",
"sha256:6e74d5f4d6ecd6942375c52ffcd35f4318a61a02328f6f1bd79fcb4ffedf969e", "sha256:afdb34b715daf814d1abea0317b6d672476b498472f1e5aacbadc34ebbc26e89",
"sha256:7b4fc7b1ecc987ca7aaf3f4f0e71bbfbd81aaabf87002558f5bc95da3a865bcd", "sha256:b4b2c63cc7963aedd08a5f5a454c9f67251b1ac9e22fd9d72836206c42dc2a72",
"sha256:7ed386a40e172ddf44c061ad74881d8622f791d9af0b6f5be20023029129bc85", "sha256:d068f55bda3c2c3fcaec24bd083d9e2eede32c583faf084d6e4b9daaea77dde8",
"sha256:8f54f0924d12c47a382c600c880770b5ebfc96c9fd94cf6f6bdc21caf6163ea7", "sha256:d5b3c4b7edd2e770375a01139be11307f04341ec709cf724e0f26ebb1eef12c3",
"sha256:ad9b81351fdc236bda538efa6879315448411a81186c836d4b80d6ca8217cdb9", "sha256:deadf4df349d1dcd7b2853a2c8796593cc346600726eff680ed8ed11812382a7",
"sha256:bbd00e21ea17f7bcc58dccd13869d68441b32899e89cf6cfa90d624a9198ce85", "sha256:df533af6f88080419c5a604d0d63b2c33b1c0c4409aba7d0cb6de305147ea8c8",
"sha256:c3c289762cc09735e2a8f8a49571d0e8b4f57ea831ea11558247b5bdea0ac4db", "sha256:e4aa948eb15018a657702fee0b9db47e908491c64d36b4a90f59a64741516e77",
"sha256:cf4650942de5e5685ad308e22bcafbccfe37c54aa7c0e30cd620c2ee5c93d336", "sha256:e5d842c73e4ef6ed8c1bd77806bf84a7cb535f9c0cf9b2c74d02ebda310070e1",
"sha256:cfcbc33c9c59c93776aa41ab02e55c288a042211708b72fdb518221cc803abc8", "sha256:ebec08091a22c2be870890913bdadd86fcd8e9f0f22bcb398abd3af914690c15",
"sha256:e301055deadfedbd80cf94f2f65ff23126b232b0d1fea28f332ce58137bcdb18", "sha256:edc15fcfd77395e24543be48871c251f38132bb834d9fdfdad756adb6ea37679",
"sha256:ebbfe24df7f7b5c6c7620702496b6419f6a9aa2fd7f005eb731cc80d7b4692b9", "sha256:f2b74784ed7e0bc2d02bd53e48ad6ba523c9b36c194260b7a5045071abbb1012",
"sha256:eff69ddbf3ad86375c344339371168640951c302450c5d3e9936e98d6459db06", "sha256:fa071559f14bd1e92077b1b5f6c22cf09756c6de7139370249eb372854ce51e6",
"sha256:f6ed60a62c5f1c44e789d2cf14009423cb1646b44a43e40a9cf6a21f077678a1" "sha256:fd52e796fee7171c4361d441796b64df1acfceb51f29e545e812f16d023c4bbc",
"sha256:fe976a0f1ef09b3638778024ab9fb8cde3118f203364212c198f71341c0715ca"
], ],
"index": "pypi", "index": "pypi",
"version": "==4.4.2" "version": "==4.5.0"
}, },
"markupsafe": { "markupsafe": {
"hashes": [ "hashes": [
@ -450,11 +458,11 @@
}, },
"packaging": { "packaging": {
"hashes": [ "hashes": [
"sha256:aec3fdbb8bc9e4bb65f0634b9f551ced63983a529d6a8931817d52fdd0816ddb", "sha256:170748228214b70b672c581a3dd610ee51f733018650740e98c7df862a583f73",
"sha256:fe1d8331dfa7cc0a883b49d75fc76380b2ab2734b220fbb87d774e4fd4b851f8" "sha256:e665345f9eef0c621aa0bf2f8d78cf6d21904eef16a93f020240b704a57f1334"
], ],
"index": "pypi", "index": "pypi",
"version": "==20.0" "version": "==20.1"
}, },
"prometheus-client": { "prometheus-client": {
"hashes": [ "hashes": [
@ -522,41 +530,39 @@
}, },
"pycryptodome": { "pycryptodome": {
"hashes": [ "hashes": [
"sha256:042ae873baadd0c33b4d699a5c5b976ade3233a979d972f98ca82314632d868c", "sha256:012ca77c2105600e3c6aef43188101ac1d95052c633a4ae8fbebffab20c25f8a",
"sha256:0502876279772b1384b660ccc91563d04490d562799d8e2e06b411e2d81128a9", "sha256:05b4d865710f9a6378d3ada28195ff78e52642d3ecffe6fa9d379d870b9bf29d",
"sha256:2de33ed0a95855735d5a0fc0c39603314df9e78ee8bbf0baa9692fb46b3b8bbb", "sha256:07daddb98f98f771ba027f8f835bdb675aeb84effe41ed5221f520b267429354",
"sha256:319e568baf86620b419d53063b18c216abf924875966efdfe06891b987196a45", "sha256:09bf05a489fe10f9280a5e0163f195e7b9630cafb15f7d72fb9c8f5eb2afa84f",
"sha256:4372ec7518727172e1605c0843cdc5375d4771e447b8148c787b860260aae151", "sha256:0a8d5f2dbb4bbe830ace54286b829bfa529f0853bedaab6225fcb2e6d1f7e356",
"sha256:48821950ffb9c836858d8fa09d7840b6df52eadd387a3c5acece55cb387743f9", "sha256:1259b8ca49662b8a941177357f08147d858595c0042e63ff81e9628e925b5c9d",
"sha256:4b9533d4166ca07abdd49ce9d516666b1df944997fe135d4b21ac376aa624aff", "sha256:238d8b6dd27bd1a04816a68aa90a739e6dd23b192fcd83b50f9360958bff192a",
"sha256:54456cf85130e01674d21fb1ab89ffccacb138a8ade88d72fa2b0ac898d2798b", "sha256:2a57daef18a2022a5e4b6f7376c9ddd0c2d946e4b1f1e59b837f5bf295be7380",
"sha256:56fdd0e425f1b8fd3a00b6d96351f86226674974814c50534864d0124d48871f", "sha256:39e5ca2f66d1eac7abcba5ce1a03370d123dc6085620f1cd532dfee27e650178",
"sha256:57b1b707363490c495ad0eeb38bd1b0e1697c497af25fad78d3a1ebf0477fd5b", "sha256:3d516df693c195b8da3795e381429bd420e87081b7e6c2871c62c9897c812cda",
"sha256:5c485ed6e9718ebcaa81138fa70ace9c563d202b56a8cee119b4085b023931f5", "sha256:3e486c5b7228e864665fc479e9f596b2547b5fe29c6f5c8ed3807784d06faed7",
"sha256:63c103a22cbe9752f6ea9f1a0de129995bad91c4d03a66c67cffcf6ee0c9f1e1", "sha256:5029c46b0d41dfb763c3981c0af68eab029f06fe2b94f2299112fc18cf9e8d6d",
"sha256:68fab8455efcbfe87c5d75015476f9b606227ffe244d57bfd66269451706e899", "sha256:5817c0b3c263025d851da96b90cbc7e95348008f88b990e90d10683dba376666",
"sha256:6c2720696b10ae356040e888bde1239b8957fe18885ccf5e7b4e8dec882f0856", "sha256:79320f1fc5c9ca682869087c565bb29ca6f334692e940d7365771e9a94382e12",
"sha256:72166c2ac520a5dbd2d90208b9c279161ec0861662a621892bd52fb6ca13ab91", "sha256:887d08beca6368d3d70dc75126607ad76317a9fd07fe61323d8c3cb42add12b6",
"sha256:7c52308ac5b834331b2f107a490b2c27de024a229b61df4cdc5c131d563dfe98", "sha256:9163fec630495c10c767991e3f8dab32f4427bfb2dfeaa59bb28fe3e52ba66f2",
"sha256:87d8d85b4792ca5e730fb7a519fbc3ed976c59dcf79c5204589c59afd56b9926", "sha256:95d324e603c5cec5d89e8595236bbf59ade5fe3a72d100ce61eebb323d598750",
"sha256:896e9b6fd0762aa07b203c993fbbee7a1f1a4674c6886afd7bfa86f3d1be98a8", "sha256:9927aa8a8cb4af681279b6f28a1dcb14e0eb556c1aea8413a1e27608a8516e0c",
"sha256:8a799bea3c6617736e914a2e77c409f52893d382f619f088f8a80e2e21f573c1", "sha256:9948c2d5c5c0ee45ed44cee0e2eba2ce60a03be006ed3074521f3da3be162e72",
"sha256:9d9945ac8375d5d8e60bd2a2e1df5882eaa315522eedf3ca868b1546dfa34eba", "sha256:a719bd708207fa219fcbf4c8ebbcbc52846045f78179d00445b429fdabdbc1c4",
"sha256:9ef966c727de942de3e41aa8462c4b7b4bca70f19af5a3f99e31376589c11aac", "sha256:bc22ced26ebc46546798fa0141f4418f1db116dec517f0aeaecec87cf7b2416c",
"sha256:a168e73879619b467072509a223282a02c8047d932a48b74fbd498f27224aa04", "sha256:c41b7e10b72cef00cd63410f31fe50e72dc3a40eafbd146e288384fbe4208064",
"sha256:a30f501bbb32e01a49ef9e09ca1260e5ab49bf33a257080ec553e08997acc487", "sha256:cdb0ad83a5d6bac986a37fcb7562bcbef0aabae8ea19505bab5cf83c4d18af12",
"sha256:a8ca2450394d3699c9f15ef25e8de9a24b401933716a1e39d37fa01f5fe3c58b", "sha256:d8e480f65ac7105cbc288eec2417dc61eaac6ed6e75595aa15b8c7c77c53a68b",
"sha256:aec4d42deb836b8fb3ba32f2ba1ef0d33dd3dc9d430b1479ee7a914490d15b5e", "sha256:da2d581da279bc7408d38e16ff77754f5448c4352f2acfe530a5d14d8fc6934a",
"sha256:b4af098f2a50f8d048ab12cabb59456585c0acf43d90ee79782d2d6d0ed59dba", "sha256:de61091dd68326b600422cf731eb4810c4c6363f18a65bccd6061784b7454f5b",
"sha256:b55c60c321ac91945c60a40ac9896ac7a3d432bb3e8c14006dfd82ad5871c331", "sha256:ec7d39589f9cfc2a8b83b1d2fc673441757c99d43283e97b2dd46e0e23730db8",
"sha256:c53348358408d94869059e16fba5ff3bef8c52c25b18421472aba272b9bb450f", "sha256:f3204006869ab037604b1d9f045c4e84882ddd365e4ee8caa5eb1ff47a59188e",
"sha256:cbfd97f9e060f0d30245cd29fa267a9a84de9da97559366fca0a3f7655acc63f", "sha256:f4d2174e168d0eabd1fffaf88b4f62c2b6f30a67b8816f31024b8e48be3e2d75",
"sha256:d3fe3f33ad52bf0c19ee6344b695ba44ffbfa16f3c29ca61116b48d97bd970fb", "sha256:fcff8c9d88d58880f7eda2139c7c444552a38f98a9e77ba5970b6e78f54ac358"
"sha256:e3a79a30d15d9c7c284a7734036ee8abdb5ca3a6f5774d293cdc9e1358c1dc10",
"sha256:eec0689509389f19875f66ae8dedd59f982240cdab31b9f78a8dc266011df93a"
], ],
"index": "pypi", "index": "pypi",
"version": "==3.9.4" "version": "==3.9.6"
}, },
"pycryptodomex": { "pycryptodomex": {
"hashes": [ "hashes": [
@ -714,10 +720,10 @@
}, },
"ruamel.yaml": { "ruamel.yaml": {
"hashes": [ "hashes": [
"sha256:ee3264b83c3309b4ae7978afa185da6a1d278e3abc9fb942f1a0b57c622092f8", "sha256:0962fd7999e064c4865f96fb1e23079075f4a2a14849bcdc5cdba53a24f9759b",
"sha256:fd16843ff0ba45fa5e1ea9ea7038428b4a46f2c39deea9aa67f9eaa34823dc11" "sha256:099c644a778bf72ffa00524f78dd0b6476bca94a1da344130f4bf3381ce5b954"
], ],
"version": "==0.16.9" "version": "==0.16.10"
}, },
"ruamel.yaml.clib": { "ruamel.yaml.clib": {
"hashes": [ "hashes": [
@ -753,11 +759,11 @@
}, },
"sentry-sdk": { "sentry-sdk": {
"hashes": [ "hashes": [
"sha256:8e2d38dc58dc992280487e553ec3d97a424e4d179f4fad802ef3b08f64ccf4d8", "sha256:b06dd27391fd11fb32f84fe054e6a64736c469514a718a99fb5ce1dff95d6b28",
"sha256:9b59e155229ea7d46a52b5c025d8c3c6d591e9dd9bb5f5f47310b2bb430038a8" "sha256:e023da07cfbead3868e1e2ba994160517885a32dfd994fc455b118e37989479b"
], ],
"index": "pypi", "index": "pypi",
"version": "==0.14.0" "version": "==0.14.1"
}, },
"service-identity": { "service-identity": {
"hashes": [ "hashes": [
@ -791,11 +797,11 @@
}, },
"structlog": { "structlog": {
"hashes": [ "hashes": [
"sha256:4287058cf4ce1a59bc5dea290d6386d37f29a37529c9a51cdf7387e51710152b", "sha256:7a48375db6274ed1d0ae6123c486472aa1d0890b08d314d2b016f3aa7f35990b",
"sha256:6640e6690fc31d5949bc614c1a630464d3aaa625284aeb7c6e486c3010d73e12" "sha256:8a672be150547a93d90a7d74229a29e765be05bd156a35cdcc527ebf68e9af92"
], ],
"index": "pypi", "index": "pypi",
"version": "==19.2.0" "version": "==20.1.0"
}, },
"swagger-spec-validator": { "swagger-spec-validator": {
"hashes": [ "hashes": [
@ -817,12 +823,12 @@
"secure" "secure"
], ],
"hashes": [ "hashes": [
"sha256:a8a318824cc77d1fd4b2bec2ded92646630d7fe8619497b142c84a9e6f5a7293", "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
"sha256:f3c5fd51747d450d4dcf6f923c81f78f811aab8205fda64b0aba34a4e48b0745" "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"
], ],
"index": "pypi", "index": "pypi",
"markers": null, "markers": null,
"version": "==1.25.7" "version": "==1.25.8"
}, },
"vine": { "vine": {
"hashes": [ "hashes": [
@ -863,10 +869,10 @@
}, },
"autopep8": { "autopep8": {
"hashes": [ "hashes": [
"sha256:4d8eec30cc81bc5617dbf1218201d770dc35629363547f17577c61683ccfb3ee" "sha256:0f592a0447acea0c2b0a9602be1e4e3d86db52badd2e3c84f0193bfd89fd3a43"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.4.4" "version": "==1.5"
}, },
"bandit": { "bandit": {
"hashes": [ "hashes": [
@ -946,40 +952,33 @@
}, },
"django": { "django": {
"hashes": [ "hashes": [
"sha256:1226168be1b1c7efd0e66ee79b0e0b58b2caa7ed87717909cd8a57bb13a7079a", "sha256:2f1ba1db8648484dd5c238fb62504777b7ad090c81c5f1fd8d5eb5ec21b5f283",
"sha256:9a4635813e2d498a3c01b10c701fe4a515d76dd290aaa792ccb65ca4ccb6b038" "sha256:c91c91a7ad6ef67a874a4f76f58ba534f9208412692a840e1d125eb5c279cb0a"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.2.10" "version": "==3.0.3"
}, },
"django-debug-toolbar": { "django-debug-toolbar": {
"hashes": [ "hashes": [
"sha256:24c157bc6c0e1648e0a6587511ecb1b007a00a354ce716950bff2de12693e7a8", "sha256:eabbefe89881bbe4ca7c980ff102e3c35c8e8ad6eb725041f538988f2f39a943",
"sha256:77cfba1d6e91b9bc3d36dc7dc74a9bb80be351948db5f880f2562a0cbf20b6c5" "sha256:ff94725e7aae74b133d0599b9bf89bd4eb8f5d2c964106e61d11750228c8774c"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.1" "version": "==2.2"
},
"dodgy": {
"hashes": [
"sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a",
"sha256:51f54c0fd886fa3854387f354b19f429d38c04f984f38bc572558b703c0542a6"
],
"version": "==0.2.1"
}, },
"gitdb2": { "gitdb2": {
"hashes": [ "hashes": [
"sha256:1b6df1433567a51a4a9c1a5a0de977aa351a405cc56d7d35f3388bad1f630350", "sha256:0375d983fd887d03c8942e81b1b0abc6c320cfb500cd3fe0d9c0eac87fbf2b52",
"sha256:96bbb507d765a7f51eb802554a9cfe194a174582f772e0d89f4e87288c288b7b" "sha256:b2b3a67090c17dc61f8407ca485e79ae811225ab5ebcd98ac5ee01448e8987b5"
], ],
"version": "==2.0.6" "version": "==3.0.2"
}, },
"gitpython": { "gitpython": {
"hashes": [ "hashes": [
"sha256:99c77677f31f255e130f3fed4c8e0eebb35f1a09df98ff965fff6774f71688cf", "sha256:620b3c729bbc143b498cfea77e302999deedc55faec5b1067086c9ef90e101bc",
"sha256:99cd0403cecd8a13b95d2e045b9fcaa7837137fcc5ec3105f2c413305d82c143" "sha256:a43a5d88a5bbc3cf32bb5223e4b4e68fd716db5e9996cad6e561bbfee6e5f4af"
], ],
"version": "==3.0.7" "version": "==3.0.8"
}, },
"isort": { "isort": {
"hashes": [ "hashes": [
@ -1035,40 +1034,12 @@
], ],
"version": "==5.4.4" "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": { "pycodestyle": {
"hashes": [ "hashes": [
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83", "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a" "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
], ],
"version": "==2.4.0" "version": "==2.5.0"
},
"pydocstyle": {
"hashes": [
"sha256:da7831660b7355307b32778c4a0dbfb137d89254ef31a2b2978f50fc0b4d7586",
"sha256:f4f5d210610c2d153fae39093d44224c17429e2ad7da12a8b419aba5c2f614b5"
],
"version": "==5.0.2"
},
"pyflakes": {
"hashes": [
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
],
"version": "==2.1.1"
}, },
"pylint": { "pylint": {
"hashes": [ "hashes": [
@ -1078,25 +1049,13 @@
"index": "pypi", "index": "pypi",
"version": "==2.4.4" "version": "==2.4.4"
}, },
"pylint-celery": {
"hashes": [
"sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"
],
"version": "==0.3"
},
"pylint-django": { "pylint-django": {
"hashes": [ "hashes": [
"sha256:9bdb0e022b19881218a25ffb8ad05e83b83bc5cdbc58e5ee8ffbe99965193f6c", "sha256:440beb814464928aedd2e21196bb6e47a83b63e2cbe886a701ba0f4a64206bbb",
"sha256:9eea6a026eaa5ecfad5fed7a33faf77ef55a43cc78afbcaf2f6ddd071156b3f8" "sha256:d5d113605a64cf0e638b707d4cb42106e626f8851bc30a44d5b22bd698ad8483"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.0.12" "version": "==2.0.13"
},
"pylint-flask": {
"hashes": [
"sha256:f4d97de2216bf7bfce07c9c08b166e978fe9f2725de2a50a9845a97de7e31517"
],
"version": "==0.6"
}, },
"pylint-plugin-utils": { "pylint-plugin-utils": {
"hashes": [ "hashes": [
@ -1155,18 +1114,6 @@
], ],
"version": "==2020.1.8" "version": "==2020.1.8"
}, },
"requirements-detector": {
"hashes": [
"sha256:9fbc4b24e8b7c3663aff32e3eba34596848c6b91bd425079b386973bd8d08931"
],
"version": "==0.6"
},
"setoptconf": {
"hashes": [
"sha256:5b0b5d8e0077713f5d5152d4f63be6f048d9a1bb66be15d089a11c898c3cf49c"
],
"version": "==0.2.0"
},
"six": { "six": {
"hashes": [ "hashes": [
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a", "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
@ -1181,13 +1128,6 @@
], ],
"version": "==2.0.5" "version": "==2.0.5"
}, },
"snowballstemmer": {
"hashes": [
"sha256:209f257d7533fdb3cb73bdbd24f436239ca3b2fa67d56f6ff88e86be08cc5ef0",
"sha256:df3bac3df4c2c01363f3dd2cfa78cce2840a79b9f1c2d2de9ce8d31683992f52"
],
"version": "==2.0.0"
},
"sqlparse": { "sqlparse": {
"hashes": [ "hashes": [
"sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177", "sha256:40afe6b8d4b1117e7dff5504d7a8ce07d9a1b15aeeade8a2d10f130a834f8177",
@ -1237,11 +1177,11 @@
}, },
"unittest-xml-reporting": { "unittest-xml-reporting": {
"hashes": [ "hashes": [
"sha256:358bbdaf24a26d904cc1c26ef3078bca7fc81541e0a54c8961693cc96a6f35e0", "sha256:6584562cde8226fc79fa29e38903c669a02799074a563bb0b70fcd3a8e87829c",
"sha256:9d28ddf6524cf0ff9293f61bd12e792de298f8561a5c945acea63fb437789e0e" "sha256:dd8046a64dc62f3d30301523a54992e0be75a945194491e0a3b718130cb429e0"
], ],
"index": "pypi", "index": "pypi",
"version": "==2.5.2" "version": "==3.0.1"
}, },
"wrapt": { "wrapt": {
"hashes": [ "hashes": [

View 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 %}]
```

View File

@ -19,6 +19,9 @@ nav:
- Rancher: integrations/services/rancher/index.md - Rancher: integrations/services/rancher/index.md
- Harbor: integrations/services/harbor/index.md - Harbor: integrations/services/harbor/index.md
- Sentry: integrations/services/sentry/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_name: "BeryJu.org/passbook"
repo_url: https://github.com/BeryJu/passbook repo_url: https://github.com/BeryJu/passbook

View File

@ -1,4 +1,4 @@
{% extends "generic/form.html" %} {% extends base_template|default:"generic/form.html" %}
{% load utils %} {% load utils %}
{% load i18n %} {% load i18n %}

View File

@ -20,6 +20,7 @@
<link rel="stylesheet" href="{% static 'codemirror/lib/codemirror.css' %}"> <link rel="stylesheet" href="{% static 'codemirror/lib/codemirror.css' %}">
<link rel="stylesheet" href="{% static 'codemirror/theme/monokai.css' %}"> <link rel="stylesheet" href="{% static 'codemirror/theme/monokai.css' %}">
<script src="{% static 'codemirror/mode/yaml/yaml.js' %}"></script> <script src="{% static 'codemirror/mode/yaml/yaml.js' %}"></script>
<script src="{% static 'codemirror/mode/jinja2/jinja2.js' %}"></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}
@ -29,21 +30,33 @@
<div class=""> <div class="">
<form action="" method="post" class="form-horizontal"> <form action="" method="post" class="form-horizontal">
{% include 'partials/form.html' with form=form %} {% include 'partials/form.html' with form=form %}
{% block beneath_form %}
{% endblock %}
<a class="btn btn-default" href="{% back %}">{% trans "Cancel" %}</a> <a class="btn btn-default" href="{% back %}">{% trans "Cancel" %}</a>
<input type="submit" class="btn btn-primary" value="{% block action %}{% endblock %}" /> <input type="submit" class="btn btn-primary" value="{% block action %}{% endblock %}" />
</form> </form>
</div> </div>
{% block beneath_form %}
{% endblock %}
<script> <script>
let attributes = document.getElementsByName('attributes'); const attributes = document.getElementsByName('attributes');
if (attributes.length > 0) { 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', mode: 'yaml',
theme: 'monokai', theme: 'monokai',
lineNumbers: true, lineNumbers: true,
}); });
} }
const templates = document.getElementsByName('template');
if (templates.length > 0) {
// https://github.com/codemirror/CodeMirror/issues/5092
templates[0].removeAttribute("required");
const templateCM = CodeMirror.fromTextArea(templates[0], {
mode: 'jinja2',
theme: 'monokai',
lineNumbers: true,
});
}
</script> </script>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,4 @@
{% extends "generic/form.html" %} {% extends base_template|default:"generic/form.html" %}
{% load utils %} {% load utils %}
{% load i18n %} {% load i18n %}

View File

@ -66,6 +66,9 @@ class PropertyMappingCreateView(
if x.__name__ == property_mapping_type if x.__name__ == property_mapping_type
) )
kwargs["type"] = model._meta.verbose_name 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 return kwargs
def get_form_class(self): def get_form_class(self):
@ -92,6 +95,12 @@ class PropertyMappingUpdateView(
success_url = reverse_lazy("passbook_admin:property-mappings") success_url = reverse_lazy("passbook_admin:property-mappings")
success_message = _("Successfully updated Property Mapping") success_message = _("Successfully updated Property Mapping")
def get_context_data(self, **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): def get_form_class(self):
form_class_path = self.get_object().form form_class_path = self.get_object().form
form_class = path_to_class(form_class_path) form_class = path_to_class(form_class_path)

View 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,
),
]

View 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",
),
]

View File

@ -2,15 +2,17 @@
from datetime import timedelta from datetime import timedelta
from random import SystemRandom from random import SystemRandom
from time import sleep from time import sleep
from typing import Optional from typing import Optional, Any
from uuid import uuid4 from uuid import uuid4
from jinja2.nativetypes import NativeEnvironment
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
from django.db import models from django.db import models
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.http import HttpRequest
from django.utils.timezone import now 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 django_prometheus.models import ExportModelOperationsMixin
from guardian.mixins import GuardianUserMixin from guardian.mixins import GuardianUserMixin
from model_utils.managers import InheritanceManager from model_utils.managers import InheritanceManager
@ -22,6 +24,7 @@ from passbook.policies.exceptions import PolicyException
from passbook.policies.struct import PolicyRequest, PolicyResult from passbook.policies.struct import PolicyRequest, PolicyResult
LOGGER = get_logger() LOGGER = get_logger()
NATIVE_ENVIRONMENT = NativeEnvironment()
def default_nonce_duration(): 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.""" """User-defined key -> x mapping which can be used by providers to expose extra data."""
name = models.TextField() name = models.TextField()
expression = models.TextField()
form = "" form = ""
objects = InheritanceManager() 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): def __str__(self):
return f"Property Mapping {self.name}" return f"Property Mapping {self.name}"

View File

@ -14,12 +14,16 @@ class SAMLProviderSerializer(ModelSerializer):
fields = [ fields = [
"pk", "pk",
"name", "name",
"property_mappings", "processor_path",
"acs_url", "acs_url",
"audience", "audience",
"processor_path",
"issuer", "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",
"signing_cert", "signing_cert",
"signing_key", "signing_key",
@ -39,7 +43,7 @@ class SAMLPropertyMappingSerializer(ModelSerializer):
class Meta: class Meta:
model = SAMLPropertyMapping model = SAMLPropertyMapping
fields = ["pk", "name", "saml_name", "friendly_name", "values"] fields = ["pk", "name", "saml_name", "friendly_name", "expression"]
class SAMLPropertyMappingViewSet(ModelViewSet): class SAMLPropertyMappingViewSet(ModelViewSet):

View File

@ -4,7 +4,6 @@ from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from passbook.lib.fields import DynamicArrayField
from passbook.providers.saml.models import ( from passbook.providers.saml.models import (
SAMLPropertyMapping, SAMLPropertyMapping,
SAMLProvider, SAMLProvider,
@ -60,13 +59,14 @@ class SAMLProviderForm(forms.ModelForm):
class SAMLPropertyMappingForm(forms.ModelForm): class SAMLPropertyMappingForm(forms.ModelForm):
"""SAML Property Mapping form""" """SAML Property Mapping form"""
template_name = "saml/idp/property_mapping_form.html"
class Meta: class Meta:
model = SAMLPropertyMapping model = SAMLPropertyMapping
fields = ["name", "saml_name", "friendly_name", "values"] fields = ["name", "saml_name", "friendly_name", "expression"]
widgets = { widgets = {
"name": forms.TextInput(), "name": forms.TextInput(),
"saml_name": forms.TextInput(), "saml_name": forms.TextInput(),
"friendly_name": forms.TextInput(), "friendly_name": forms.TextInput(),
} }
field_classes = {"values": DynamicArrayField}

View File

@ -4,46 +4,6 @@ import django.contrib.postgres.fields
from django.db import migrations, models from django.db import migrations, models
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",
"Value": "{user.email}",
},
{"FriendlyName": "cn", "Name": "urn:oid:2.5.4.3", "Value": "{user.name}",},
{
"FriendlyName": "mail",
"Name": "urn:oid:0.9.2342.19200300.100.1.3",
"Value": "{user.email}",
},
{
"FriendlyName": "displayName",
"Name": "urn:oid:2.16.840.1.113730.3.1.241",
"Value": "{user.username}",
},
{
"FriendlyName": "uid",
"Name": "urn:oid:0.9.2342.19200300.100.1.1",
"Value": "{user.pk}",
},
]
for default in defaults:
SAMLPropertyMapping.objects.using(db_alias).get_or_create(
saml_name=default["Name"],
friendly_name=default["FriendlyName"],
values=[default["Value"]],
defaults={
"name": f"Autogenerated SAML Mapping: {default['FriendlyName']} -> {default['Value']}"
},
)
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
@ -75,5 +35,4 @@ class Migration(migrations.Migration):
name="signing_cert", name="signing_cert",
field=models.TextField(verbose_name="Singing Certificate"), field=models.TextField(verbose_name="Singing Certificate"),
), ),
migrations.RunPython(create_default_property_mappings),
] ]

View File

@ -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),
]

View File

@ -1,5 +1,4 @@
"""passbook saml_idp Models""" """passbook saml_idp Models"""
from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from django.shortcuts import reverse from django.shortcuts import reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -118,15 +117,6 @@ class SAMLPropertyMapping(PropertyMapping):
saml_name = models.TextField(verbose_name="SAML Name") saml_name = models.TextField(verbose_name="SAML Name")
friendly_name = models.TextField(default=None, blank=True, null=True) friendly_name = models.TextField(default=None, blank=True, null=True)
values = ArrayField(
models.TextField(),
help_text=_(
(
"This string can contain string substitutions delimited by {}."
" The following Variables are available: user, request"
)
),
)
form = "passbook.providers.saml.forms.SAMLPropertyMappingForm" form = "passbook.providers.saml.forms.SAMLPropertyMappingForm"

View File

@ -98,17 +98,19 @@ class Processor:
for mapping in self._remote.property_mappings.all().select_subclasses(): for mapping in self._remote.property_mappings.all().select_subclasses():
if isinstance(mapping, SAMLPropertyMapping): if isinstance(mapping, SAMLPropertyMapping):
value = mapping.evaluate(
user=self._http_request.user,
request=self._http_request,
provider=self._remote,
)
mapping_payload = { mapping_payload = {
"Name": mapping.saml_name, "Name": mapping.saml_name,
"ValueArray": [],
"FriendlyName": mapping.friendly_name, "FriendlyName": mapping.friendly_name,
} }
for value in mapping.values: if isinstance(value, list):
mapping_payload["ValueArray"].append( mapping_payload["ValueArray"] = value
value.format( else:
user=self._http_request.user, request=self._http_request mapping_payload["Value"] = value
)
)
attributes.append(mapping_payload) attributes.append(mapping_payload)
self._assertion_params["ATTRIBUTES"] = attributes self._assertion_params["ATTRIBUTES"] = attributes
self._assertion_xml = get_assertion_xml( self._assertion_xml = get_assertion_xml(

View File

@ -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 %}

View File

@ -35,7 +35,7 @@ class LDAPPropertyMappingSerializer(ModelSerializer):
class Meta: class Meta:
model = LDAPPropertyMapping model = LDAPPropertyMapping
fields = ["pk", "name", "ldap_property", "object_field"] fields = ["pk", "name", "expression", "object_field"]
class LDAPSourceViewSet(ModelViewSet): class LDAPSourceViewSet(ModelViewSet):

View File

@ -6,7 +6,7 @@ import ldap3.core.exceptions
from structlog import get_logger from structlog import get_logger
from passbook.core.models import Group, User 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() LOGGER = get_logger()
@ -154,7 +154,10 @@ class Connector:
) -> Dict[str, Dict[Any, Any]]: ) -> Dict[str, Dict[Any, Any]]:
properties = {"attributes": {}} properties = {"attributes": {}}
for mapping in self._source.property_mappings.all().select_subclasses(): 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: if self._source.object_uniqueness_field in attributes:
properties["attributes"]["ldap_uniq"] = attributes.get( properties["attributes"]["ldap_uniq"] = attributes.get(
self._source.object_uniqueness_field self._source.object_uniqueness_field

View File

@ -50,10 +50,12 @@ class LDAPSourceForm(forms.ModelForm):
class LDAPPropertyMappingForm(forms.ModelForm): class LDAPPropertyMappingForm(forms.ModelForm):
"""LDAP Property Mapping form""" """LDAP Property Mapping form"""
template_name = "ldap/property_mapping_form.html"
class Meta: class Meta:
model = LDAPPropertyMapping model = LDAPPropertyMapping
fields = ["name", "ldap_property", "object_field"] fields = ["name", "object_field", "expression"]
widgets = { widgets = {
"name": forms.TextInput(), "name": forms.TextInput(),
"ldap_property": forms.TextInput(), "ldap_property": forms.TextInput(),

View File

@ -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),
]

View File

@ -59,13 +59,12 @@ class LDAPSource(Source):
class LDAPPropertyMapping(PropertyMapping): class LDAPPropertyMapping(PropertyMapping):
"""Map LDAP Property to User or Group object""" """Map LDAP Property to User or Group object"""
ldap_property = models.TextField(verbose_name=_("LDAP Property"))
object_field = models.TextField() object_field = models.TextField()
form = "passbook.sources.ldap.forms.LDAPPropertyMappingForm" form = "passbook.sources.ldap.forms.LDAPPropertyMappingForm"
def __str__(self): 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: class Meta:

View File

@ -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 %}