Skip to content
Snippets Groups Projects
Commit 1e588e61 authored by Stefano Alberto Russo's avatar Stefano Alberto Russo
Browse files

Merge branch 'feature/OpenID' into develop

parents 6e7a544d 39aa1ddd
No related branches found
No related tags found
No related merge requests found
...@@ -133,7 +133,9 @@ ...@@ -133,7 +133,9 @@
downgrade-1.0 force-response-1.0 downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive # MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
# Required for the Open ID connect redirects to work properly
RequestHeader set X-Forwarded-Proto 'https' env=HTTPS
</VirtualHost> </VirtualHost>
</IfModule> </IfModule>
......
from mozilla_django_oidc.auth import OIDCAuthenticationBackend
from .core_app.utils import finalize_user_creation
# Setup logging
import logging
logger = logging.getLogger(__name__)
class RosettaOIDCAuthenticationBackend(OIDCAuthenticationBackend):
def create_user(self, claims):
# Call parent user creation function
user = super(RosettaOIDCAuthenticationBackend, self).create_user(claims)
# Add profile, keys etc.
finalize_user_creation(user)
return user
def get_userinfo(self, access_token, id_token, payload):
# Payload must contain the "email" key
return payload
import os
from django.conf import settings
def export_vars(request):
data = {}
if settings.OIDC_RP_CLIENT_ID:
data['OPENID_ENABLED'] = True
else:
data['OPENID_ENABLED'] = False
return data
\ No newline at end of file
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<b>Account ID</b> <b>Account ID</b>
</td> </td>
<td> <td>
{{data.user.username}} | <a href="/logout/">Logout</a> {{data.user.username}}
</td> </td>
</tr> </tr>
...@@ -99,9 +99,22 @@ ...@@ -99,9 +99,22 @@
</tr> </tr>
</table> </table>
</form> </form>
<div style="margin-left:10px; margin-top:40px">
{% if OPENID_ENABLED %}
<form action="{% url 'oidc_logout' %}" method="post">
{% csrf_token %}
<input type="submit" value="logout">
</form>
{% else %}
<form action="/logout/" method="get">
<input type="submit" value="logout">
</form>
{% endif %}
</div>
<br/> <br/>
<br/> <br/>
<br/> <br/>
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
<input type="password" class="form-control" placeholder="Password" name='password'> <input type="password" class="form-control" placeholder="Password" name='password'>
<input type='submit' class="btn btn-lg ha-btn-lg" value='Login' /> <input type='submit' class="btn btn-lg ha-btn-lg" value='Login' />
</form> </form>
{% if OPENID %}
{% endif %}
</center> </center>
</li> </li>
<center> <center>
...@@ -53,7 +55,23 @@ ...@@ -53,7 +55,23 @@
</div> </div>
</center> </center>
{% endif %} {% endif %}
{% if OPENID_ENABLED %}
<li>
{% if not user.is_authenticated %}
<a href="{% url 'oidc_authentication_init' %}">Login with OpenID Conn. &nbsp;</a>
{% endif %}
</li>
{% endif %}
</ul> </ul>
</nav> </nav>
{% endif %} {% endif %}
...@@ -134,6 +134,34 @@ def random_username(): ...@@ -134,6 +134,34 @@ def random_username():
return username return username
def finalize_user_creation(user):
from .models import Profile, KeyPair
# Create profile
logger.debug('Creating user profile for user "{}"'.format(user.email))
Profile.objects.create(user=user)
# Generate user keys
out = os_shell('mkdir -p /data/resources/keys/', capture=True)
if not out.exit_code == 0:
logger.error(out)
raise ErrorMessage('Something went wrong in creating user keys folder. Please contact support')
command= "/bin/bash -c \"ssh-keygen -q -t rsa -N '' -f /data/resources/keys/{}_id_rsa 2>/dev/null <<< y >/dev/null\"".format(user.username)
out = os_shell(command, capture=True)
if not out.exit_code == 0:
logger.error(out)
raise ErrorMessage('Something went wrong in creating user keys. Please contact support')
# Create key objects
KeyPair.objects.create(user = user,
default = True,
private_key_file = '/data/resources/keys/{}_id_rsa'.format(user.username),
public_key_file = '/data/resources/keys/{}_id_rsa.pub'.format(user.username))
def sanitize_shell_encoding(text): def sanitize_shell_encoding(text):
return text.encode("utf-8", errors="ignore") return text.encode("utf-8", errors="ignore")
......
...@@ -9,7 +9,7 @@ from django.http import HttpResponse, HttpResponseRedirect ...@@ -9,7 +9,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.shortcuts import redirect from django.shortcuts import redirect
from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing, KeyPair, ComputingSysConf, ComputingUserConf from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing, KeyPair, ComputingSysConf, ComputingUserConf
from .utils import send_email, format_exception, timezonize, os_shell, booleanize, debug_param, get_tunnel_host, random_username, setup_tunnel from .utils import send_email, format_exception, timezonize, os_shell, booleanize, debug_param, get_tunnel_host, random_username, setup_tunnel, finalize_user_creation
from .decorators import public_view, private_view from .decorators import public_view, private_view
from .exceptions import ErrorMessage from .exceptions import ErrorMessage
...@@ -166,29 +166,7 @@ def register_view(request): ...@@ -166,29 +166,7 @@ def register_view(request):
data['user'] = user data['user'] = user
# Create profile finalize_user_creation(user)
logger.debug('Creating user profile for user "{}"'.format(user.email))
Profile.objects.create(user=user)
# Generate user keys
out = os_shell('mkdir -p /data/resources/keys/', capture=True)
if not out.exit_code == 0:
logger.error(out)
raise ErrorMessage('Something went wrong in creating user keys folder. Please contact support')
command= "/bin/bash -c \"ssh-keygen -q -t rsa -N '' -f /data/resources/keys/{}_id_rsa 2>/dev/null <<< y >/dev/null\"".format(user.username)
out = os_shell(command, capture=True)
if not out.exit_code == 0:
logger.error(out)
raise ErrorMessage('Something went wrong in creating user keys. Please contact support')
# Create key objects
KeyPair.objects.create(user = user,
default = True,
private_key_file = '/data/resources/keys/{}_id_rsa'.format(user.username),
public_key_file = '/data/resources/keys/{}_id_rsa.pub'.format(user.username))
# Manually set the auth backend for the user # Manually set the auth backend for the user
user.backend = 'django.contrib.auth.backends.ModelBackend' user.backend = 'django.contrib.auth.backends.ModelBackend'
......
...@@ -36,6 +36,7 @@ INSTALLED_APPS = [ ...@@ -36,6 +36,7 @@ INSTALLED_APPS = [
'rosetta.core_app', 'rosetta.core_app',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'mozilla_django_oidc',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
...@@ -67,6 +68,7 @@ TEMPLATES = [ ...@@ -67,6 +68,7 @@ TEMPLATES = [
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'rosetta.context_processors.export_vars'
], ],
}, },
}, },
...@@ -225,3 +227,48 @@ LOGGING = { ...@@ -225,3 +227,48 @@ LOGGING = {
#===============================
# Auth
#===============================
OIDC_RP_CLIENT_ID = os.environ.get('OIDC_RP_CLIENT_ID', None)
if OIDC_RP_CLIENT_ID:
# Add 'mozilla_django_oidc' authentication backend
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'rosetta.auth.RosettaOIDCAuthenticationBackend'
)
# Base
OIDC_RP_CLIENT_SECRET = os.environ.get('OIDC_RP_CLIENT_SECRET')
OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get('OIDC_OP_AUTHORIZATION_ENDPOINT')
OIDC_OP_TOKEN_ENDPOINT = os.environ.get('OIDC_OP_TOKEN_ENDPOINT')
OIDC_OP_USER_ENDPOINT = os.environ.get('OIDC_OP_USER_ENDPOINT')
OIDC_RP_SIGN_ALGO = os.environ.get('OIDC_RP_SIGN_ALGO', 'RS256')
OIDC_RP_IDP_SIGN_KEY = os.environ.get('OIDC_RP_IDP_SIGN_KEY', None)
OIDC_OP_JWKS_ENDPOINT = os.environ.get('OIDC_OP_JWKS_ENDPOINT', None)
# Check
if OIDC_RP_SIGN_ALGO == 'RS256':
if not OIDC_RP_IDP_SIGN_KEY and not OIDC_OP_JWKS_ENDPOINT:
raise ImproperlyConfigured('RS256 OpenID requires OIDC_RP_IDP_SIGN_KEY or OIDC_OP_JWKS_ENDPOINT to be set')
# Optional
OIDC_USE_NONCE = booleanize(os.environ.get('OIDC_USE_NONCE', False))
OIDC_TOKEN_USE_BASIC_AUTH = booleanize(os.environ.get('OIDC_TOKEN_USE_BASIC_AUTH', True))
# Non-customizable stuff
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
LOGIN_REDIRECT_URL_FAILURE = '/'
#OIDC_AUTHENTICATION_CALLBACK_URL = 'rosetta.local/oidc/callback/'
# Required for the Open ID connect redirects to work properly
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
...@@ -63,7 +63,10 @@ urlpatterns = [ ...@@ -63,7 +63,10 @@ urlpatterns = [
# Custom APIs # Custom APIs
path('api/v1/base/agent/', core_app_api.agent_api.as_view(), name='agent_api'), path('api/v1/base/agent/', core_app_api.agent_api.as_view(), name='agent_api'),
# Open ID Connect Auth
path('oidc/', include('mozilla_django_oidc.urls')),
] ]
# This message here is quite useful when developing in autoreload mode # This message here is quite useful when developing in autoreload mode
......
...@@ -5,3 +5,4 @@ djangorestframework==3.9.3 ...@@ -5,3 +5,4 @@ djangorestframework==3.9.3
django-rest-swagger==2.2.0 django-rest-swagger==2.2.0
dateutils==0.6.6 dateutils==0.6.6
sendgrid==5.3.0 sendgrid==5.3.0
mozilla-django-oidc==1.2.4
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment