Skip to content

Commit

Permalink
coverage 75%
Browse files Browse the repository at this point in the history
  • Loading branch information
peppelinux committed Jan 6, 2020
1 parent 2bb20c4 commit 50e83ef
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 38 deletions.
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,30 @@ uniAuth, as a SAML2 IDP, is based on [pysaml2](https://github.com/IdentityPython

## Implementation specific Features

- no restart is needed on new matadata store or SP;
- Full Internazionalization support (i18n);
- Interactive Metadata Store definitions through the Admin Backend UI;
- Interactive ServiceProvider Federation through the Admin Backend UI;
- Interactive ServiceProvider definition through the Admin Backend UI;
- Customizable Template and style based on [AGID guidelines](https://www.agid.gov.it/it/argomenti/linee-guida-design-pa);
- MetadataStore and SP validations on save, to prevent faulty configurations in production environment;
- Optional and quite granular Agreement Screen;
- Configurable digest algorithm and salt for Computed NameID;
- Many configurable options, for every SP we can decide:
- enable/disable explicitally;
- signature and digest algorithms;
- attributes release policies;
- attribute rewrite and creation, fully configurable AttributeProcessors per SP, every aspect of attribute release can be customized from schratch;
- attributes release (force a set or release what requested by sp);
- attribute rewrite and creation, fully configurable AttributeProcessors per SP, every aspect of attribute release can be customized from scratch;
- agreement screen message, availability, data consent form.
- Configurable log rotation through uwsgi;
- Importable StoredPersistentID for each user, from migrations from another IDP;
- An optional LDAP web manager with a configurable app (`ldap_peoples`);
- Multiple LDAP sources though `pyMultiLDAP <https://github.com/peppelinux/pyMultiLDAP>`__;
- An optional LDAP web manager with a configurable app (`ldap_peoples`) through `django-ldap-academia-ou-manager <https://github.com/peppelinux/django-ldap-academia-ou-manager>`__;
- Multiple LDAP sources through `pyMultiLDAP <https://github.com/peppelinux/pyMultiLDAP>`__;
- Multifactor support, as originally available in djangosaml2idp;
- Detailed logs.


## Characteristics

uniauth will let us configure metadata store and federate new Service Providers directly from the Admin backend interface, via Web.
uniAuth permit us to configure metadata store and federate new Service Providers directly from the Admin backend interface, via Web.
See [Official Documentation at readthedocs](https://uniauth.readthedocs.io/en/latest/index.html) for usage specifications and advanced topics.

---
Expand All @@ -61,12 +62,13 @@ See [Official Documentation at readthedocs](https://uniauth.readthedocs.io/en/la

![Alt text](documentation/contents/sp_search.png)
![Alt text](documentation/contents/sp.png)
*Define a new SP. If `SAML_DISALLOW_UNDEFINED_SP` is True this configuration is mandatory, otherwise just store the sp metadata.*
*Define a new SP. If `SAML_DISALLOW_UNDEFINED_SP` is True this configuration is mandatory, otherwise only the sp metadata is needed.*

## Tests

````
pip install -r requirements-dev.txt
python3 tests/ldapd.py
pytest tests/ -x --pdb
````

Expand All @@ -77,7 +79,7 @@ coverage run -m pytest tests/
coverage report -m
````

A test LDAP server is available in `tests/ldaptord.py`.
A test LDAP server is available in `tests/ldapd.py`.
You can run it manually and test a query with `ldapsearch`.

```
Expand All @@ -87,6 +89,9 @@ ldapsearch -H ldap://localhost:3899 -b "dc=testunical,dc=it" -x uid=mario
ldapsearch -H ldap://localhost:3899 -b "dc=testunical,dc=it" uid=mario -D "uid=mario,ou=people,dc=testunical,dc=it" -w cimpa12
```

TODO:
- test code regarding required attributes from sp, views: 292-327
- test logout, views: 858-914

## Contribute

Expand Down
20 changes: 10 additions & 10 deletions documentation/contents/general_description.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ uniAuth, as a SAML2 IDP, is based on `pysaml2 <https://github.com/IdentityPython
Implementation specific Features
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

- no restart is needed on new matadata store or SP;
- Full Internazionalization support (i18n);
- Interactive Metadata Store definitions through the Admin Backend UI;
- MetadataStore supports local file (upload), local folder, remote url and MDQ service;
- Interactive ServiceProvider Federation through the Admin Backend UI;
- Customizable Template and style based on `AGID guidelines <https://www.agid.gov.it/it/argomenti/linee-guida-design-pa>`__;
- Interactive ServiceProvider definition through the Admin Backend UI;
- Customizable Template and style based on [AGID guidelines](https://www.agid.gov.it/it/argomenti/linee-guida-design-pa);
- MetadataStore and SP validations on save, to prevent faulty configurations in production environment;
- Optional and quite granular Agreement Screen;
- Configurable digest algorithm and salt for Computed NameID;
- Many configurable options, for every SP we can decide:
- enable/disable explicitally;
- signature and digest algorithms;
- attributes release policies;
- attribute rewrite and creation, fully configurable AttributeProcessors per SP, every aspect of attribute release can be customized from schratch;
- attributes release (force a set or release what requested by sp);
- attribute rewrite and creation, fully configurable AttributeProcessors per SP, every aspect of attribute release can be customized from scratch;
- agreement screen message, availability, data consent form.
- Configurable log rotation through uwsgi;
- Importable StoredPersistentID for each user, for migrations from other IDP;
- An optional LDAP web manager with a configurable app (`ldap_peoples`);
- Multiple LDAP sources though `pyMultiLDAP <https://github.com/peppelinux/pyMultiLDAP>`__;
- Multifactor support, as available in djangosaml2idp;
- Importable StoredPersistentID for each user, from migrations from another IDP;
- An optional LDAP web manager with a configurable app (`ldap_peoples`) through `django-ldap-academia-ou-manager <https://github.com/peppelinux/django-ldap-academia-ou-manager>`__;
- Multiple LDAP sources through `pyMultiLDAP <https://github.com/peppelinux/pyMultiLDAP>`__;
- Multifactor support, as originally available in djangosaml2idp;
- Detailed logs.
4 changes: 2 additions & 2 deletions idp/processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class GroupProcessor(BaseProcessor):
"""
group = "ExampleGroup"

def has_access(self, user):
def has_access(self, user): # pragma: no cover
return user.is_superuser or \
user.is_staff or \
user.groups.filter(name=self.group).exists()
Expand Down Expand Up @@ -92,7 +92,7 @@ def get_identity(self, user):

# otherwise do another query ...
identity = None
for lc in settings.LDAP_CONNECTIONS:
for lc in settings.LDAP_CONNECTIONS: # pragma: no coverage
ldapfilter = '(uid={})'.format(user.username)
logging.debug("Processor {} searches for {} in {}".format(self.__class__,
user.username,
Expand Down
2 changes: 1 addition & 1 deletion tests/settingsldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
'givenName',
'sn',
'eduPersonScopedAffiliation',
'schacPersonalUniqueId',
'schacPersonalUniqueID',
'schacPersonalUniqueCode'
]

Expand Down
26 changes: 26 additions & 0 deletions tests/test_05_ldap_datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,29 @@ def test_valid_form(self):
saml_resp = re.findall(samlresponse_form_regexp,
login_response.content.decode())
assert saml_resp

# login again to update existing user on db
login_response = self.client.post(login_url,
data=self.login_data, follow=True)

# test a disabled user
#user = get_user_model().objects.last()
#user.is_active = 0
#user.save()
#login_response = self.client.post(login_url,
#data=self.login_data, follow=True)

def test_invalid_form(self):
url, data = self._get_sp_authn_request()
response = self.client.post(url, data, follow=True)
login_data = {'username':'mario', 'password':'erewr'}
login_response = self.client.post(login_url,
data=login_data,
follow=True)
assert 'is invalid' in login_response.content.decode()

login_data = {'username':'dsfhdsjkfh', 'password':'erewr'}
login_response = self.client.post(login_url,
data=login_data,
follow=True)
assert 'is invalid' in login_response.content.decode()
41 changes: 25 additions & 16 deletions uniauth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ def sso_entry(request, binding='POST'):
sp = get_idp_sp_config().get(sp_id, {})

mduui = {}
if not IDP.config.metadata.service(sp_id,
"spsso_descriptor",
'assertion_consumer_service'):
msg = _("{} is not present in any Metadata").format(sp_id)
raise MetadataNotFound(msg)

try:
mduui = IDP.metadata[sp_id]['spsso_descriptor'][0]\
.get('extensions', {}).get('extension_elements', [{}])[0]
Expand Down Expand Up @@ -240,23 +246,26 @@ def set_sp(self, sp_entity_id):
sp = ServiceProvider.objects.filter(entity_id = sp_entity_id).first()

if not self.sp['config']:
if settings.SAML_DISALLOW_UNDEFINED_SP:
msg = _("No config for SP {} was defined in SAML_IDP_SPCONFIG")
raise ImproperlyConfigured(msg.format(sp_entity_id))
else:
if not self.IDP.config.metadata.service(sp_entity_id,
"spsso_descriptor",
'assertion_consumer_service'):
msg = _("{} is not present in any Metadata").format(sp_entity_id)
raise MetadataNotFound(msg)

self.sp['config'] = copy.deepcopy(settings.DEFAULT_SPCONFIG)

self.sp['config']['display_name'] = sp_entity_id
self.sp['config']['display_description'] = ''
self.sp['config']['force_attribute_release'] = False
# already checked in sso_init
#if settings.SAML_DISALLOW_UNDEFINED_SP:
#msg = _("No config for SP {} was defined in SAML_IDP_SPCONFIG")
#raise ImproperlyConfigured(msg.format(sp_entity_id))
#else:
#if not self.IDP.config.metadata.service(sp_entity_id,
#"spsso_descriptor",
#'assertion_consumer_service'):
#msg = _("{} is not present in any Metadata").format(sp_entity_id)
#raise MetadataNotFound(msg)

self.sp['config'] = copy.deepcopy(settings.DEFAULT_SPCONFIG)

# TODO: get these information from sp's metadata
self.sp['config']['display_name'] = sp_entity_id
self.sp['config']['display_description'] = ''
self.sp['config']['force_attribute_release'] = False

if not sp:
# TODO: get these information from sp's metadata
sp = ServiceProvider.objects.create(entity_id = sp_entity_id,
display_name = sp_entity_id,
is_valid=True,
Expand All @@ -271,7 +280,7 @@ def set_sp(self, sp_entity_id):
sp.save()

if self.sp['config']['force_attribute_release']:
# IdP ignores what SP requests for and release what it wants
# IdP ignores what SP requests for and release what you configured
return

# check if SP asks for required attributes
Expand Down

0 comments on commit 50e83ef

Please sign in to comment.