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

Update userinfo of users

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