Commit 1c64600c authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Update userinfo of users

parent a6ae9e38
...@@ -75,7 +75,7 @@ def _webpage_client_valid(request): ...@@ -75,7 +75,7 @@ def _webpage_client_valid(request):
): ):
return True return True
LOGGER.error('Failed to authenticate webpage client for RabbitMQ') #LOGGER.error('Failed to authenticate webpage client for RabbitMQ')
return False return False
# VIEWS: authentication and authorization for # VIEWS: authentication and authorization for
...@@ -83,14 +83,14 @@ def _webpage_client_valid(request): ...@@ -83,14 +83,14 @@ def _webpage_client_valid(request):
def user_endpoint(request): def user_endpoint(request):
if _webpage_client_valid(request): if _webpage_client_valid(request):
#LOGGER.info('Authenticated webpage client') LOGGER.info('Authenticated webpage client')
return ALLOW return ALLOW
user = authenticate( user = authenticate(
username=request.POST.get('username'), username=request.POST.get('username'),
password=request.POST.get('password'), password=request.POST.get('password'),
) )
if user: if user is not None:
LOGGER.info('Authenticated client as %s', user) LOGGER.info('Authenticated client as %s', user)
return ALLOW return ALLOW
...@@ -175,7 +175,6 @@ def resource_endpoint(request): ...@@ -175,7 +175,6 @@ def resource_endpoint(request):
) )
return DENY return DENY
def topic_endpoint(request): def topic_endpoint(request):
permission = request.POST.get('permission', []) permission = request.POST.get('permission', [])
resource = request.POST.get('resource', '') resource = request.POST.get('resource', '')
...@@ -215,9 +214,8 @@ def topic_endpoint(request): ...@@ -215,9 +214,8 @@ def topic_endpoint(request):
match = re.search('service.(.+)', routing_key) match = re.search('service.(.+)', routing_key)
if match: if match:
service_name = match.group(1) service_name = match.group(1)
for service in user.site.services.all(): if user.site.services.filter(name=service_name).exists():
if service_name == service.name: return ALLOW
return ALLOW
elif name == 'sites': elif name == 'sites':
if routing_key == user.site.name: if routing_key == user.site.name:
return ALLOW return ALLOW
......
import logging import logging
import json import json
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
from django.core.exceptions import ObjectDoesNotExist
from django.db import models as db_models from django.db import models as db_models
from django_mysql.models import JSONField
from oic.oic import Client from oic.oic import Client
from oic.oic.message import RegistrationResponse from oic.oic.message import RegistrationResponse
from oic.utils.authn.client import CLIENT_AUTHN_METHOD from oic.utils.authn.client import CLIENT_AUTHN_METHOD
...@@ -13,6 +13,9 @@ LOGGER = logging.getLogger(__name__) ...@@ -13,6 +13,9 @@ LOGGER = logging.getLogger(__name__)
OIDC_CLIENT = {} OIDC_CLIENT = {}
def scopes_default():
return []
class OIDCConfig(db_models.Model): class OIDCConfig(db_models.Model):
client_id = db_models.CharField(max_length=200) client_id = db_models.CharField(max_length=200)
...@@ -25,6 +28,13 @@ class OIDCConfig(db_models.Model): ...@@ -25,6 +28,13 @@ class OIDCConfig(db_models.Model):
# does this idp provide us with group informations? # does this idp provide us with group informations?
group_provider = db_models.BooleanField(default=False) group_provider = db_models.BooleanField(default=False)
# scopes as a list of strings
scopes = JSONField(
default=scopes_default,
editable=True,
)
@property @property
def registration_response(self): def registration_response(self):
info = { info = {
...@@ -55,13 +65,13 @@ class OIDCConfig(db_models.Model): ...@@ -55,13 +65,13 @@ class OIDCConfig(db_models.Model):
args = { args = {
'client_id': self.client_id, 'client_id': self.client_id,
'response_type': 'code', 'response_type': 'code',
'scope': ['openid', 'profile', 'email', 'credentials'], 'scope': self.scopes,
'redirect_uri': self.redirect_uri, 'redirect_uri': self.redirect_uri,
'state': state, 'state': state,
} }
auth_req = client.construct_AuthorizationRequest( auth_req = client.construct_AuthorizationRequest(
request_args=args request_args=args,
) )
return auth_req.request(client.authorization_endpoint) return auth_req.request(client.authorization_endpoint)
...@@ -79,12 +89,12 @@ def default_idp(): ...@@ -79,12 +89,12 @@ def default_idp():
class OIDCTokenAuthBackend(object): class OIDCTokenAuthBackend(object):
def get_userinfo(self, request, oidc_client, access_token='', state=None): def get_userinfo(self, oidc_client, access_token=None):
user_info = None user_info = None
if access_token is not None: if access_token is not None:
req = Request( req = Request(
oidc_client.provider_info['userinfo_endpoint']+'?scope=openid&scope=profile', oidc_client.provider_info['userinfo_endpoint'],
) )
auth = ('Bearer ' + access_token) auth = ('Bearer ' + access_token)
req.add_header('Authorization', auth) req.add_header('Authorization', auth)
...@@ -108,25 +118,33 @@ class OIDCTokenAuthBackend(object): ...@@ -108,25 +118,33 @@ class OIDCTokenAuthBackend(object):
# get the user info from the idp # get the user info from the idp
userinfo = self.get_userinfo( userinfo = self.get_userinfo(
request,
oidc_client, oidc_client,
access_token=token, access_token=token,
) )
try: return models.User.get_user(
return models.User.get_user( userinfo,
userinfo, oidc_client,
oidc_client, )
)
except Exception as exception:
LOGGER.error('OIDCTokenAuthBackend: error constructing user: %s', exception)
return None
def get_user(self, user_id): def get_user(self, user_id):
try: query = models.User.objects.filter(
return models.User.objects.get( user_type='oidcuser',
user_type='oidcuser', pk=user_id
pk=user_id )
if query.exists():
if len(query) == 1:
return query.first()
LOGGER.error(
'OIDCTokenAuthBackend: query for user id %s: %s results',
user_id,
len(query),
) )
except ObjectDoesNotExist:
return None return None
LOGGER.error(
'OIDCTokenAuthBackend: query for user id %s: no results',
user_id,
)
return None
...@@ -89,24 +89,6 @@ class AuthCallback(View): ...@@ -89,24 +89,6 @@ class AuthCallback(View):
}, },
) )
) )
# FIXME 'email_verified' in user info is no boolean
# but oic expects it to be
#user_info = oidc_client.do_user_info_request(
# method="GET",
# state=state,
#)
#LOGGER.debug("EXPERIMENT: %s", user_info)
# user_info = self.get_user_info(ac_token_response['access_token'])
# try:
# u = models.User.objects.get(sub=user_info['sub'])
# except:
# u = models.user_from_user_info(user_info)
# u.save()
# response = render(request, 'backend/index.html', context)
user = authenticate( user = authenticate(
request, request,
token=ac_token_response['access_token'], token=ac_token_response['access_token'],
...@@ -117,13 +99,11 @@ class AuthCallback(View): ...@@ -117,13 +99,11 @@ class AuthCallback(View):
if user is None: if user is None:
# authentication failed -> "401" # authentication failed -> "401"
LOGGER.error('User failed to log in') LOGGER.error('User failed to log in')
utils.set_session(request, 'error', 'Login failed') request.session['error'] = 'Authentication failed'
# response = HttpResponse('Unauthorized', status=401)
elif not user.is_active: elif not user.is_active:
# user is deactivated -> "403" # user is deactivated -> "403"
LOGGER.info('%s tried to log in', user) LOGGER.info('%s tried to log in', user)
utils.set_session(request, 'error', 'Account deactivated') request.session['error'] = 'Account deactivated'
# response = HttpResponse('Forbidden', status=403)
else: else:
# user authenticated -> back to frontend # user authenticated -> back to frontend
login(request, user) login(request, user)
......
import logging import logging
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth import logout from django.contrib.auth import logout
from rest_framework import views from rest_framework import views
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny
...@@ -35,22 +34,6 @@ def _api_state_response_data(request): ...@@ -35,22 +34,6 @@ def _api_state_response_data(request):
'user_state': user_state(request.user), 'user_state': user_state(request.user),
} }
# Response for StateView, LogoutView, and all post requests
def _api_state_response(request):
if not request.user.is_authenticated:
return Response({
'user_state': None,
})
response = _api_state_response_data(request)
if 'error' in request.session:
response['error'] = request.session['error']
# we display errors only once
del request.session['error']
return Response(response)
def state_view_data(request): def state_view_data(request):
data = {} data = {}
if request.user.is_authenticated: if request.user.is_authenticated:
...@@ -66,6 +49,12 @@ def state_view_data(request): ...@@ -66,6 +49,12 @@ def state_view_data(request):
data['user'] = None data['user'] = None
data['user_state'] = None data['user_state'] = None
data['services'] = [] data['services'] = []
if 'error' in request.session:
data['error'] = request.session['error']
# we display errors only once
del request.session['error']
return data return data
...@@ -161,7 +150,7 @@ class QuestionnaireView(views.APIView): ...@@ -161,7 +150,7 @@ class QuestionnaireView(views.APIView):
else: else:
LOGGER.error('Received questionnaire answer for non existing item') LOGGER.error('Received questionnaire answer for non existing item')
return _api_state_response(request) return Response(state_view_data(request))
class UserDeletionView(views.APIView): class UserDeletionView(views.APIView):
......
...@@ -280,19 +280,22 @@ class User(AbstractUser): ...@@ -280,19 +280,22 @@ class User(AbstractUser):
if 'sub' not in userinfo: if 'sub' not in userinfo:
raise Exception('get_user needs a userinfo which contains the users subject') raise Exception('get_user needs a userinfo which contains the users subject')
query_result = cls.objects.filter( query = cls.objects.filter(
sub=userinfo['sub'], sub=userinfo['sub'],
idp=idp, idp=idp,
) )
if not query_result.exists(): if not query.exists():
return cls.construct_from_userinfo(userinfo, idp) return cls.construct_from_userinfo(userinfo, idp)
if len(query_result) > 1: if len(query) > 1:
return Exception('Two user instances with same subject from the same idp') return Exception('Two user instances with same subject from the same idp')
# TODO update the users userinfo when it changes user = query.first()
# TODO update the users groupinfo when it changes # update the users userinfo
return query_result.first() user.userinfo = userinfo
user.save()
return user
@classmethod @classmethod
def construct_from_userinfo(cls, userinfo, idp): def construct_from_userinfo(cls, userinfo, idp):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment