0001-auth_oidc-do-not-attempt-to-generate-one-s-own-clien.patch
src/authentic2_auth_oidc/management/commands/oidc-register-issuer.py | ||
---|---|---|
60 | 60 |
name = options['name'] |
61 | 61 |
openid_configuration = options.get('openid_configuration') |
62 | 62 |
issuer = options.get('issuer') |
63 |
client_id = options.get('client_id') |
|
64 |
if not client_id: |
|
65 |
raise CommandError('Client identifier must be specified') |
|
66 |
client_secret = options.get('client_secret') |
|
67 |
if not client_secret: |
|
68 |
raise CommandError('Client secret must be specified') |
|
63 | 69 |
if openid_configuration: |
64 | 70 |
with open(openid_configuration) as fd: |
65 | 71 |
openid_configuration = json.load(fd) |
... | ... | |
70 | 76 |
ou = OrganizationalUnit.objects.get(slug=options['ou_slug']) |
71 | 77 |
provider = register_issuer( |
72 | 78 |
name, |
79 |
client_id, |
|
80 |
client_secret, |
|
73 | 81 |
issuer=issuer, |
74 | 82 |
openid_configuration=openid_configuration, |
75 | 83 |
verify=not options['no_verify'], |
... | ... | |
87 | 95 |
except ValidationError as e: |
88 | 96 |
provider.delete() |
89 | 97 |
raise CommandError(e) |
90 |
client_id = options.get('client_id') |
|
91 |
if client_id: |
|
92 |
provider.client_id = client_id |
|
93 |
client_secret = options.get('client_secret') |
|
94 |
if client_secret: |
|
95 |
provider.client_secret = client_secret |
|
96 | 98 |
scope = options.get('scope') |
97 | 99 |
if scope is not None: |
98 | 100 |
provider.scopes = ' '.join(filter(None, options['scope'])) |
src/authentic2_auth_oidc/migrations/0001_initial.py | ||
---|---|---|
1 |
import uuid |
|
2 | ||
3 | 1 |
import django.contrib.postgres.fields.jsonb |
4 | 2 |
from django.conf import settings |
5 | 3 |
from django.db import migrations, models |
... | ... | |
70 | 68 |
'issuer', |
71 | 69 |
models.CharField(unique=True, max_length=256, verbose_name='issuer', db_index=True), |
72 | 70 |
), |
73 |
('client_id', models.CharField(default=uuid.uuid4, max_length=128, verbose_name='client id')),
|
|
71 |
('client_id', models.CharField(max_length=128, verbose_name='client id')), |
|
74 | 72 |
( |
75 | 73 |
'client_secret', |
76 |
models.CharField(default=uuid.uuid4, max_length=128, verbose_name='client secret'),
|
|
74 |
models.CharField(max_length=128, verbose_name='client secret'), |
|
77 | 75 |
), |
78 | 76 |
( |
79 | 77 |
'authorization_endpoint', |
src/authentic2_auth_oidc/models.py | ||
---|---|---|
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 | 17 |
import json |
18 |
import uuid |
|
19 | 18 | |
20 | 19 |
from django.conf import settings |
21 | 20 |
from django.contrib.postgres.fields import JSONField |
... | ... | |
81 | 80 |
] |
82 | 81 | |
83 | 82 |
issuer = models.CharField(max_length=256, verbose_name=_('issuer'), db_index=True) |
84 |
client_id = models.CharField(max_length=128, default=uuid.uuid4, verbose_name=_('client id'))
|
|
85 |
client_secret = models.CharField(max_length=128, default=uuid.uuid4, verbose_name=_('client secret'))
|
|
83 |
client_id = models.CharField(max_length=128, verbose_name=_('client id')) |
|
84 |
client_secret = models.CharField(max_length=128, verbose_name=_('client secret')) |
|
86 | 85 |
# endpoints |
87 | 86 |
authorization_endpoint = models.URLField(max_length=128, verbose_name=_('authorization endpoint')) |
88 | 87 |
token_endpoint = models.URLField(max_length=128, verbose_name=_('token endpoint')) |
src/authentic2_auth_oidc/utils.py | ||
---|---|---|
186 | 186 |
return urllib.parse.urlparse(url).scheme == 'https' |
187 | 187 | |
188 | 188 | |
189 |
def register_issuer(name, issuer=None, openid_configuration=None, verify=True, timeout=None, ou=None): |
|
189 |
def register_issuer( |
|
190 |
name, client_id, client_secret, issuer=None, openid_configuration=None, verify=True, timeout=None, ou=None |
|
191 |
): |
|
190 | 192 |
from . import models |
191 | 193 | |
192 | 194 |
if issuer and not openid_configuration: |
tests/test_auth_oidc.py | ||
---|---|---|
161 | 161 |
idtoken_algo=OIDCProvider._meta.get_field('idtoken_algo').default, |
162 | 162 |
jwkset=None, |
163 | 163 |
claims_parameter_supported=False, |
164 |
client_id='abc', |
|
165 |
client_secret='def', |
|
164 | 166 |
): |
165 | 167 |
slug = slug or name.lower() |
166 | 168 |
issuer = issuer or ('https://%s.example.com' % slug) |
... | ... | |
169 | 171 |
ou=get_default_ou(), |
170 | 172 |
name=name, |
171 | 173 |
slug=slug, |
174 |
client_id=client_id, |
|
175 |
client_secret=client_secret, |
|
172 | 176 |
enabled=True, |
173 | 177 |
issuer=issuer, |
174 | 178 |
authorization_endpoint='%s/authorize' % issuer, |
... | ... | |
843 | 847 |
return oidc_provider_jwkset.export() |
844 | 848 | |
845 | 849 |
with HTTMock(jwks_mock): |
846 |
register_issuer(name='test_issuer', issuer='https://default.issuer', openid_configuration=oidc_conf) |
|
850 |
register_issuer( |
|
851 |
name='test_issuer', |
|
852 |
client_id='abc', |
|
853 |
client_secret='def', |
|
854 |
issuer='https://default.issuer', |
|
855 |
openid_configuration=oidc_conf, |
|
856 |
) |
|
847 | 857 | |
848 | 858 |
oidc_conf['id_token_signing_alg_values_supported'] = ['HS256'] |
849 | 859 |
with HTTMock(jwks_mock): |
850 | 860 |
register_issuer( |
851 |
name='test_issuer_hmac_only', issuer='https://hmac_only.issuer', openid_configuration=oidc_conf |
|
861 |
name='test_issuer_hmac_only', |
|
862 |
client_id='ghi', |
|
863 |
client_secret='jkl', |
|
864 |
issuer='https://hmac_only.issuer', |
|
865 |
openid_configuration=oidc_conf, |
|
852 | 866 |
) |
853 | 867 | |
854 | 868 |
tests/test_commands.py | ||
---|---|---|
274 | 274 |
with oidc_conf_f.open() as f: |
275 | 275 |
oidc_conf = json.load(f) |
276 | 276 | |
277 |
def register_issuer(name, issuer=None, openid_configuration=None, verify=True, timeout=None, ou=None): |
|
277 |
def register_issuer( |
|
278 |
name, |
|
279 |
client_id, |
|
280 |
client_secret, |
|
281 |
issuer=None, |
|
282 |
openid_configuration=None, |
|
283 |
verify=True, |
|
284 |
timeout=None, |
|
285 |
ou=None, |
|
286 |
): |
|
278 | 287 |
ou = OrganizationalUnit.objects.get(default=True) |
279 | 288 |
# skipping jwkset retrieval in mocked function |
280 | 289 |
jwkset = JWKSet() |
... | ... | |
283 | 292 |
return OIDCProvider.objects.create( |
284 | 293 |
name=name, |
285 | 294 |
slug='test', |
295 |
client_id='abc', |
|
296 |
client_secret='def', |
|
286 | 297 |
enabled=True, |
287 | 298 |
ou=ou, |
288 | 299 |
issuer=issuer, |
... | ... | |
299 | 310 | |
300 | 311 |
oidc_conf = py.path.local(__file__).dirpath('openid_configuration.json').strpath |
301 | 312 |
call_command( |
302 |
'oidc-register-issuer', '--openid-configuration', oidc_conf, '--issuer', 'issuer', 'somename' |
|
313 |
'oidc-register-issuer', |
|
314 |
'--openid-configuration', |
|
315 |
oidc_conf, |
|
316 |
'--issuer', |
|
317 |
'issuer', |
|
318 |
'--client-id', |
|
319 |
'auie', |
|
320 |
'--client-secret', |
|
321 |
'tsrn', |
|
322 |
'somename', |
|
303 | 323 |
) |
304 | 324 | |
305 | 325 |
provider = OIDCProvider.objects.get(name='somename') |
tests/test_manager_authenticators.py | ||
---|---|---|
166 | 166 | |
167 | 167 |
resp = resp.click('Edit') |
168 | 168 |
assert 'enabled' not in resp.form.fields |
169 |
assert resp.pyquery('input#id_client_id').val() == '' |
|
170 |
assert resp.pyquery('input#id_client_secret').val() == '' |
|
169 | 171 |
resp.form['ou'] = ou1.pk |
170 | 172 |
resp.form['issuer'] = 'https://oidc.example.com' |
171 | 173 |
resp.form['scopes'] = 'profile email' |
... | ... | |
176 | 178 |
resp.form['idtoken_algo'] = 2 |
177 | 179 |
resp.form['button_label'] = 'Test' |
178 | 180 |
resp.form['button_description'] = 'test' |
181 |
resp.form['client_id'] = 'auie' |
|
182 |
resp.form['client_secret'] = 'tsrn' |
|
179 | 183 |
resp = resp.form.submit().follow() |
180 | 184 |
assert_event('authenticator.edit', user=superuser, session=app.session) |
181 | 185 | |
... | ... | |
195 | 199 |
resp = resp.click('Journal') |
196 | 200 |
assert 'enable' in resp.text |
197 | 201 |
assert ( |
198 |
'edit (ou, issuer, scopes, strategy, button_label, idtoken_algo, token_endpoint, ' |
|
199 |
'userinfo_endpoint, button_description, authorization_endpoint)' in resp.text |
|
202 |
'edit (ou, issuer, scopes, strategy, client_id, button_label, idtoken_algo, ' |
|
203 |
'client_secret, token_endpoint, userinfo_endpoint, button_description, authorization_endpoint)' |
|
204 |
in resp.text |
|
200 | 205 |
) |
201 | 206 |
assert 'creation' in resp.text |
202 | 207 | |
203 |
- |