Skip to content
This repository was archived by the owner on Jan 26, 2026. It is now read-only.

Commit 803b465

Browse files
authored
Various fixes (#95)
* Fix example_setup with docker * xml validation local_metadata in form * refresh metadata on changed field content * update version number for fix release * select_related in admin
1 parent d13b6af commit 803b465

File tree

12 files changed

+59
-19
lines changed

12 files changed

+59
-19
lines changed

CHANGELOG.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# Changelog
22

3-
## [0.7.0] - 2020-04-xx
4-
5-
*In development, *
3+
## [0.7.2] - 2020-04-14
64

75
Many thanks for major contributions (especially on the testing front where the project was lacking) from [Amertz08](https://github.com/Amertz08) and [askvortsov1](https://github.com/askvortsov1)
86

@@ -12,7 +10,7 @@ Many thanks for major contributions (especially on the testing front where the p
1210
- Django 3.0 is added to the tests matrix. We currently are doing Python 3.6, 3.7, 3.8 and Django 2.2, 3.0.
1311

1412
### Removed
15-
- Python 3.5
13+
- Dropped Python 3.5.
1614
- Django 2.0 and 2.1 as they are no longer officially supported Django versions.
1715

1816

djangosaml2idp/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.7.0'
1+
__version__ = '0.7.2'

djangosaml2idp/admin.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,4 @@ class ServiceProviderAdmin(admin.ModelAdmin):
3131
class PersistentIdAdmin(admin.ModelAdmin):
3232
list_filter = ['sp', ]
3333
list_display = ['user', 'sp', 'persistent_id']
34-
35-
def get_queryset(self, request):
36-
return super().get_queryset(request).select_related('user', 'sp')
34+
select_related = ['user', 'sp']

djangosaml2idp/forms.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from .models import ServiceProvider
88
from .processors import instantiate_processor, validate_processor_path
9+
from .utils import validate_metadata
910

1011
boolean_form_select_choices = ((None, _('--------')), (True, _('Yes')), (False, _('No')))
1112

@@ -39,6 +40,11 @@ def clean__processor(self):
3940
validate_processor_path(value)
4041
return value
4142

43+
def clean_local_metadata(self):
44+
value = self.cleaned_data['local_metadata']
45+
validate_metadata(value)
46+
return value
47+
4248
def clean(self):
4349
cleaned_data = super().clean()
4450

djangosaml2idp/migrations/0001_initial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Migration(migrations.Migration):
1818
('dt_created', models.DateTimeField(auto_now_add=True, verbose_name='Created at')),
1919
('dt_updated', models.DateTimeField(auto_now=True, null=True, verbose_name='Updated at')),
2020
('entity_id', models.CharField(max_length=255, unique=True, verbose_name='Entity ID')),
21-
('pretty_name', models.CharField(blank=True, help_text='For display purposes, can be empty', max_length=256, verbose_name='Pretty Name')),
21+
('pretty_name', models.CharField(blank=True, help_text='For display purposes, can be empty', max_length=255, verbose_name='Pretty Name')),
2222
('description', models.TextField(blank=True, verbose_name='Description')),
2323
('metadata_expiration_dt', models.DateTimeField(verbose_name='Metadata valid until')),
2424
('remote_metadata_url', models.CharField(blank=True, help_text='If set, metadata will be fetched upon saving into the local metadata xml field, and automatically be refreshed after the expiration timestamp.', max_length=512, verbose_name='Remote metadata URL')),

djangosaml2idp/models.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,25 @@ class ServiceProvider(models.Model):
5151
remote_metadata_url = models.CharField(verbose_name='Remote metadata URL', max_length=512, blank=True, help_text='If set, metadata will be fetched upon saving into the local metadata xml field, and automatically be refreshed after the expiration timestamp.')
5252
local_metadata = models.TextField(verbose_name='Local Metadata XML', blank=True, help_text='XML containing the metadata')
5353

54+
@classmethod
55+
def from_db(cls, db, field_names, values):
56+
instance = super().from_db(db, field_names, values)
57+
instance._loaded_db_values = dict(zip(field_names, values))
58+
return instance
59+
60+
def field_value_changed(self, field_name: str) -> bool:
61+
''' Returns whether the current value of a field is changed vs what was loaded from the db. '''
62+
current_value = getattr(self, field_name)
63+
return current_value != getattr(self, '_loaded_db_values', {}).get(field_name, current_value)
64+
5465
def _should_refresh(self) -> bool:
5566
''' Returns whether or not a refresh operation is necessary.
5667
'''
57-
# - Data was not fetched ever before, so local_metadata is empty
58-
if not self.local_metadata:
68+
# - Data was not fetched ever before, so local_metadata is empty, or local_metadata has been changed from what it was in the db before
69+
if not self.local_metadata or self.field_value_changed('local_metadata'):
70+
return True
71+
# - The remote url has been updated
72+
if self.field_value_changed('remote_metadata_url'):
5973
return True
6074
# - The expiration timestamp is not set, or it is expired
6175
if not self.metadata_expiration_dt or now() > self.metadata_expiration_dt:
@@ -104,7 +118,7 @@ def refresh_metadata(self, force_refresh: bool = False) -> bool:
104118
if self.remote_metadata_url:
105119
return self._refresh_from_remote()
106120

107-
if (not self.metadata_expiration_dt) or (now() > self.metadata_expiration_dt):
121+
if force_refresh or (not self.metadata_expiration_dt) or (now() > self.metadata_expiration_dt) or self.field_value_changed('local_metadata'):
108122
return self._refresh_from_local()
109123

110124
raise Exception('Uncaught case of refresh_metadata')

example_setup/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ services:
2020
stdin_open: true
2121
tty: true
2222
volumes:
23-
- ./idp:/app
24-
working_dir: /app
23+
- ..:/app
24+
working_dir: /app/example_setup/idp
2525
ports:
2626
- "9000:9000"

example_setup/idp/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.6.6-alpine3.7
1+
FROM python:3.8-alpine
22

33
RUN apk add --update \
44
build-base libffi-dev openssl-dev \

example_setup/idp/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
django<3.0
1+
django~=3.0
22
pysaml2==5.0.0
33
arrow
44
pytz

example_setup/sp/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:3.6.6-alpine3.7
1+
FROM python:3.8-alpine
22

33
RUN apk add --update \
44
build-base libffi-dev openssl-dev \

0 commit comments

Comments
 (0)