Projet

Général

Profil

0001-misc-simplify-identification-subsystem-selection-pic.patch

Frédéric Péters, 04 décembre 2022 17:50

Télécharger (7,29 ko)

Voir les différences:

Subject: [PATCH] misc: simplify identification subsystem selection (pick saml
 or first) (#72001)

 tests/test_auth_pages.py | 40 +++++++++++----------
 wcs/root.py              | 78 ++++------------------------------------
 2 files changed, 27 insertions(+), 91 deletions(-)
tests/test_auth_pages.py
32 32
def pub_2auth(pub):
33 33
    pub.cfg['identification'] = {'methods': ['password', 'idp']}
34 34
    pub.write_cfg()
35

  
36
    # setup saml
37
    from wcs.qommon.ident.idp import MethodAdminDirectory
38

  
39
    from .test_saml_auth import setup_idps
40

  
41
    pub.cfg['sp'] = {
42
        'saml2_metadata': 'saml2-metadata.xml',
43
        'saml2_base_url': 'http://example.net/saml',
44
        'saml2_providerid': 'http://example.net/saml/metadata',
45
    }
46
    MethodAdminDirectory().generate_rsa_keypair()
47
    setup_idps(pub)
48

  
35 49
    return pub
36 50

  
37 51

  
......
80 94

  
81 95

  
82 96
def test_login_2auth(pub_2auth):
97
    # check sso is initiated if there is both password and saml support
83 98
    resp = get_app(pub_2auth).get('/').click('Login').follow()
84
    resp.form['method'] = 'Username / password'
85
    resp = resp.form.submit().follow()
86
    resp.form['username'] = 'foo'
87
    resp.form['password'] = 'foo'
88
    resp = resp.form.submit().follow()
89
    assert '/logout' in resp.text
90

  
91
    resp = get_app(pub_2auth).get('/').click('Login').follow()
92
    resp.form['method'] = 'SAML identity provider'
93
    resp = resp.form.submit().follow()
94
    assert 'SSO support is not yet configured' in resp.text
99
    assert resp.location.startswith('http://sso.example.net/saml')
95 100

  
96 101

  
97 102
def test_register_2auth(pub_2auth):
98
    pub_2auth.cfg['identities'] = {'creation': 'self'}
103
    pub_2auth.cfg['saml_identities'] = {
104
        'identity-creation': 'self',
105
        'registration-url': 'http://sso.example.net/registration',
106
    }
99 107
    pub_2auth.write_cfg()
100 108
    resp = get_app(pub_2auth).get('/register/')
101
    resp.form['method'] = 'Username / password'
102
    resp = resp.form.submit().follow()
103
    assert 'New Account' in resp.text
104

  
105
    resp = get_app(pub_2auth).get('/register/')
106
    resp.form['method'] = 'SAML identity provider'
107
    assert resp.form.submit().location == 'http://example.net/ident/idp/register'
109
    assert resp.location == 'http://sso.example.net/registration'
wcs/root.py
17 17
import json
18 18
import os
19 19
import re
20
import urllib.parse
21 20
from importlib import import_module
22 21

  
23 22
from quixote import get_publisher, get_request, get_response, get_session, get_session_manager, redirect
24 23
from quixote.directory import Directory
25
from quixote.html import TemplateIO, htmltext
26 24
from quixote.util import StaticDirectory
27 25

  
28 26
from . import portfolio
......
35 33
from .myspace import MyspaceDirectory
36 34
from .qommon import _, errors, get_cfg, ident, misc, saml2, template
37 35
from .qommon.afterjobs import AfterJobStatusDirectory
38
from .qommon.form import Form, RadiobuttonsWidget
39 36
from .qommon.upload_storage import UploadStorageError, get_storage_object
40 37

  
41 38

  
......
75 72
            # to saml login.
76 73
            ident_methods = ['idp']
77 74

  
78
        if len(ident_methods) == 1:
79
            method = ident_methods[0]
80
            try:
81
                return ident.login(method)
82
            except KeyError as e:
83
                msg = _('Failed to login with method %s') % method
84
                get_publisher().record_error(msg, exception=e)
85
                return errors.TraversalError(msg)
86
        else:
87
            form = Form(enctype='multipart/form-data')
88
            form.add(
89
                RadiobuttonsWidget,
90
                'method',
91
                options=[
92
                    (x.key, x.description) for x in ident.get_method_classes() if x.key in ident_methods
93
                ],
94
                delim=htmltext('<br/>'),
95
            )
96
            form.add_submit('submit', _('Submit'))
97

  
98
            if form.is_submitted() and not form.has_errors():
99
                method = form.get_widget('method').parse()
100
                if get_publisher().ident_methods.get(method)().is_interactive():
101
                    login_url = '../ident/%s/login' % method
102
                    if get_request().form.get('next'):
103
                        login_url += '?' + urllib.parse.urlencode({'next': get_request().form.get('next')})
104
                    return redirect(login_url)
105
                else:
106
                    try:
107
                        return ident.login(method)
108
                    except KeyError as e:
109
                        get_publisher().record_error(
110
                            _('Failed to login with method %s') % method, exception=e
111
                        )
112
                        return errors.TraversalError()
113
            else:
114
                template.html_top(_('Login'))
115
                r = TemplateIO(html=True)
116
                r += htmltext('<p>%s</p>') % _('Select the identification method you want to use:')
117
                r += form.render()
118
                return r.getvalue()
75
        # always prefer idp (saml), fallback to first configured method
76
        method = 'idp' if 'idp' in ident_methods else ident_methods[0]
77
        return ident.login(method)
119 78

  
120 79
    def _q_lookup(self, component):
121 80
        try:
......
141 100
                return template.error_page(_('Authentication subsystem is not yet configured.'))
142 101
            ident_methods = ['idp']  # fallback to old behaviour; saml.
143 102

  
144
        if len(ident_methods) == 1:
145
            method = ident_methods[0]
146
            try:
147
                return ident.register(method)
148
            except KeyError as e:
149
                get_publisher().record_error(_('Failed to register with method %s') % method, exception=e)
150
                return errors.TraversalError()
151
        else:
152
            form = Form(enctype='multipart/form-data')
153
            form.add(
154
                RadiobuttonsWidget,
155
                'method',
156
                options=[
157
                    (x.key, x.description) for x in ident.get_method_classes() if x.key in ident_methods
158
                ],
159
                delim=htmltext('<br/>'),
160
            )
161
            form.add_submit('submit', _('Submit'))
162

  
163
            if form.is_submitted() and not form.has_errors():
164
                method = form.get_widget('method').parse()
165
                return redirect('../ident/%s/register' % method)
166
            else:
167
                template.html_top(_('Register'))
168
                r = TemplateIO(html=True)
169
                r += htmltext('<p>%s</p>') % _('Select the registration method you want to use:')
170
                r += htmltext(form.render())
171
                return r.getvalue()
103
        # always prefer idp (saml), fallback to first configured method
104
        method = 'idp' if 'idp' in ident_methods else ident_methods[0]
105
        return ident.register(method)
172 106

  
173 107
    def _q_lookup(self, component):
174 108
        try:
175
-