Skip to content

Commit c9d413a

Browse files
committed
using the well-known json dict instead of manually providing multiple API endpoints through the config file
1 parent 33f2879 commit c9d413a

File tree

4 files changed

+70
-47
lines changed

4 files changed

+70
-47
lines changed

qiita_core/configuration_manager.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,18 @@ class ConfigurationManager(object):
137137
redirect_endpoint : str
138138
The internal Qiita endpoint the IdP shall redirect the user after
139139
logging in
140-
authorize_url : str
141-
The URL of the IdP to obtain a code (step 1)
142-
accesstoken_url : str
143-
The URL of the IdP to exchange the code from step 1 for an access
144-
token (step 2)
145-
userinfo_url : str
146-
The URL of the IdP to obtain information about the user, like email,
147-
username, ...
140+
wellknown_uri : str
141+
The URL of the well-known json document, specifying how API end points
142+
like 'authorize', 'token' or 'userinfo' are defined. See e.g.
143+
https://swagger.io/docs/specification/authentication/
144+
openid-connect-discovery/
148145
label : str
149146
A speaking label for the Identity Provider
147+
scope : str
148+
The scope, i.e. fields about a user, which Qiita requests from the
149+
Identity Provider, e.g. "profile email eduperson_orcid".
150+
Will be automatically extended by the scope "openid", to enable the
151+
"authorize_code" OIDC flow.
150152
151153
Raises
152154
------
@@ -436,14 +438,16 @@ def _get_oidc(self, config):
436438
if provider['redirect_endpoint'].endswith('/'):
437439
provider['redirect_endpoint'] = provider[
438440
'redirect_endpoint'][:-1]
439-
provider['authorize_url'] = config.get(
440-
section_name, 'AUTHORIZE_URL')
441-
provider['accesstoken_url'] = config.get(
442-
section_name, 'ACCESS_TOKEN_URL')
443-
provider['userinfo_url'] = config.get(
444-
section_name, 'USERINFO_URL')
441+
provider['wellknown_uri'] = config.get(
442+
section_name, 'WELLKNOWN_URI')
445443
provider['label'] = config.get(section_name, 'LABEL')
446444
if not provider['label']:
447445
# fallback, if no label is provided
448446
provider['label'] = section_name[len(PREFIX):]
449447
self.oidc[section_name[len(PREFIX):]] = provider
448+
provider['scope'] = config.get(
449+
section_name, 'SCOPE', fallback=None)
450+
if not provider['scope']:
451+
provider['scope'] = 'openid'
452+
if 'openid' not in provider['scope']:
453+
provider['scope'] = 'openid %s' % provider['scope']

qiita_core/support_files/config_test.cfg

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,8 @@ QIIMP = https://localhost:8898/
201201
# --------------------- External Identity Provider settings --------------------
202202
# user authentication happens per default within Qiita, i.e. when a user logs in,
203203
# the stored password hash and email address is compared against what a user
204-
# just provided. You might however, use an external identity provider (IdP) to
205-
# authenticate the user like
204+
# just provided. You might however, use an external identity provider (IdP) to
205+
# authenticate the user like
206206
# google: https://developers.google.com/identity/protocols/oauth2 or
207207
# github: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps or
208208
# self hosted keycloak: https://www.keycloak.org/
@@ -235,23 +235,26 @@ QIIMP = https://localhost:8898/
235235
#
236236
## client secret to verify Qiita as the correct client. Not all IdPs require
237237
## a client secret!
238-
#CLIENT_SECRET = 5M6zKl8SKrlnRP4tPgtrgZpCpcYCj7uK
238+
#CLIENT_SECRET = verySecretString
239239
#
240-
## redirect URL (end point in your Qiita instance), to which the IdP redirects
241-
## after user types in his/her credentials. If you don't want to change code in
240+
## redirect URL (end point in your Qiita instance), to which the IdP redirects
241+
## after user types in his/her credentials. If you don't want to change code in
242242
## qiita_pet/webserver.py the URL must follow the pattern:
243-
## base_URL/auth/login_OIDC/foo where foo is the name of this config section
243+
## base_URL/auth/login_OIDC/foo where foo is the name of this config section
244244
## without the oidc_ prefix!
245245
#REDIRECT_ENDPOINT = /auth/login_OIDC/localkeycloak
246246
#
247-
## URL for step 1: obtain code
248-
#AUTHORIZE_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/protocol/openid-connect/auth
249-
#
250-
## URL for step 2: obtain user token
251-
#ACCESS_TOKEN_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/protocol/openid-connect/token
252-
#
253-
## URL for step 3: obtain user infos
254-
#USERINFO_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/protocol/openid-connect/userinfo
247+
## The URL of the well-known json document, specifying how API end points
248+
## like 'authorize', 'token' or 'userinfo' are defined. See e.g.
249+
## https://swagger.io/docs/specification/authentication/
250+
## openid-connect-discovery/
251+
#WELLKNOWN_URI = https://keycloak.sso.gwdg.de/.well-known/openid-configuration
255252
#
256253
## a speaking label for the Identity Provider. Section name is used if empty.
257254
#LABEL = GWDG Academic Cloud
255+
#
256+
## The scope, i.e. fields about a user, which Qiita requests from the
257+
## Identity Provider, e.g. "profile email eduperson_orcid".
258+
## Will be automatically extended by the scope "openid", to enable the
259+
## "authorize_code" OIDC flow.
260+
#SCOPE = openid

qiita_core/tests/test_configuration_manager.py

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,7 @@ def test_get_oidc(self):
311311
obs._get_oidc(self.conf)
312312
self.assertEqual(obs.oidc['academicid']['client_id'], "foo")
313313

314-
self.assertTrue('gwdg.de' in obs.oidc['academicid']['authorize_url'])
315-
self.assertTrue('gwdg.de' in obs.oidc['academicid']['accesstoken_url'])
316-
self.assertTrue('gwdg.de' in obs.oidc['academicid']['userinfo_url'])
314+
self.assertTrue('gwdg.de' in obs.oidc['academicid']['wellknown_uri'])
317315

318316
self.assertEqual(obs.oidc['academicid']['label'],
319317
'GWDG Academic Cloud')
@@ -322,6 +320,18 @@ def test_get_oidc(self):
322320
obs._get_oidc(self.conf)
323321
self.assertEqual(obs.oidc['academicid']['label'], 'academicid')
324322

323+
self.assertEqual(obs.oidc['academicid']['scope'], 'openid')
324+
print(obs.oidc['academicid']['scope'])
325+
# test fallback, if no scope is provided
326+
self.conf.set(SECTION_NAME, 'SCOPE', '')
327+
obs._get_oidc(self.conf)
328+
self.assertEqual(obs.oidc['academicid']['scope'], 'openid')
329+
330+
# test if scope will be automatically extended with 'openid'
331+
self.conf.set(SECTION_NAME, 'SCOPE', 'email affiliation')
332+
obs._get_oidc(self.conf)
333+
self.assertTrue('openid' in obs.oidc['academicid']['scope'].split())
334+
325335
CONF = """
326336
# ------------------------------ Main settings --------------------------------
327337
[main]
@@ -513,7 +523,7 @@ def test_get_oidc(self):
513523
514524
# client secret to verify Qiita as the correct client. Not all IdPs require
515525
# a client secret.
516-
CLIENT_SECRET = 5M6zKl8SKrlnRP4tPgtrgZpCpcYCj7uK
526+
CLIENT_SECRET = verySecretString
517527
518528
# redirect URL (end point in your Qiita instance), to which the IdP redirects
519529
# after user types in his/her credentials. If you don't want to change code in
@@ -522,17 +532,20 @@ def test_get_oidc(self):
522532
# without the oidc_ prefix!
523533
REDIRECT_ENDPOINT = /auth/login_OIDC/academicid
524534
525-
# URL for step 1: obtain code
526-
AUTHORIZE_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/auth
527-
528-
# URL for step 2: obtain user token
529-
ACCESS_TOKEN_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/token
530-
531-
# URL for step 3: obtain user infos
532-
USERINFO_URL = https://keycloak.sso.gwdg.de/auth/realms/academiccloud/userinfo
535+
# The URL of the well-known json document, specifying how API end points
536+
# like 'authorize', 'token' or 'userinfo' are defined. See e.g.
537+
# https://swagger.io/docs/specification/authentication/
538+
# openid-connect-discovery/
539+
WELLKNOWN_URI = https://keycloak.sso.gwdg.de/.well-known/openid-configuration
533540
534541
# a speaking label for the Identity Provider. Section name is used if empty.
535542
LABEL = GWDG Academic Cloud
543+
544+
# The scope, i.e. fields about a user, which Qiita requests from the
545+
# Identity Provider, e.g. "profile email eduperson_orcid".
546+
# Will be automatically extended by the scope "openid", to enable the
547+
# "authorize_code" OIDC flow.
548+
SCOPE = openid
536549
"""
537550

538551
if __name__ == '__main__':

qiita_pet/handlers/auth_handlers.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import urllib.parse
1010
import os
1111
import warnings
12+
import requests
1213

1314
from tornado.escape import url_escape, json_encode, json_decode
1415
from tornado.auth import OAuth2Mixin
@@ -268,12 +269,14 @@ async def post(self, login):
268269
if self.idp is None:
269270
self.render("index.html", message=msg, level='warning')
270271

271-
self._OAUTH_AUTHORIZE_URL = qiita_config.oidc[self.idp][
272-
'authorize_url']
273-
self._OAUTH_ACCESS_TOKEN_URL = qiita_config.oidc[self.idp][
274-
'accesstoken_url']
275-
self._OAUTH_USERINFO_URL = qiita_config.oidc[self.idp][
276-
'userinfo_url']
272+
idp_config = requests.get(qiita_config.oidc[self.idp]['wellknown_uri'],
273+
proxies={env: os.environ[env]
274+
for env in os.environ
275+
if env.lower().endswith('_proxy')}).json()
276+
277+
self._OAUTH_AUTHORIZE_URL = idp_config['authorization_endpoint']
278+
self._OAUTH_ACCESS_TOKEN_URL = idp_config['token_endpoint']
279+
self._OAUTH_USERINFO_URL = idp_config['userinfo_endpoint']
277280

278281
if code:
279282
# step 2: we got a code and now want to exchange it for a user
@@ -333,7 +336,7 @@ async def post(self, login):
333336
client_id=qiita_config.oidc[self.idp]['client_id'],
334337
client_secret=qiita_config.oidc[self.idp]['client_secret'],
335338
response_type='code',
336-
scope=['openid']
339+
scope=[qiita_config.oidc[self.idp]['scope']]
337340
)
338341
get = post # redirect will use GET method
339342

0 commit comments

Comments
 (0)