def test_get_current_realm(self): request = RequestFactory().get('/') self.assertEqual(utils.get_current_realm(request), settings.DEFAULT_REALM) meta_key = get_meta_http_name(settings.REALM_COOKIE) request.META[meta_key] = 'in-headers' self.assertEqual(utils.get_current_realm(request), 'in-headers') request.COOKIES[settings.REALM_COOKIE] = 'in-cookies' self.assertEqual(utils.get_current_realm(request), 'in-cookies') setattr(request, 'session', {}) request.session[settings.REALM_COOKIE] = 'in-session' self.assertEqual(utils.get_current_realm(request), 'in-session')
def post_authenticate(request): session_state = request.GET.get('session_state') code = request.GET.get('code') realm = get_current_realm(request, default_realm=None) if not session_state or not code or not realm: return redirect_uri = _get_login_url(request) token, userinfo = _authenticate( realm=realm, data={ 'grant_type': 'authorization_code', 'client_id': settings.KEYCLOAK_CLIENT_ID, 'client_session_state': session_state, 'client_session_host': redirect_uri, 'code': code, 'redirect_uri': redirect_uri, }) # save the user token in the session request.session[_KC_TOKEN_SESSION] = token request.session.modified = True return _get_or_create_user(request, userinfo)
def unparse_username(request, username): # the internal username prepends the realm name realm = get_current_realm(request) if realm and username.startswith(f'{realm}__'): username = username[len(f'{realm}__'):] return username
def parse_username(request, username): # the internal username prepends the realm name realm = get_current_realm(request) if realm and not username.startswith(f'{realm}__'): username = f'{realm}__{username}' return username
def get_realm_auth_url(request): realm = get_current_realm(request, default_realm=None) redirect_uri = urllib.parse.quote(_get_login_url(request), safe='') return ( f'{_KC_URL}/{realm}/{_KC_OID_URL}/auth?' f'&client_id={settings.KEYCLOAK_CLIENT_ID}' '&scope=openid' '&response_type=code' f'&redirect_uri={redirect_uri}' )
def add_to_realm(self, request): ''' Adds the instance to the current realm. ''' if not settings.MULTITENANCY: return # add instance to current realm realm = get_current_realm(request) try: self.mt.realm = realm self.mt.save() except ObjectDoesNotExist: MtInstance.objects.create(instance=self, realm=realm)
def check_user_token(request): ''' Checks if the user token is valid refreshing it in keycloak server. ''' token = request.session.get(_KC_TOKEN_SESSION) realm = get_current_realm(request, default_realm=None) if token and realm: # refresh token response = refresh_kc_token(realm, token) try: response.raise_for_status() request.session[_KC_TOKEN_SESSION] = response.json() request.session.modified = True except Exception: logout(request)
def test_auth(self): realm_group = utils.get_auth_group(self.request) self.assertIsNotNone(realm_group) self.assertEqual(realm_group.name, utils.get_current_realm(self.request)) self.assertEqual(self.request.user.groups.count(), 0) # it does not complain if the user does not belong to the realm utils.remove_user_from_realm(self.request, self.request.user) utils.add_user_to_realm(self.request, self.request.user) self.assertEqual(self.request.user.groups.count(), 1) self.assertIn(realm_group, self.request.user.groups.all()) utils.remove_user_from_realm(self.request, self.request.user) self.assertEqual(self.request.user.groups.count(), 0) self.assertNotIn(realm_group, self.request.user.groups.all())
def get_or_create_user(request, username): # gets the existing user or creates a new one _username = parse_username(request, username) try: user = user_objects.get(username=_username) except UserModel.DoesNotExist: realm = get_current_realm(request) user = user_objects.create_user( username=_username, first_name=username, last_name=realm or '', password=user_objects.make_random_password(length=100), ) # only add user if it doesn't exist. add_user_to_realm(request, user) return user
def _user_logged_out(sender, user, request, **kwargs): ''' Removes realm and token from session also logs out from keycloak server making the user token invalid. ''' token = request.session.get(_KC_TOKEN_SESSION) realm = get_current_realm(request, default_realm=None) if token and realm: # logout exec_request( method='post', url=f'{_KC_URL}/{realm}/{_KC_OID_URL}/logout', data={ 'client_id': settings.KEYCLOAK_CLIENT_ID, 'refresh_token': token['refresh_token'], }, )
def check_gateway_token(request): ''' Checks if the gateway token is valid fetching the user info from keycloak server. ''' token = find_in_request_headers(request, settings.GATEWAY_HEADER_TOKEN) realm = get_current_realm(request, default_realm=None) if token and realm: try: userinfo = _get_user_info(realm, token) # flags that we are using the gateway to authenticate request.session[settings.GATEWAY_HEADER_TOKEN] = True request.session[settings.REALM_COOKIE] = realm request.session.modified = True user = _get_or_create_user(request, userinfo) # only login if the user changed otherwise it will refresh the Csrf # token and make the AJAX calls fail. if not hasattr(request, 'user') or request.user.pk != user.pk: login(request, user) # WORKAROUND!!! # Using curl behind the gateway always returns CSRF errors due # to the missing CSRF Token in the request headers. # We are adding it manually to skip this issue but # only if it needs to login csrfCookie = request.META.get('CSRF_COOKIE') if not request.META.get(settings.CSRF_HEADER_NAME): request.META[settings.CSRF_HEADER_NAME] = csrfCookie if not request.session.get(CSRF_SESSION_KEY): request.session[CSRF_SESSION_KEY] = csrfCookie request.user = user except Exception: # something went wrong logout(request) elif request.session.get(settings.GATEWAY_HEADER_TOKEN): # this session was using the gateway to authenticate before logout(request)
def test_no_multitenancy(self, *args): self.assertIsNone(utils.get_multitenancy_model()) self.assertIsNone(utils.get_current_realm(None)) obj1 = TestModel.objects.create(name='two') self.assertFalse(obj1.is_accessible(TEST_REALM)) self.assertFalse(obj1.is_accessible(settings.DEFAULT_REALM)) self.assertIsNone(obj1.get_realm()) self.assertTrue(MtInstance.objects.count() == 0) self.assertTrue(utils.is_accessible_by_realm(self.request, obj1)) self.assertEqual(utils.add_instance_realm_in_headers(obj1, {}), {}) self.assertEqual(utils.add_current_realm_in_headers(self.request, {}), {}) initial_data = TestModel.objects.all() self.assertEqual(utils.filter_by_realm(self.request, initial_data), initial_data) initial_users = get_user_model().objects.all() self.assertEqual( utils.filter_users_by_realm(self.request, initial_users), initial_users) obj1.add_to_realm(self.request) self.assertTrue(MtInstance.objects.count() == 0) self.assertIsNone(utils.get_auth_group(self.request)) self.assertEqual(self.request.user.groups.count(), 0) self.assertTrue( utils.check_user_in_realm(self.request, self.request.user)) utils.add_user_to_realm(self.request, self.request.user) self.assertEqual(self.request.user.groups.count(), 0) self.assertTrue( utils.check_user_in_realm(self.request, self.request.user)) utils.remove_user_from_realm(self.request, self.request.user) self.assertEqual(self.request.user.groups.count(), 0) self.assertTrue( utils.check_user_in_realm(self.request, self.request.user)) self.client.logout() username = '******' email = '*****@*****.**' password = '******' user = get_user_model().objects.create_user( f'{TEST_REALM}__{username}', email, password) token_key = 'token-123456' Token.objects.create(user=user, key=token_key) token_headers = {'HTTP_AUTHORIZATION': f'Token {token_key}'} auth_str = f'{username}:{password}' basic = base64.b64encode(bytearray(auth_str, 'utf-8')).decode('ascii') basic_headers = {'HTTP_AUTHORIZATION': f'Basic {basic}'} auth_str = f'{TEST_REALM}__{username}:{password}' basic = base64.b64encode(bytearray(auth_str, 'utf-8')).decode('ascii') basic_realm_headers = {'HTTP_AUTHORIZATION': f'Basic {basic}'} url = reverse('http-200') response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertEqual( response.json(), {'detail': 'Authentication credentials were not provided.'}) response = self.client.get(url, **basic_headers) self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) self.assertEqual(response.json(), {'detail': 'Invalid username/password.'}) response = self.client.get(url, **basic_realm_headers) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.client.get(url, **token_headers) self.assertEqual(response.status_code, status.HTTP_200_OK) username = '******' email = '*****@*****.**' password = '******' get_user_model().objects.create_superuser(username, email, password) self.assertTrue(self.client.login(username=username, password=password)) response = self.client.get(reverse('get-realms')) self.assertEqual(response.json(), {'realms': [settings.NO_MULTITENANCY_REALM]})
def authenticate_header(self, request): realm = get_current_realm(request) or self.www_authenticate_realm return f'Basic realm="{realm}"'