Browse Source

DIV-1136: Add local keycloak sign in support.

pull/172/head
Steven Ly 5 years ago
committed by Michael Olund
parent
commit
e8d7d59707
12 changed files with 2191 additions and 23 deletions
  1. +11
    -1
      .env.example
  2. +2105
    -0
      conf/keycloak/realm-export.json
  3. +15
    -0
      docker-compose.yml
  4. +10
    -0
      edivorce/apps/core/middleware/keycloak.py
  5. +1
    -1
      edivorce/apps/core/templates/base.html
  6. +1
    -1
      edivorce/apps/core/templates/intro.html
  7. +1
    -1
      edivorce/apps/core/templates/localdev/register.html
  8. +5
    -4
      edivorce/apps/core/views/main.py
  9. +2
    -1
      edivorce/apps/core/views/pdf.py
  10. +6
    -5
      edivorce/apps/poc/urls.py
  11. +32
    -9
      edivorce/settings/base.py
  12. +2
    -0
      edivorce/urls.py

+ 11
- 1
.env.example View File

@ -26,4 +26,14 @@ EFILING_HUB_CLIENT_SECRET=''
EFILING_HUB_API_BASE_URL='' EFILING_HUB_API_BASE_URL=''
# BCE ID test accounts for localdev # BCE ID test accounts for localdev
EFILING_BCEID=
EFILING_BCEID=
# Keycloak settings
OIDC_OP_JWKS_ENDPOINT=
OIDC_RP_CLIENT_ID=
OIDC_RP_CLIENT_SECRET=
OIDC_OP_AUTHORIZATION_ENDPOINT=
OIDC_OP_TOKEN_ENDPOINT=
OIDC_OP_USER_ENDPOINT=
LOGIN_REDIRECT_URL=
LOGOUT_REDIRECT_URL=

+ 2105
- 0
conf/keycloak/realm-export.json
File diff suppressed because it is too large
View File


+ 15
- 0
docker-compose.yml View File

@ -43,5 +43,20 @@ services:
- "5005:5001" - "5005:5001"
restart: always restart: always
# Keycloak
keycloak:
container_name: edivorce-keycloak
image: jboss/keycloak:9.0.3
environment:
DB_VENDOR: H2
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
KEYCLOAK_IMPORT: /tmp/realm-export.json
volumes:
- ./conf/keycloak/realm-export.json:/tmp/realm-export.json
ports:
- 8081:8080
command: ["-Dkeycloak.profile.feature.upload_scripts=enabled"]
volumes: volumes:
data-redis: data-redis:

+ 10
- 0
edivorce/apps/core/middleware/keycloak.py View File

@ -0,0 +1,10 @@
from mozilla_django_oidc.auth import OIDCAuthenticationBackend
class EDivorceKeycloakBackend(OIDCAuthenticationBackend):
def verify_claims(self, claims):
verified = super(EDivorceKeycloakBackend, self).verify_claims(claims)
print(claims)
return verified

+ 1
- 1
edivorce/apps/core/templates/base.html View File

@ -55,7 +55,7 @@
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<span> <span>
{{ request.user.display_name}} {{ request.user.display_name}}
&nbsp;&nbsp;|&nbsp;&nbsp; <a href="{% url 'logout' %}">Log out</a>
&nbsp;&nbsp;|&nbsp;&nbsp; <a href="{% url 'oidc_logout' %}">Log out</a>
</span> </span>
{% endif %} {% endif %}
</div> </div>


+ 1
- 1
edivorce/apps/core/templates/intro.html View File

@ -51,7 +51,7 @@
<h3> <h3>
Already started completing forms online and want to pick up where you left off? Already started completing forms online and want to pick up where you left off?
</h3> </h3>
<a href="{% url 'login' %}" class="btn btn-primary btn-lg">Returning users</a>
<a href="{% url 'oidc_authentication_init' %}" class="btn btn-primary btn-lg">Returning users</a>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}


+ 1
- 1
edivorce/apps/core/templates/localdev/register.html View File

@ -10,7 +10,7 @@
<p>Enter <strong>any user id</strong> with the password <em><strong>divorce</strong></em> to <p>Enter <strong>any user id</strong> with the password <em><strong>divorce</strong></em> to
simulate a login in your localdev envirommnent.</p> simulate a login in your localdev envirommnent.</p>
<a href="{% url 'login' %}">Goto Login</a>
<a href="{% url 'oidc_authentication_init' %}">Goto Login</a>
</body> </body>

+ 5
- 4
edivorce/apps/core/views/main.py View File

@ -4,6 +4,7 @@ from django.conf import settings
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.decorators import login_required
from edivorce.apps.core.utils.derived import get_derived_data from edivorce.apps.core.utils.derived import get_derived_data
from ..decorators import bceid_required, intercept, prequal_completed from ..decorators import bceid_required, intercept, prequal_completed
@ -164,7 +165,7 @@ def logout(request):
return response return response
@bceid_required
@login_required
@prequal_completed @prequal_completed
@intercept @intercept
def overview(request): def overview(request):
@ -192,7 +193,7 @@ def overview(request):
return response return response
@bceid_required
@login_required
@prequal_completed @prequal_completed
def dashboard_nav(request, nav_step): def dashboard_nav(request, nav_step):
""" """
@ -212,7 +213,7 @@ def dashboard_nav(request, nav_step):
return render(request, template_name=template_name, context=responses_dict) return render(request, template_name=template_name, context=responses_dict)
@bceid_required
@login_required
@prequal_completed @prequal_completed
def submit_initial_files(request): def submit_initial_files(request):
return _submit_files(request, initial=True) return _submit_files(request, initial=True)
@ -309,7 +310,7 @@ def contact(request):
return render(request, 'contact-us.html', context={'active_page': 'contact'}) return render(request, 'contact-us.html', context={'active_page': 'contact'})
@bceid_required
@login_required
def intercept_page(request): def intercept_page(request):
""" """
On intercept, show the Orders page to get the requested orders before the On intercept, show the Orders page to get the requested orders before the


+ 2
- 1
edivorce/apps/core/views/pdf.py View File

@ -5,6 +5,7 @@ import json
from django.conf import settings from django.conf import settings
from django.http import HttpResponse from django.http import HttpResponse
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.contrib.auth.decorators import login_required
import requests import requests
@ -16,7 +17,7 @@ from ..utils.user_response import get_data_for_user
EXHIBITS = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'[::-1]) EXHIBITS = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'[::-1])
@bceid_required
@login_required
def form(request, form_number): def form(request, form_number):
""" View for rendering PDF's and previews """ """ View for rendering PDF's and previews """


+ 6
- 5
edivorce/apps/poc/urls.py View File

@ -1,12 +1,13 @@
from django.conf.urls import url from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from edivorce.apps.poc import views from edivorce.apps.poc import views
from ..core.decorators import bceid_required from ..core.decorators import bceid_required
urlpatterns = [ urlpatterns = [
url(r'scan', bceid_required(views.UploadScan.as_view()), name="poc-scan"),
url(r'hub', bceid_required(views.EfilingHubUpload.as_view()), name="poc-hub"),
url(r'storage/doc/(?P<document_id>\d+)', bceid_required(views.view_document_file), name="poc-storage-download"),
url(r'storage/delete/(?P<pk>\d+)', bceid_required(views.UploadStorageDelete.as_view()), name="poc-storage-delete"),
url(r'storage', bceid_required(views.UploadStorage.as_view()), name="poc-storage"),
url(r'scan', login_required(views.UploadScan.as_view()), name="poc-scan"),
url(r'hub', login_required(views.EfilingHubUpload.as_view()), name="poc-hub"),
url(r'storage/doc/(?P<document_id>\d+)', login_required(views.view_document_file), name="poc-storage-download"),
url(r'storage/delete/(?P<pk>\d+)', login_required(views.UploadStorageDelete.as_view()), name="poc-storage-delete"),
url(r'storage', login_required(views.UploadStorage.as_view()), name="poc-storage"),
] ]

+ 32
- 9
edivorce/settings/base.py View File

@ -11,6 +11,8 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
""" """
import os import os
from django.urls import reverse_lazy
from environs import Env from environs import Env
from unipath import Path from unipath import Path
@ -45,6 +47,7 @@ INSTALLED_APPS = (
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.humanize', 'django.contrib.humanize',
'mozilla_django_oidc', # Load after auth
'rest_framework', 'rest_framework',
'debug_toolbar', 'debug_toolbar',
'corsheaders', 'corsheaders',
@ -62,7 +65,7 @@ if ENVIRONMENT in ['localdev', 'dev', 'test', 'minishift']:
) )
MIDDLEWARE = ( MIDDLEWARE = (
'edivorce.apps.core.middleware.basicauth_middleware.BasicAuthMiddleware',
# 'edivorce.apps.core.middleware.basicauth_middleware.BasicAuthMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', 'corsheaders.middleware.CorsMiddleware',
@ -71,11 +74,15 @@ MIDDLEWARE = (
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'edivorce.apps.core.middleware.bceid_middleware.BceidMiddleware',
# 'edivorce.apps.core.middleware.bceid_middleware.BceidMiddleware',
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware',
) )
AUTHENTICATION_BACKENDS = (
'edivorce.apps.core.middleware.keycloak.EDivorceKeycloakBackend',
)
ROOT_URLCONF = 'edivorce.urls' ROOT_URLCONF = 'edivorce.urls'
TEMPLATES = [ TEMPLATES = [
@ -99,11 +106,11 @@ WSGI_APPLICATION = 'wsgi.application'
# need to disable auth in Django Rest Framework so it doesn't get triggered # need to disable auth in Django Rest Framework so it doesn't get triggered
# by presence of Basic Auth headers # by presence of Basic Auth headers
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'edivorce.apps.core.authenticators.BCeIDAuthentication',
]
}
# REST_FRAMEWORK = {
# 'DEFAULT_AUTHENTICATION_CLASSES': [
# 'edivorce.apps.core.authenticators.BCeIDAuthentication',
# ]
# }
LOGGING = { LOGGING = {
@ -117,7 +124,7 @@ LOGGING = {
'loggers': { 'loggers': {
'': { '': {
'handlers': ['console'], 'handlers': ['console'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),
'level': env('DJANGO_LOG_LEVEL', 'INFO'),
}, },
}, },
} }
@ -175,7 +182,7 @@ DEBUG_TOOLBAR_CONFIG = {
SECURE_BROWSER_XSS_FILTER = True SECURE_BROWSER_XSS_FILTER = True
LOGOUT_URL = '/accounts/logout/'
# LOGOUT_URL = '/accounts/logout/'
# CLAMAV settings # CLAMAV settings
@ -187,3 +194,19 @@ EFILING_HUB_CLIENT_SECRET = env('EFILING_HUB_CLIENT_SECRET', 'abc')
EFILING_HUB_API_BASE_URL = env('EFILING_HUB_API_BASE_URL', 'https://efiling.gov.bc.ca') EFILING_HUB_API_BASE_URL = env('EFILING_HUB_API_BASE_URL', 'https://efiling.gov.bc.ca')
EFILING_BCEID = env.dict('EFILING_BCEID', '', subcast=str) EFILING_BCEID = env.dict('EFILING_BCEID', '', subcast=str)
# Keycloak OpenID Connect settings
# Provided by mozilla-django-oidc
LOGIN_URL = reverse_lazy('oidc_authentication_init')
OIDC_RP_SIGN_ALGO = 'RS256'
OIDC_RP_SCOPES = 'openid email profile'
OIDC_AUTH_REQUEST_EXTRA_PARAMS = {'kc_idp_hint': 'bceid'} # this is needed to bypass the Keycloak login screen
# OIDC_CREATE_USER = False
OIDC_OP_JWKS_ENDPOINT = env('OIDC_OP_JWKS_ENDPOINT', '')
OIDC_RP_CLIENT_ID = env('OIDC_RP_CLIENT_ID', '')
OIDC_RP_CLIENT_SECRET = env('OIDC_RP_CLIENT_SECRET', '')
OIDC_OP_AUTHORIZATION_ENDPOINT = env('OIDC_OP_AUTHORIZATION_ENDPOINT', '')
OIDC_OP_TOKEN_ENDPOINT = env('OIDC_OP_TOKEN_ENDPOINT', '')
OIDC_OP_USER_ENDPOINT = env('OIDC_OP_USER_ENDPOINT', '')
LOGIN_REDIRECT_URL = env('LOGIN_REDIRECT_URL', '/')
LOGOUT_REDIRECT_URL = env('LOGOUT_REDIRECT_URL', '/')

+ 2
- 0
edivorce/urls.py View File

@ -22,6 +22,8 @@ if settings.ENVIRONMENT in ['localdev', 'minishift']:
urlpatterns.append(url(r'^404/$', main.page_not_found, {'exception': Exception()})) urlpatterns.append(url(r'^404/$', main.page_not_found, {'exception': Exception()}))
urlpatterns.append(url(r'^500/$', main.server_error)) urlpatterns.append(url(r'^500/$', main.server_error))
urlpatterns.append(url(r'^oidc/', include('mozilla_django_oidc.urls')))
urlpatterns.append(url(r'^', include('edivorce.apps.core.urls'))) urlpatterns.append(url(r'^', include('edivorce.apps.core.urls')))
handler404 = main.page_not_found handler404 = main.page_not_found


Loading…
Cancel
Save