diff --git a/apps/fhir/bluebutton/v2/urls.py b/apps/fhir/bluebutton/v2/urls.py index 050d933d8..4782c6d5d 100755 --- a/apps/fhir/bluebutton/v2/urls.py +++ b/apps/fhir/bluebutton/v2/urls.py @@ -4,9 +4,16 @@ from apps.fhir.bluebutton.views.read import ReadViewCoverage, ReadViewExplanationOfBenefit, ReadViewPatient from apps.fhir.bluebutton.views.search import SearchViewCoverage, SearchViewExplanationOfBenefit, SearchViewPatient +from apps.fhir.bluebutton.views import smart_configuration + admin.autodiscover() urlpatterns = [ + # OpenID Connect (OIDC) + url(r'.well-known/smart-configuration$', + smart_configuration, + name='smart-configuration-v2'), + # Patient ReadView url(r'Patient/(?P[^/]+)', ReadViewPatient.as_view(version=2), diff --git a/apps/fhir/bluebutton/views/__init__.py b/apps/fhir/bluebutton/views/__init__.py index e69de29bb..a07b2a3c2 100644 --- a/apps/fhir/bluebutton/views/__init__.py +++ b/apps/fhir/bluebutton/views/__init__.py @@ -0,0 +1 @@ +from .smart_configuration import smart_configuration, base_issuer, build_endpoint_info # NOQA \ No newline at end of file diff --git a/apps/fhir/bluebutton/views/smart_configuration.py b/apps/fhir/bluebutton/views/smart_configuration.py new file mode 100644 index 000000000..9dc664903 --- /dev/null +++ b/apps/fhir/bluebutton/views/smart_configuration.py @@ -0,0 +1,96 @@ +import logging + +from django.http import JsonResponse +from django.views.decorators.http import require_GET +from collections import OrderedDict +from django.conf import settings +from django.urls import reverse + +import apps.logging.request_logger as bb2logging + +logger = logging.getLogger(bb2logging.HHS_SERVER_LOGNAME_FMT.format(__name__)) + + +@require_GET +def smart_configuration(request): + """ + Views that returns openid_configuration. + """ + data = OrderedDict() + issuer = base_issuer(request) + #v2 = request.path.endswith('openid-configuration-v2') or request.path.endswith('openidConfigV2') + v2 = True + data = build_endpoint_info(data, issuer=issuer, v2=v2) + return JsonResponse(data) + + +def base_issuer(request): + """ + define the base url for issuer + + """ + issuer = getattr(settings, 'HOSTNAME_URL', 'http://localhost:8000') + + if "http://" in issuer.lower(): + pass + elif "https://" in issuer.lower(): + pass + else: + logger.debug("HOSTNAME_URL [%s] " + "does not contain http or https prefix. " + "Issuer:%s" % (settings.HOSTNAME_URL, issuer)) + # no http/https prefix in HOST_NAME_URL so we add it + if request.is_secure(): + http_mode = 'https://' + else: + http_mode = 'http://' + + # prefix hostname with http/https:// + issuer = http_mode + issuer + + return issuer + + +def build_endpoint_info(data=OrderedDict(), v2=False, issuer=""): + """ + construct the data package + issuer should be http: or https:// prefixed url. + + :param data: + :return: + """ + # Removing below per warning about ommitting this when not including sso-openid-connnect capability. + #data["issuer"] = issuer + + data["authorization_endpoint"] = issuer + \ + reverse('oauth2_provider:authorize' if not v2 else 'oauth2_provider_v2:authorize-v2') + data["token_endpoint"] = issuer + \ + reverse('oauth2_provider:token' if not v2 else 'oauth2_provider_v2:token-v2') + data["userinfo_endpoint"] = issuer + \ + reverse('openid_connect_userinfo' if not v2 else 'openid_connect_userinfo_v2') + data["ui_locales_supported"] = ["en-US", ] + data["service_documentation"] = getattr(settings, + 'DEVELOPER_DOCS_URI', + "https://cmsgov.github.io/bluebutton-developer-help/") + data["op_tos_uri"] = settings.TOS_URI + data["grant_types_supported"] = [] + + for i in settings.GRANT_TYPES: + data["grant_types_supported"].append(i[0]) + + data["grant_types_supported"].append("refresh_token") + + data["grant_types_supported"].remove("implicit") + + data["response_types_supported"] = ["code", "token"] + data["fhir_metadata_uri"] = issuer + \ + reverse('fhir_conformance_metadata' if not v2 else 'fhir_conformance_metadata_v2') + + + data["capabilities"] = ["launch-standalone", "client-confidential-symmetric", "permission-v1"] + + data["code_challenge_methods_supported"] = ["S256"] + + data["grant_types_supported"] = ["authorization_code"] + + return data