Projet

Général

Profil

0002-WIP-federation-file-lazy-provider-loading-19396.patch

Paul Marillonnet, 18 avril 2018 15:51

Télécharger (14,1 ko)

Voir les différences:

Subject: [PATCH 2/2] WIP federation file: lazy provider loading (#19396)

 mellon/utils.py     | 13 ----------
 mellon/views.py     | 58 +++++++++++++++++++++++++++++++++++++++++----
 tests/test_utils.py | 46 ++++++++++++++++++-----------------
 3 files changed, 77 insertions(+), 40 deletions(-)
mellon/utils.py
76 76
            password = key[1]
77 77
            key = key[0]
78 78
        server.setEncryptionPrivateKeyWithPassword(key, password)
79
    for idp in get_idps():
80
        try:
81
            metadata = idp.get('METADATA')
82
            if idp_metadata_is_file(metadata):
83
                with open(metadata, 'r') as f:
84
                    metadata = f.read()
85
            server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
86
        except lasso.Error, e:
87
            logger.error(u'bad metadata in idp %r', idp)
88
            logger.debug(u'lasso error: %s', e)
89
        except IOError, e:
90
            logger.warning('No such metadata file: %r', metadata)
91
            continue
92 79
    return server
93 80

  
94 81

  
mellon/views.py
17 17
from django.db import transaction
18 18
from django.utils.translation import ugettext as _
19 19

  
20
from . import app_settings, utils
20
from . import app_settings, utils, federation_utils
21 21

  
22 22

  
23 23
lasso.setFlag('thin-sessions')
......
108 108
        idp_message = None
109 109
        status_codes = []
110 110
        # prevent null characters in SAMLResponse
111
        import pdb; pdb.set_trace()
111 112
        try:
112 113
            login.processAuthnResponseMsg(request.POST['SAMLResponse'])
113 114
            login.acceptSso()
......
120 121
                lasso.ProfileStatusNotSuccessError,
121 122
                lasso.ProfileRequestDeniedError):
122 123
            self.show_message_status_is_not_success(login, 'SAML authentication failed')
124
        except (lasso.ProfileUnknownProviderError,
125
                lasso.ServerProviderNotFoundError):
126
            try:
127
                metadata = utils.get_idp(login.remoteProviderId)
128
                if federation_utils.idp_metadata_is_file(metadata):
129
                    with open(metadata, 'r') as f:
130
                        metadata = f.read()
131
                server = utils.create_server(request)
132
                server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
133
            except lasso.Error as e:
134
                return HttpResponseBadRequest('error processing the authentication response: %r' % e)
123 135
        except lasso.Error as e:
124 136
            return HttpResponseBadRequest('error processing the authentication response: %r' % e)
125 137
        else:
......
240 252
        self.profile = login = utils.create_login(request)
241 253
        if relay_state and utils.is_nonnull(relay_state):
242 254
            login.msgRelayState = relay_state
255
        import pdb; pdb.set_trace()
243 256
        try:
244 257
            login.initRequest(message, method)
245 258
        except lasso.ProfileInvalidArtifactError:
246 259
            self.log.warning(u'artifact is malformed %r', artifact)
247 260
            return HttpResponseBadRequest(u'artifact is malformed %r' % artifact)
248
        except lasso.ServerProviderNotFoundError:
249
            self.log.warning('no entity id found for artifact %s', artifact)
250
            return HttpResponseBadRequest(
251
                'no entity id found for this artifact %r' % artifact)
261
        except (lasso.ProfileUnknownProviderError,
262
                lasso.ServerProviderNotFoundError,
263
                lasso.ProfileInvalidArtifactError):
264
            try:
265
                idp = utils.get_idp(login.remoteProviderId)
266
                metadata = idp.get('METADATA')
267
                if federation_utils.idp_metadata_is_file(metadata):
268
                    with open(metadata, 'r') as f:
269
                        metadata = f.read()
270
                server = utils.create_server(request)
271
                server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
272
            except lasso.Error as e:
273
                self.log.warning('no entity id found for artifact %s', artifact)
274
                return HttpResponseBadRequest(
275
                    'no entity id found for this artifact %r' % artifact)
252 276
        idp = utils.get_idp(login.remoteProviderId)
253 277
        if not idp:
254 278
            self.log.warning('entity id %r is unknown', login.remoteProviderId)
......
395 419
    def idp_logout(self, request):
396 420
        '''Handle logout request emitted by the IdP'''
397 421
        self.profile = logout = utils.create_logout(request)
422
        import pdb; pdb.set_trace()
398 423
        try:
399 424
            logout.processRequestMsg(request.META['QUERY_STRING'])
425
        except (lasso.ProfileUnknownProviderError,
426
                lasso.ServerProviderNotFoundError):
427
            try:
428
                idp_metadata = utils.get_idp(logout.remoteProviderId)
429
                if federation_utils.idp_metadata_is_file(idp_metadata):
430
                    with open(metadata, 'r') as f:
431
                        metadata = f.read()
432
                server = utils.create_server(request)
433
                server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
434
            except lasso.Error as e:
435
                return HttpResponseBadRequest('error processing logout request: %r' % e)
400 436
        except lasso.Error as e:
401 437
            return HttpResponseBadRequest('error processing logout request: %r' % e)
402 438
        try:
......
454 490
        # that a concurrent SSO happened in the meantime, so we do another
455 491
        # logout to make sure.
456 492
        auth.logout(request)
493
        import pdb; pdb.set_trace()
457 494
        try:
458 495
            logout.processResponseMsg(request.META['QUERY_STRING'])
459 496
        except lasso.ProfileStatusNotSuccessError:
460 497
            self.show_message_status_is_not_success(logout, 'SAML logout failed')
461 498
        except lasso.LogoutPartialLogoutError:
462 499
            self.log.warning('partial logout')
500
        except (lasso.ProfileUnknownProviderError,
501
                lasso.ServerProviderNotFoundError):
502
            try:
503
                idp_metadata = utils.get_idp(logout.remoteProviderId)
504
                if federation_utils.idp_metadata_is_file(idp_metadata):
505
                    with open(metadata, 'r') as f:
506
                        metadata = f.read()
507
                server = utils.create_server(request)
508
                server.addProviderFromBuffer(lasso.PROVIDER_ROLE_IDP, metadata)
509
            except lasso.Error as e:
510
                return HttpResponseBadRequest('error processing a logout request: %s' % e)
463 511
        except lasso.Error as e:
464 512
            self.log.warning('unable to process a logout response: %s', e)
465 513
            return HttpResponseRedirect(resolve_url(settings.LOGIN_REDIRECT_URL))
tests/test_utils.py
17 17
        html_response, dummy_md_response
18 18

  
19 19

  
20
def test_create_server_connection_error(mocker, rf, private_settings, caplog):
20
def test_create_server_connection_error_lazy(mocker, rf, private_settings, caplog):
21 21
    mocker.patch('requests.get',
22 22
                 side_effect=requests.exceptions.ConnectionError('connection error'))
23 23
    private_settings.MELLON_IDENTITY_PROVIDERS = [
......
27 27
    ]
28 28
    request = rf.get('/')
29 29
    create_server(request)
30
    assert 'connection error' in caplog.text
30
    assert 'connection error' not in caplog.text
31 31

  
32 32

  
33
def test_create_server_internal_server_error(mocker, rf, private_settings, caplog):
33
def test_create_server_internal_server_error_lazy(mocker, rf, private_settings, caplog):
34 34
    private_settings.MELLON_IDENTITY_PROVIDERS = [
35 35
        {
36 36
            'METADATA_URL': 'http://example.com/metadata',
......
40 40
    assert not 'failed with error' in caplog.text
41 41
    with HTTMock(error_500):
42 42
        create_server(request)
43
    assert 'failed with error' in caplog.text
43
    assert 'failed with error' not in caplog.text
44 44

  
45 45

  
46
def test_load_federation_file(mocker, rf, private_settings, caplog, tmpdir):
46
def test_load_federation_file_lazy(mocker, rf, private_settings, caplog, tmpdir):
47 47
    private_settings.MELLON_FEDERATIONS = [
48 48
            {'FEDERATION': 'tests/federation-sample.xml'},
49 49
    ]
......
51 51
    assert 'failed with error' not in caplog.text
52 52
    with HTTMock(html_response):
53 53
        server = create_server(request)
54
    assert len(server.providers) == 5
54
    assert len(server.providers) == 0
55 55

  
56 56

  
57
def test_load_federation_url(mocker, rf, private_settings, caplog, tmpdir):
57
def test_load_federation_url_lazy(mocker, rf, private_settings, caplog, tmpdir):
58 58
    private_settings.MELLON_FEDERATIONS = [
59 59
            {'FEDERATION': 'https://dummy.server/metadata.xml'},
60 60
    ]
......
62 62
    assert 'failed with error' not in caplog.text
63 63
    with HTTMock(dummy_md_response):
64 64
        server = create_server(request)
65
    assert len(server.providers) == 3
65
    assert len(server.providers) == 0
66 66

  
67 67

  
68
def test_federation_parameters(mocker, rf, private_settings, caplog, tmpdir):
68
def test_federation_parameters_lazy(mocker, rf, private_settings, caplog, tmpdir):
69 69
    private_settings.MELLON_FEDERATIONS = [{
70 70
            'FEDERATION': 'tests/federation-sample.xml',
71 71
            'VERIFY_SSL_CERTIFICATE': False,
......
76 76
    assert 'failed with error' not in caplog.text
77 77
    with HTTMock(html_response):
78 78
        server = create_server(request)
79
    assert len(server.providers) == 5
79
    assert len(server.providers) == 0
80
    """
80 81
    for entity_id in server.providers.keys():
81 82
        idp = get_idp(entity_id)
82 83
        assert idp
83 84
        assert idp['VERIFY_SSL_CERTIFICATE'] is False
84 85
        assert idp['ERROR_REDIRECT_AFTER_TIMEOUT'] == 150
85 86
        assert idp['PROVISION'] is True
87
    """
86 88

  
87 89

  
88
def test_create_server_invalid_metadata(mocker, rf, private_settings, caplog):
90
def test_create_server_invalid_metadata_lazy(mocker, rf, private_settings, caplog):
89 91
    caplog.set_level(logging.DEBUG)
90 92
    private_settings.MELLON_IDENTITY_PROVIDERS = [
91 93
        {
......
96 98
    assert not 'failed with error' in caplog.text
97 99
    with HTTMock(error_500):
98 100
        create_server(request)
99
    assert len(caplog.records) == 4
100
    assert re.search('METADATA.*is invalid|bad metadata in idp', caplog.text)
101
    assert len(caplog.records) == 0
102
    assert not re.search('METADATA.*is invalid|bad metadata in idp', caplog.text)
101 103

  
102 104

  
103
def test_create_server_invalid_metadata_file(mocker, rf, private_settings, caplog):
105
def test_create_server_invalid_metadata_file_lazy(mocker, rf, private_settings, caplog):
104 106
    private_settings.MELLON_IDENTITY_PROVIDERS = [
105 107
        {
106 108
            'METADATA': '/xxx',
......
114 116
    assert len(server.providers) == 0
115 117

  
116 118

  
117
def test_create_server_good_metadata_file(mocker, rf, private_settings, caplog):
119
def test_create_server_good_metadata_file_lazy(mocker, rf, private_settings, caplog):
118 120
    private_settings.MELLON_IDENTITY_PROVIDERS = [
119 121
        {
120 122
            'METADATA': './tests/metadata.xml',
......
124 126
    with HTTMock(html_response):
125 127
        server = create_server(request)
126 128
    assert 'ERROR' not in caplog.text
127
    assert len(server.providers) == 1
129
    assert len(server.providers) == 0
128 130

  
129 131

  
130
def test_create_server_good_metadata(mocker, rf, private_settings, caplog):
132
def test_create_server_good_metadata_lazy(mocker, rf, private_settings, caplog):
131 133
    private_settings.MELLON_IDENTITY_PROVIDERS = [
132 134
        {
133 135
            'METADATA': file('tests/metadata.xml').read(),
......
137 139
    assert not 'failed with error' in caplog.text
138 140
    server = create_server(request)
139 141
    assert 'ERROR' not in caplog.text
140
    assert len(server.providers) == 1
142
    assert len(server.providers) == 0
141 143

  
142 144

  
143
def test_create_server_invalid_idp_dict(mocker, rf, private_settings, caplog):
145
def test_create_server_invalid_idp_dict_lazy(mocker, rf, private_settings, caplog):
144 146
    private_settings.MELLON_IDENTITY_PROVIDERS = [
145 147
        {
146 148
        }
......
148 150
    request = rf.get('/')
149 151
    assert not 'failed with error' in caplog.text
150 152
    create_server(request)
151
    assert 'missing METADATA' in caplog.text
153
    assert 'missing METADATA' not in caplog.text
152 154

  
153 155

  
154
def test_create_server_good_metadata_url(mocker, rf, private_settings, caplog):
156
def test_create_server_good_metadata_url_lazy(mocker, rf, private_settings, caplog):
155 157
    private_settings.MELLON_IDENTITY_PROVIDERS = [
156 158
        {
157 159
            'METADATA_URL': 'http://example.com/metadata',
......
163 165
    with HTTMock(metadata_response):
164 166
        server = create_server(request)
165 167
    assert 'ERROR' not in caplog.text
166
    assert len(server.providers) == 1
168
    assert len(server.providers) == 0
167 169

  
168 170

  
169 171
def test_create_metadata(rf, private_settings, caplog):
170
-