Skip to content

Commit 8d3cbe8

Browse files
committed
Add a couple tests.
1 parent 56191be commit 8d3cbe8

File tree

8 files changed

+77
-2
lines changed

8 files changed

+77
-2
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Response.
2424

2525
```python
2626
from flask import request, session, redirect
27+
import uw_saml2
2728

2829
@app.route('/saml/login', methods=['GET', 'POST'])
2930
def login():

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,6 @@
2020
license='Apache License, Version 2.0',
2121
packages=find_packages(),
2222
include_package_data=True,
23-
install_requires=['python3-saml']
23+
install_requires=['python3-saml'],
24+
tests_require=['pytest', 'pytest-cov', 'mock', 'pycodestyle']
2425
)

tests/samlresponse.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
RelayState=%2Fsecure&SAMLResponse=PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNhbWwycDpSZXNwb25zZSBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9zYW1sZGVtby5pYW1kZXYucy51dy5lZHUvc2FtbC9sb2dpbiIgSUQ9Il83ZjFiNTlmMmZjYTVmMDkwZDk2ODBjNmUxYjMwYjBmMSIgSW5SZXNwb25zZVRvPSJPTkVMT0dJTl8wMTYwOGY3NjdhNDg1YTEyZDYxMWZiOGRlZTJiZjA4ZWJlNDJlYmI2IiBJc3N1ZUluc3RhbnQ9IjIwMTktMDItMDRUMTg6MTE6MjIuMDU0WiIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1sMnA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgeG1sbnM6eHNkPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYSI%2BPHNhbWwyOklzc3VlciB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BdXJuOm1hY2U6aW5jb21tb246d2FzaGluZ3Rvbi5lZHU8L3NhbWwyOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj4KPGRzOlNpZ25lZEluZm8%2BCjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BCjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8%2BCjxkczpSZWZlcmVuY2UgVVJJPSIjXzdmMWI1OWYyZmNhNWYwOTBkOTY4MGM2ZTFiMzBiMGYxIj4KPGRzOlRyYW5zZm9ybXM%2BCjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPgo8ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIj48ZWM6SW5jbHVzaXZlTmFtZXNwYWNlcyBQcmVmaXhMaXN0PSJ4c2QiIHhtbG5zOmVjPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybT4KPC9kczpUcmFuc2Zvcm1zPgo8ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8%2BCjxkczpEaWdlc3RWYWx1ZT5RUHdSM3VCbnJ5QThwODVuQVBSSldpTTFpM1JyUGJoMHJVdGtxWk1YQ1Q0PTwvZHM6RGlnZXN0VmFsdWU%2BCjwvZHM6UmVmZXJlbmNlPgo8L2RzOlNpZ25lZEluZm8%2BCjxkczpTaWduYXR1cmVWYWx1ZT4KTEJ1bFh1NjJvdnliblVoU3l1ZXBId1diUHpackVBMEQvMEJwcXBPMG5zamVteXhNU0VFay9VRXBuZXIreTJYVktLWFN3QitwUWV3Rwpiem9GNnROL3A1L1U5WThDWWRVdnVPVG9xN0dac2RuTWsxdm9rM0FJaW96Z3VteHF5KzFXdmg4aHQvZlc5eDlHczhDRE5xd0lsa1A2CjJ5WGRGYmNScnE3ME5ia1BmK04rK0wxaEtlVjZwbnl4dHJNeWVkUHZQZHFId29xNGJpY0QrUlY5WVNXcXRPK0srRnlnUndwbTJxeFkKTkIwRmhZOS9VT2FoNTA4a21LVWZhdmgvelcwSXJYdkZ6RG02cVVGNmVDd2FtTERERThtZG5ZbTlLQ1VpcCs1cDR1VVE2bWZCb24yTgpyR29QK3E0SkkzbTBBKzJQSzVCRFgrUVZLblJ6UHZEcnhyb0k1QT09CjwvZHM6U2lnbmF0dXJlVmFsdWU%2BCjxkczpLZXlJbmZvPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUQvVENDQXVXZ0F3SUJBZ0lKQU1vWUpiRHQ5bEtLTUEwR0NTcUdTSWIzRFFFQkJRVUFNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Rc3cKQ1FZRFZRUUlFd0pYUVRFaE1COEdBMVVFQ2hNWVZXNXBkbVZ5YzJsMGVTQnZaaUJYWVhOb2FXNW5kRzl1TVIwd0d3WURWUVFERXhScApaSEF1ZFM1M1lYTm9hVzVuZEc5dUxtVmtkVEFlRncweE1UQTBNall4T1RFd016bGFGdzB5TVRBME1qTXhPVEV3TXpsYU1Gd3hDekFKCkJnTlZCQVlUQWxWVE1Rc3dDUVlEVlFRSUV3SlhRVEVoTUI4R0ExVUVDaE1ZVlc1cGRtVnljMmwwZVNCdlppQlhZWE5vYVc1bmRHOXUKTVIwd0d3WURWUVFERXhScFpIQXVkUzUzWVhOb2FXNW5kRzl1TG1Wa2RUQ0NBU0l3RFFZSktvWklodmNOQVFFQkJRQURnZ0VQQURDQwpBUW9DZ2dFQkFNSDlHOG02OEwwSGY5Ym1mNC83YytFUnhnRFFyYnE1ME5mU2kyWVRRV2MxdmVVSVBZYlp5MWFnU051YzRkd24zUnRDCjB1T1FiZE5UWVVBaVZUY1lnYVljZUpWQjdzeVdmOVF5R0lyZ2xaUE11OThjNWhXYjd2cXd2czZkM3MyU203dEJpYjJ2NnhRRERpWjQKS0p4cGRBdnNvUFFsbUdkZ3BGZm1Bc2lZcm5ZRlhMVEhnYmdDYy9ZaFY4bHViVGFrVWRJM2JNWVdmaDlka2orRFZHVW10MmdMdFFVegpidUg4RVU0NHZuWGdyUVlTWE5Ra21SY3lvRTNyajRSaGhidS9wNUQzUCtudU91a0xZRk9MUmFOZWlpR3lUdTNQN2d0Yy9keS9ValVyCmYrcEg3NVVVVTdMYjM2OWRHRWZad3ZWdElUWHNkeXAwcEJmdW40Q1A4MDhIOU4wQ0F3RUFBYU9Cd1RDQnZqQWRCZ05WSFE0RUZnUVUKUDVzbXgzWllLT0RNa0RnbGtUYmR1dkxjR1lBd2dZNEdBMVVkSXdTQmhqQ0JnNEFVUDVzbXgzWllLT0RNa0RnbGtUYmR1dkxjR1lDaApZS1JlTUZ3eEN6QUpCZ05WQkFZVEFsVlRNUXN3Q1FZRFZRUUlFd0pYUVRFaE1COEdBMVVFQ2hNWVZXNXBkbVZ5YzJsMGVTQnZaaUJYCllYTm9hVzVuZEc5dU1SMHdHd1lEVlFRREV4UnBaSEF1ZFM1M1lYTm9hVzVuZEc5dUxtVmtkWUlKQU1vWUpiRHQ5bEtLTUF3R0ExVWQKRXdRRk1BTUJBZjh3RFFZSktvWklodmNOQVFFRkJRQURnZ0VCQUVvN2MyQ05IRUkrRnZ6NURod3VtVStXSFhxd1NPSzQ3TXhYd05KVgpwRlE5R1BSMlpHREFxNmh6TEpMQVZXY1k0a0IzRUNEa1J0eXNBV1NGSG0xcm9PVTd4c1U5ZjBDMTdRb2tvWGZMTkMwZDdLb2l2UE02CmN0bDhhUmZ0VTVtb3lGSmtrSlgzcVNFeFhybDA1M3V4VE9RVlBtczR5cGtZdjFBL0ZCWldnU0M4ZU5vWW5CbnYxTWh5NG04YmZlRU4KN3FUOXJGb3hoNGNWak1IMVlrcTdKV3lGWExFQjRpZnpINEtIeXBsdDVSeXY2MWVoNkoxWVBGYTJSdXJWVHlHcEhKWmVPTFVJQnZKdQoxNUd6Y2V4dUREWGUwa2c3c0hENlBiSzB4ekVGL1FlWFAvaFh6TXhSOWtRWEIvSVIvYjJrNGllbitFTTNlWS91ZUJjVFo5NWRnVk09PC9kczpYNTA5Q2VydGlmaWNhdGU%2BPC9kczpYNTA5RGF0YT48L2RzOktleUluZm8%2BPC9kczpTaWduYXR1cmU%2BPHNhbWwycDpTdGF0dXM%2BPHNhbWwycDpTdGF0dXNDb2RlIFZhbHVlPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6c3RhdHVzOlN1Y2Nlc3MiLz48L3NhbWwycDpTdGF0dXM%2BPHNhbWwyOkFzc2VydGlvbiBJRD0iXzk5YjA2ZGYwNmFlYTgwZDRiZGQwMzkyYTI4Yjk2NmQ3IiBJc3N1ZUluc3RhbnQ9IjIwMTktMDItMDRUMTg6MTE6MjIuMDU0WiIgVmVyc2lvbj0iMi4wIiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BPHNhbWwyOklzc3Vlcj51cm46bWFjZTppbmNvbW1vbjp3YXNoaW5ndG9uLmVkdTwvc2FtbDI6SXNzdWVyPjxzYW1sMjpTdWJqZWN0PjxzYW1sMjpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6bmFtZWlkLWZvcm1hdDp0cmFuc2llbnQiIE5hbWVRdWFsaWZpZXI9InVybjptYWNlOmluY29tbW9uOndhc2hpbmd0b24uZWR1IiBTUE5hbWVRdWFsaWZpZXI9Imh0dHBzOi8vc2FtbGRlbW8uaWFtZGV2LnMudXcuZWR1L3NhbWwiPkFBZHpaV055WlhReEh0bXo5VTFIN3JFb2NtN0xnaFNiM1h5UFNOR2xBb094SngzNW44SzFuQjJ1Qk9yM2RlalMxOFl0dGM5cU5rOFZvcGpKTXZLYjdVZnlSZWNsTy94VWZkQXBuS2p0bjlpd096S1Q3OWpEU2hPd3JXUkJiNFUzOEx0eGNhR3RGZnNxUU1YK2RrSjJQd2pUPC9zYW1sMjpOYW1lSUQ%2BPHNhbWwyOlN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48c2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgQWRkcmVzcz0iOTcuMTEzLjEzOC4xMjUiIEluUmVzcG9uc2VUbz0iT05FTE9HSU5fMDE2MDhmNzY3YTQ4NWExMmQ2MTFmYjhkZWUyYmYwOGViZTQyZWJiNiIgTm90T25PckFmdGVyPSIyMDE5LTAyLTA0VDE4OjE2OjIyLjA2M1oiIFJlY2lwaWVudD0iaHR0cHM6Ly9zYW1sZGVtby5pYW1kZXYucy51dy5lZHUvc2FtbC9sb2dpbiIvPjwvc2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbj48L3NhbWwyOlN1YmplY3Q%2BPHNhbWwyOkNvbmRpdGlvbnMgTm90QmVmb3JlPSIyMDE5LTAyLTA0VDE4OjExOjIyLjA1NFoiIE5vdE9uT3JBZnRlcj0iMjAxOS0wMi0wNFQxODoxNjoyMi4wNTRaIj48c2FtbDI6QXVkaWVuY2VSZXN0cmljdGlvbj48c2FtbDI6QXVkaWVuY2U%2BaHR0cHM6Ly9zYW1sZGVtby5pYW1kZXYucy51dy5lZHUvc2FtbDwvc2FtbDI6QXVkaWVuY2U%2BPC9zYW1sMjpBdWRpZW5jZVJlc3RyaWN0aW9uPjwvc2FtbDI6Q29uZGl0aW9ucz48c2FtbDI6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDE5LTAyLTA0VDE4OjExOjIxLjY5M1oiIFNlc3Npb25JbmRleD0iX2JhM2QxYmY1ZjU2ZmFhZWNhYjIwNzUwNDk0NWY1MjAwIj48c2FtbDI6U3ViamVjdExvY2FsaXR5IEFkZHJlc3M9Ijk3LjExMy4xMzguMTI1Ii8%2BPHNhbWwyOkF1dGhuQ29udGV4dD48c2FtbDI6QXV0aG5Db250ZXh0Q2xhc3NSZWY%2BdXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6UGFzc3dvcmRQcm90ZWN0ZWRUcmFuc3BvcnQ8L3NhbWwyOkF1dGhuQ29udGV4dENsYXNzUmVmPjwvc2FtbDI6QXV0aG5Db250ZXh0Pjwvc2FtbDI6QXV0aG5TdGF0ZW1lbnQ%2BPHNhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iaXNNZW1iZXJPZiIgTmFtZT0idXJuOm9pZDoxLjMuNi4xLjQuMS41OTIzLjEuNS4xLjEiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzZDpzdHJpbmciPnVybjptYWNlOndhc2hpbmd0b24uZWR1Omdyb3Vwczp1X2pwZl90ZXN0LXNhbWw8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDI6QXR0cmlidXRlPjxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJ1aWQiIE5hbWU9InVybjpvaWQ6MC45LjIzNDIuMTkyMDAzMDAuMTAwLjEuMSIgTmFtZUZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmF0dHJuYW1lLWZvcm1hdDp1cmkiPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHNkOnN0cmluZyI%2BaWR0ZXN0NTU8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDI6QXR0cmlidXRlPjxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJlZHVQZXJzb25BZmZpbGlhdGlvbiIgTmFtZT0idXJuOm9pZDoxLjMuNi4xLjQuMS41OTIzLjEuMS4xLjEiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzZDpzdHJpbmciPnN0dWRlbnQ8L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHNkOnN0cmluZyI%2BbWVtYmVyPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48L3NhbWwyOkF0dHJpYnV0ZT48c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iZWR1UGVyc29uUHJpbmNpcGFsTmFtZSIgTmFtZT0idXJuOm9pZDoxLjMuNi4xLjQuMS41OTIzLjEuMS4xLjYiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzZDpzdHJpbmciPmlkdGVzdDU1QHdhc2hpbmd0b24uZWR1PC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48L3NhbWwyOkF0dHJpYnV0ZT48c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iZWR1UGVyc29uU2NvcGVkQWZmaWxpYXRpb24iIE5hbWU9InVybjpvaWQ6MS4zLjYuMS40LjEuNTkyMy4xLjEuMS45IiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI%2BPHNhbWwyOkF0dHJpYnV0ZVZhbHVlIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIHhzaTp0eXBlPSJ4c2Q6c3RyaW5nIj5zdHVkZW50QHdhc2hpbmd0b24uZWR1PC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzZDpzdHJpbmciPm1lbWJlckB3YXNoaW5ndG9uLmVkdTwvc2FtbDI6QXR0cmlidXRlVmFsdWU%2BPC9zYW1sMjpBdHRyaWJ1dGU%2BPC9zYW1sMjpBdHRyaWJ1dGVTdGF0ZW1lbnQ%2BPC9zYW1sMjpBc3NlcnRpb24%2BPC9zYW1sMnA6UmVzcG9uc2U%2B

tests/test_auth.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import uw_saml2
2+
from onelogin.saml2.utils import OneLogin_Saml2_Utils
3+
import pytest
4+
import mock
5+
import os
6+
import urllib.parse
7+
BASEDIR = os.path.abspath(os.path.dirname(__file__))
8+
9+
10+
def test_login_redirect(mock_time_and_id):
11+
"""Fix the time and check that the request still looks the same."""
12+
entity_id = 'https://example.org/saml'
13+
acs_url = 'https://example.org/saml/login'
14+
url = uw_saml2.login_redirect(entity_id=entity_id, acs_url=acs_url,
15+
return_to='/foo')
16+
expected_url = (
17+
'https://idp.u.washington.edu/idp/profile/SAML2/Redirect/SSO?'
18+
'SAMLRequest=fVPBbqMwEL33KxD34ECjrdZKkGiiaiN1NwjoHvbm2pPEkrFZe9xk%2F35'
19+
'tmjap1IYL0pv3hvdmhrljvRpo5XGvG%2FjrweFNkhx7pR0dS4vUW00Nc9JRzXpwFDltq5'
20+
'%2BPtMimdLAGDTcq%2FSC6rmHOgUVpdBStV4v0YbO5r5q8uI3Ab7Au1BZpoI4E5zystUO'
21+
'mMYDT%2FPtkWkymsy6%2Fo7NvtJj9iaxV8C01w1G5RxwcJUSKIfPZgbm91Ds0OgPhI0iC'
22+
'661UQKKlgjQgpAWOpG03sVd9ynQvtQjC62GeX0mO%2Fui6elJv2i62qN4iLo12vgfbgn2'
23+
'RHJ6ax7M9OLJ%2BUJAZuyNxakSZndRpGfRJMo8IHcPb8ivFnFyyzrqB%2FgpG16vaKMn'
24+
'%2FjXh8HoztGX6dJ8%2FyEZFish2p1Gs3AJdbCSJ9b1MpZQ5LCwxhkaL1kCbkw8dPdwRi'
25+
'vKowAoQjJkvTD8xKFzcUgnA8JT2nvaQvVTiTBrbl1UvilEdegOvwOhgr4vLCLkF0lgXzx'
26+
'uJpSJ82f3VNrtgub97Kl79I%2BR8%3D&RelayState=%2Ffoo')
27+
assert url == expected_url
28+
29+
30+
def test_process_response(mock_time_and_id):
31+
"""
32+
Take a once-valid SAML Response, mock the time to when it was valid,
33+
validate the response, and compare the attributes.
34+
"""
35+
with open(os.path.join(BASEDIR, 'samlresponse.txt')) as fd:
36+
post = dict(urllib.parse.parse_qsl(fd.read()))
37+
# set a time when this response was still valid
38+
mock_time_and_id.return_value = 1549304000
39+
entity_id = 'https://samldemo.iamdev.s.uw.edu/saml'
40+
acs_url = 'https://samldemo.iamdev.s.uw.edu/saml/login'
41+
attributes = uw_saml2.process_response(post, entity_id=entity_id,
42+
acs_url=acs_url)
43+
expected_attributes = {
44+
'affiliations': ['student', 'member'],
45+
'eppn': 'idtest55@washington.edu',
46+
'groups': ['u_jpf_test-saml'],
47+
'scoped_affiliations': ['student@washington.edu',
48+
'member@washington.edu'],
49+
'two_factor': False,
50+
'uwnetid': 'idtest55'
51+
}
52+
assert attributes == expected_attributes
53+
54+
55+
@pytest.fixture
56+
def mock_time_and_id(monkeypatch):
57+
"""Mock the two things guaranteed to be nondeterministic - date and id."""
58+
utils = 'onelogin.saml2.utils.OneLogin_Saml2_Utils'
59+
mock_time = mock.MagicMock()
60+
mock_time.return_value = 1549302384
61+
monkeypatch.setattr(f'{utils}.now', mock_time)
62+
monkeypatch.setattr(f'{utils}.generate_unique_id', lambda: 'FOOBAR123')
63+
return mock_time

uw_saml2/auth.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def login_redirect(entity_id=None, acs_url=None, return_to='/',
1616
acs_url - The SP endpoint the Identity Provider will post back to, known
1717
technically as the Assertion Consumer Service. This endpoint along
1818
with the Entity Id are registered with the IdP.
19+
return_to - The URL to send back to after authentication. This is known
20+
in a SAML request as 'RelayState'.
1921
force_authn - whether to force authentication even if the user has already
2022
authenticated against the IdP.
2123
idp - which IdP to use, defaulting to UW's IdP. Other IdPs of type

uw_saml2/idp/attribute.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
"""Attribute mappings."""
22

3+
34
def map(attribute_data, idp):
5+
"""
6+
Map attribute data from an IdP's SAML Response to values that are
7+
easier to consume.
8+
"""
49
attribute_map = {idp.id_attribute: idp.mapped_id_attribute}
510
attribute_map.update(idp.attribute_map)
611
for key, values in attribute_data.items():
@@ -11,6 +16,7 @@ def map(attribute_data, idp):
1116
if value is not None:
1217
yield attribute.name, value
1318

19+
1420
class Attribute:
1521
"""Base class for mapping a list of attribute values."""
1622
def __init__(self, name):

uw_saml2/idp/federated.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Federated Identity Providers."""
22
from . import IdpConfig, attribute
33

4+
45
class CascadiaStudentIdp(IdpConfig):
56
entity_id = 'https://idp.cascadia.edu/idp/shibboleth'
67
sso_url = 'https://idp.student.cascadia.edu/idp/profile/SAML2/Redirect/SSO'

uw_saml2/sp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def __init__(self, entity_id=None, acs_url=None):
1616
self.entity_id = entity_id
1717
if acs_url:
1818
self.acs_url = acs_url
19-
19+
2020
def request(self, post=None):
2121
post = post or {}
2222
parsed_url = urlparse(self.acs_url)

0 commit comments

Comments
 (0)