116 lines
5.0 KiB
Python
116 lines
5.0 KiB
Python
# hobo - portal to configure and deploy applications
|
|
# Copyright (C) 2015-2020 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import json
|
|
import logging
|
|
import sys
|
|
import urllib.parse
|
|
|
|
from django.conf import settings
|
|
from django.db import connection
|
|
from django.http import HttpResponseBadRequest, HttpResponseForbidden, JsonResponse
|
|
from django.utils.deprecation import MiddlewareMixin
|
|
from django.utils.encoding import force_bytes, force_str
|
|
|
|
from hobo.provisionning.utils import NotificationProcessing
|
|
from hobo.rest_authentication import PublikAuthentication, PublikAuthenticationFailed
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ProvisionningMiddleware(MiddlewareMixin, NotificationProcessing):
|
|
def process_request(self, request):
|
|
if not (request.method == 'PUT' and request.path == '/__provision__/'):
|
|
return None
|
|
if 'hobo.environment' in settings.INSTALLED_APPS:
|
|
self.hobo_specific_setup()
|
|
|
|
try:
|
|
user_auth_tuple = PublikAuthentication().authenticate(request)
|
|
except PublikAuthenticationFailed:
|
|
return HttpResponseForbidden()
|
|
if user_auth_tuple is None:
|
|
return HttpResponseForbidden()
|
|
|
|
try:
|
|
notification = json.loads(force_str(request.body))
|
|
except ValueError:
|
|
return HttpResponseBadRequest()
|
|
if not isinstance(notification, dict) or 'objects' not in notification:
|
|
return HttpResponseBadRequest()
|
|
|
|
object_type = notification['objects'].get('@type')
|
|
issuer = notification.get('issuer')
|
|
action = notification.get('@type')
|
|
if not (object_type and action):
|
|
return HttpResponseBadRequest()
|
|
full = notification['full'] if 'full' in notification else False
|
|
data = notification['objects']['data']
|
|
|
|
msg = 'received request for %sing %%d %%s objects (HTTP)' % action
|
|
logger.info(msg, len(notification['objects']['data']), object_type)
|
|
if 'uwsgi' in sys.modules and 'sync' not in request.GET:
|
|
from hobo.provisionning.spooler import provision
|
|
|
|
tenant = getattr(connection, 'tenant', None)
|
|
domain = getattr(tenant, 'domain_url', '')
|
|
object_type = object_type or ''
|
|
domain = domain or ''
|
|
issuer = issuer or ''
|
|
action = action or ''
|
|
full = 'true' if full else 'false'
|
|
body = json.dumps(data)
|
|
provision.spool(
|
|
object_type=force_bytes(object_type),
|
|
domain=force_bytes(domain),
|
|
issuer=force_bytes(issuer),
|
|
action=force_bytes(action),
|
|
body=force_bytes(body),
|
|
full=force_bytes(full),
|
|
)
|
|
else:
|
|
self.provision(object_type=object_type, issuer=issuer, action=action, data=data, full=full)
|
|
return JsonResponse({'err': 0})
|
|
|
|
def hobo_specific_setup(self):
|
|
# much ado about hobo, this is because it is not deployed like other
|
|
# services and will not have a hobo.json in its tenant directory, and
|
|
# will thus be missing settings loaders, etc.
|
|
from hobo.environment.utils import get_local_hobo_dict
|
|
|
|
known_services = getattr(settings, 'KNOWN_SERVICES', None)
|
|
local_hobo_dict = get_local_hobo_dict()
|
|
if not known_services:
|
|
# hobo in a single deployment instance
|
|
settings.KNOWN_SERVICES = known_services = {}
|
|
known_services['hobo'] = {'hobo': local_hobo_dict}
|
|
known_services['authentic'] = {'idp': {}}
|
|
if known_services['hobo']['hobo']['provisionning-url'] == local_hobo_dict['provisionning-url']:
|
|
# hobo in a single deployment instance, or primary hobo in a
|
|
# multi-instances environment
|
|
from hobo.environment.models import Authentic
|
|
from hobo.multitenant.settings_loaders import KnownServices
|
|
|
|
authentic = Authentic.objects.all().first()
|
|
orig = urllib.parse.urlparse(authentic.base_url).netloc.split(':')[0]
|
|
# create stub settings.KNOWN_SERVICES with just enough to get
|
|
# authentication passing.
|
|
idp_service = list(settings.KNOWN_SERVICES['authentic'].values())[0]
|
|
idp_service['verif_orig'] = orig
|
|
idp_service['secret_key'] = KnownServices.shared_secret(
|
|
authentic.secret_key, local_hobo_dict['secret_key']
|
|
)
|