initial implementation of reverse proxy, using django-revproxy from within a middleware
add new config entry "primary_domain" which is used to set the cookie domain
This commit is contained in:
		| @ -53,3 +53,4 @@ values = | ||||
|  | ||||
| [bumpversion:file:passbook/otp/__init__.py] | ||||
|  | ||||
| [bumpversion:file:passbook/app_gw/__init__.py] | ||||
|  | ||||
							
								
								
									
										2
									
								
								debian/etc/passbook/config.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/etc/passbook/config.yml
									
									
									
									
										vendored
									
									
								
							| @ -14,6 +14,8 @@ rabbitmq: guest:guest@localhost/passbook | ||||
| # Error reporting, sends stacktrace to sentry.services.beryju.org | ||||
| error_report_enabled: true | ||||
|  | ||||
| primary_domain: passbook.local | ||||
|  | ||||
| passbook: | ||||
|   sign_up: | ||||
|     # Enables signup, created users are stored in internal Database and created in LDAP if ldap.create_users is true | ||||
|  | ||||
| @ -46,6 +46,7 @@ data: | ||||
|     secret_key: {{ randAlphaNum 50 }} | ||||
|     {{- end }} | ||||
|  | ||||
|     primary_domain: {{ .Values.primary_domain }} | ||||
|     domains: | ||||
|         {{- range .Values.ingress.hosts }} | ||||
|         - {{ . | quote }} | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								passbook/app_gw/.DS_Store
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								passbook/app_gw/.DS_Store
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										2
									
								
								passbook/app_gw/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								passbook/app_gw/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| """passbook Application Security Gateway Header""" | ||||
| __version__ = '0.1.23-beta' | ||||
							
								
								
									
										5
									
								
								passbook/app_gw/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								passbook/app_gw/admin.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| """passbook Application Security Gateway model admin""" | ||||
|  | ||||
| from passbook.lib.admin import admin_autoregister | ||||
|  | ||||
| admin_autoregister('passbook_app_gw') | ||||
							
								
								
									
										11
									
								
								passbook/app_gw/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								passbook/app_gw/apps.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| """passbook Application Security Gateway app""" | ||||
| from django.apps import AppConfig | ||||
|  | ||||
|  | ||||
| class PassbookApplicationApplicationGatewayConfig(AppConfig): | ||||
|     """passbook app_gw app""" | ||||
|  | ||||
|     name = 'passbook.app_gw' | ||||
|     label = 'passbook_app_gw' | ||||
|     verbose_name = 'passbook Application Security Gateway' | ||||
|     mountpoint = 'app_gw/' | ||||
							
								
								
									
										30
									
								
								passbook/app_gw/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								passbook/app_gw/forms.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| """passbook Application Security Gateway Forms""" | ||||
|  | ||||
| from django import forms | ||||
| from django.contrib.admin.widgets import FilteredSelectMultiple | ||||
| from django.utils.translation import gettext as _ | ||||
|  | ||||
| from passbook.app_gw.models import ApplicationGatewayProvider | ||||
| from passbook.lib.fields import DynamicArrayField | ||||
|  | ||||
|  | ||||
| class ApplicationGatewayProviderForm(forms.ModelForm): | ||||
|     """Security Gateway Provider form""" | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         model = ApplicationGatewayProvider | ||||
|         fields = ['server_name', 'upstream', 'enabled', 'authentication_header', | ||||
|                   'default_content_type', 'upstream_ssl_verification'] | ||||
|         widgets = { | ||||
|             'authentication_header': forms.TextInput(), | ||||
|             'default_content_type': forms.TextInput(), | ||||
|             'property_mappings': FilteredSelectMultiple(_('Property Mappings'), False) | ||||
|         } | ||||
|         field_classes = { | ||||
|             'server_name': DynamicArrayField, | ||||
|             'upstream': DynamicArrayField | ||||
|         } | ||||
|         labels = { | ||||
|             'upstream_ssl_verification': _('Verify upstream SSL Certificates?') | ||||
|         } | ||||
							
								
								
									
										222
									
								
								passbook/app_gw/middleware.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								passbook/app_gw/middleware.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,222 @@ | ||||
| """passbook app_gw middleware""" | ||||
| import mimetypes | ||||
| from logging import getLogger | ||||
| from urllib.parse import urlparse | ||||
|  | ||||
| import certifi | ||||
| import urllib3 | ||||
| from django.core.cache import cache | ||||
| from django.utils.http import urlencode | ||||
| from revproxy.exceptions import InvalidUpstream | ||||
| from revproxy.response import get_django_response | ||||
| from revproxy.utils import encode_items, normalize_request_headers | ||||
|  | ||||
| from passbook.app_gw.models import ApplicationGatewayProvider | ||||
| from passbook.core.models import Application | ||||
|  | ||||
| IGNORED_HOSTNAMES_KEY = 'passbook_app_gw_ignored' | ||||
| LOGGER = getLogger(__name__) | ||||
| QUOTE_SAFE = r'<.;>\(}*+|~=-$/_:^@)[{]&\'!,"`' | ||||
| ERRORS_MESSAGES = { | ||||
|     'upstream-no-scheme': ("Upstream URL scheme must be either " | ||||
|                            "'http' or 'https' (%s).") | ||||
| } | ||||
|  | ||||
| # pylint: disable=too-many-instance-attributes | ||||
| class ApplicationGatewayMiddleware: | ||||
|     """Check if request should be proxied or handeled normally""" | ||||
|  | ||||
|     ignored_hosts = [] | ||||
|     request = None | ||||
|     app_gw = None | ||||
|     http = None | ||||
|     http_no_verify = None | ||||
|     host_header = '' | ||||
|  | ||||
|     _parsed_url = None | ||||
|     _request_headers = None | ||||
|  | ||||
|     def __init__(self, get_response): | ||||
|         self.get_response = get_response | ||||
|         self.ignored_hosts = cache.get(IGNORED_HOSTNAMES_KEY, []) | ||||
|         self.http_no_verify = urllib3.PoolManager() | ||||
|         self.http = urllib3.PoolManager( | ||||
|             cert_reqs='CERT_REQUIRED', | ||||
|             ca_certs=certifi.where()) | ||||
|  | ||||
|     def precheck(self, request): | ||||
|         """Check if a request should be proxied or forwarded to passbook""" | ||||
|         # Check if hostname is in cached list of ignored hostnames | ||||
|         # This saves us having to query the database on each request | ||||
|         self.host_header = request.META.get('HTTP_HOST') | ||||
|         if self.host_header in self.ignored_hosts: | ||||
|             LOGGER.debug("%s is ignored", self.host_header) | ||||
|             return True, None | ||||
|         # Look through all ApplicationGatewayProviders and check hostnames | ||||
|         matches = ApplicationGatewayProvider.objects.filter( | ||||
|             server_name__contains=[self.host_header], | ||||
|             enabled=True) | ||||
|         if not matches.exists(): | ||||
|             # Mo matching Providers found, add host header to ignored list | ||||
|             self.ignored_hosts.append(self.host_header) | ||||
|             cache.set(IGNORED_HOSTNAMES_KEY, self.ignored_hosts) | ||||
|             LOGGER.debug("Ignoring %s", self.host_header) | ||||
|             return True, None | ||||
|         # At this point we're certain there's a matching ApplicationGateway | ||||
|         if len(matches) > 1: | ||||
|             # TODO This should never happen | ||||
|             raise ValueError | ||||
|         app_gw = matches.first() | ||||
|         try: | ||||
|             # Check if ApplicationGateway is associcaited with application | ||||
|             getattr(app_gw, 'application') | ||||
|             return False, app_gw | ||||
|         except Application.DoesNotExist: | ||||
|             LOGGER.debug("ApplicationGateway not associated with Application") | ||||
|             return True, None | ||||
|         return True, None | ||||
|  | ||||
|     def __call__(self, request): | ||||
|         forward, self.app_gw = self.precheck(request) | ||||
|         if forward: | ||||
|             return self.get_response(request) | ||||
|         self.request = request | ||||
|         return self.dispatch(request) | ||||
|  | ||||
|     def get_upstream(self): | ||||
|         """Get upstream as parsed url""" | ||||
|         # TODO: How to choose upstream? | ||||
|         upstream = self.app_gw.upstream[0] | ||||
|  | ||||
|         if not getattr(self, '_parsed_url', None): | ||||
|             self._parsed_url = urlparse(upstream) | ||||
|  | ||||
|         if self._parsed_url.scheme not in ('http', 'https'): | ||||
|             raise InvalidUpstream(ERRORS_MESSAGES['upstream-no-scheme'] % | ||||
|                                   upstream) | ||||
|  | ||||
|         return upstream | ||||
|  | ||||
|     # def _format_path_to_redirect(self, request): | ||||
|     #     full_path = request.get_full_path() | ||||
|     #     LOGGER.debug("Dispatch full path: %s", full_path) | ||||
|     #     for from_re, to_pattern in []: | ||||
|     #         if from_re.match(full_path): | ||||
|     #             redirect_to = from_re.sub(to_pattern, full_path) | ||||
|     #             LOGGER.debug("Redirect to: %s", redirect_to) | ||||
|     #             return redirect_to | ||||
|     #     return None | ||||
|  | ||||
|     def get_proxy_request_headers(self, request): | ||||
|         """Get normalized headers for the upstream | ||||
|         Gets all headers from the original request and normalizes them. | ||||
|         Normalization occurs by removing the prefix ``HTTP_`` and | ||||
|         replacing and ``_`` by ``-``. Example: ``HTTP_ACCEPT_ENCODING`` | ||||
|         becames ``Accept-Encoding``. | ||||
|         .. versionadded:: 0.9.1 | ||||
|         :param request:  The original HTTPRequest instance | ||||
|         :returns:  Normalized headers for the upstream | ||||
|         """ | ||||
|         return normalize_request_headers(request) | ||||
|  | ||||
|     def get_request_headers(self): | ||||
|         """Return request headers that will be sent to upstream. | ||||
|         The header REMOTE_USER is set to the current user | ||||
|         if AuthenticationMiddleware is enabled and | ||||
|         the view's add_remote_user property is True. | ||||
|         .. versionadded:: 0.9.8 | ||||
|         """ | ||||
|         request_headers = self.get_proxy_request_headers(self.request) | ||||
|  | ||||
|         if hasattr(self.request, 'user') and self.request.user.is_active: | ||||
|             request_headers[self.app_gw.authentication_header] = self.request.user.get_username() | ||||
|             LOGGER.info("REMOTE_USER set") | ||||
|  | ||||
|         return request_headers | ||||
|  | ||||
|     # def get_quoted_path(self, path): | ||||
|     #     """Return quoted path to be used in proxied request""" | ||||
|     #     return quote_plus(path.encode('utf8'), QUOTE_SAFE) | ||||
|  | ||||
|     def get_encoded_query_params(self): | ||||
|         """Return encoded query params to be used in proxied request""" | ||||
|         get_data = encode_items(self.request.GET.lists()) | ||||
|         return urlencode(get_data) | ||||
|  | ||||
|     def _created_proxy_response(self, request): | ||||
|         request_payload = request.body | ||||
|  | ||||
|         LOGGER.debug("Request headers: %s", self._request_headers) | ||||
|  | ||||
|         path = request.get_full_path() | ||||
|         request_url = self.get_upstream() + path | ||||
|         LOGGER.debug("Request URL: %s", request_url) | ||||
|  | ||||
|         if request.GET: | ||||
|             request_url += '?' + self.get_encoded_query_params() | ||||
|             LOGGER.debug("Request URL: %s", request_url) | ||||
|  | ||||
|         http = self.http | ||||
|         if not self.app_gw.upstream_ssl_verification: | ||||
|             http = self.http_no_verify | ||||
|  | ||||
|         try: | ||||
|             proxy_response = http.urlopen(request.method, | ||||
|                                           request_url, | ||||
|                                           redirect=False, | ||||
|                                           retries=None, | ||||
|                                           headers=self._request_headers, | ||||
|                                           body=request_payload, | ||||
|                                           decode_content=False, | ||||
|                                           preload_content=False) | ||||
|             LOGGER.debug("Proxy response header: %s", | ||||
|                          proxy_response.getheaders()) | ||||
|         except urllib3.exceptions.HTTPError as error: | ||||
|             LOGGER.exception(error) | ||||
|             raise | ||||
|  | ||||
|         return proxy_response | ||||
|  | ||||
|     def _replace_host_on_redirect_location(self, request, proxy_response): | ||||
|         location = proxy_response.headers.get('Location') | ||||
|         if location: | ||||
|             if request.is_secure(): | ||||
|                 scheme = 'https://' | ||||
|             else: | ||||
|                 scheme = 'http://' | ||||
|             request_host = scheme + self.host_header | ||||
|  | ||||
|             upstream_host_http = 'http://' + self._parsed_url.netloc | ||||
|             upstream_host_https = 'https://' + self._parsed_url.netloc | ||||
|  | ||||
|             location = location.replace(upstream_host_http, request_host) | ||||
|             location = location.replace(upstream_host_https, request_host) | ||||
|             proxy_response.headers['Location'] = location | ||||
|             LOGGER.debug("Proxy response LOCATION: %s", | ||||
|                          proxy_response.headers['Location']) | ||||
|  | ||||
|     def _set_content_type(self, request, proxy_response): | ||||
|         content_type = proxy_response.headers.get('Content-Type') | ||||
|         if not content_type: | ||||
|             content_type = (mimetypes.guess_type(request.path)[0] or | ||||
|                             self.app_gw.default_content_type) | ||||
|             proxy_response.headers['Content-Type'] = content_type | ||||
|             LOGGER.debug("Proxy response CONTENT-TYPE: %s", | ||||
|                          proxy_response.headers['Content-Type']) | ||||
|  | ||||
|     def dispatch(self, request): | ||||
|         """Build proxied request and pass to upstream""" | ||||
|         self._request_headers = self.get_request_headers() | ||||
|  | ||||
|         # redirect_to = self._format_path_to_redirect(request) | ||||
|         # if redirect_to: | ||||
|         #     return redirect(redirect_to) | ||||
|  | ||||
|         proxy_response = self._created_proxy_response(request) | ||||
|  | ||||
|         self._replace_host_on_redirect_location(request, proxy_response) | ||||
|         self._set_content_type(request, proxy_response) | ||||
|         response = get_django_response(proxy_response, strict_cookies=False) | ||||
|  | ||||
|         LOGGER.debug("RESPONSE RETURNED: %s", response) | ||||
|         return response | ||||
							
								
								
									
										
											BIN
										
									
								
								passbook/app_gw/migrations/.DS_Store
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								passbook/app_gw/migrations/.DS_Store
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										50
									
								
								passbook/app_gw/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								passbook/app_gw/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| # Generated by Django 2.1.7 on 2019-03-20 21:38 | ||||
|  | ||||
| import django.contrib.postgres.fields | ||||
| import django.db.models.deletion | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     initial = True | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('passbook_core', '0020_groupmembershippolicy'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='ApplicationGatewayProvider', | ||||
|             fields=[ | ||||
|                 ('provider_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Provider')), | ||||
|                 ('server_name', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), size=None)), | ||||
|                 ('upstream', django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), size=None)), | ||||
|                 ('enabled', models.BooleanField(default=True)), | ||||
|                 ('authentication_header', models.TextField(default='X-Remote-User')), | ||||
|                 ('default_content_type', models.TextField(default='application/octet-stream')), | ||||
|                 ('upstream_ssl_verification', models.BooleanField(default=True)), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'Application Gateway Provider', | ||||
|                 'verbose_name_plural': 'Application Gateway Providers', | ||||
|             }, | ||||
|             bases=('passbook_core.provider',), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='RewriteRule', | ||||
|             fields=[ | ||||
|                 ('propertymapping_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.PropertyMapping')), | ||||
|                 ('match', models.TextField()), | ||||
|                 ('halt', models.BooleanField(default=False)), | ||||
|                 ('replacement', models.TextField()), | ||||
|                 ('redirect', models.CharField(choices=[('internal', 'Internal'), (301, 'Moved Permanently'), (302, 'Found')], max_length=50)), | ||||
|                 ('conditions', models.ManyToManyField(to='passbook_core.Policy')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'Rewrite Rule', | ||||
|                 'verbose_name_plural': 'Rewrite Rules', | ||||
|             }, | ||||
|             bases=('passbook_core.propertymapping',), | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										0
									
								
								passbook/app_gw/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								passbook/app_gw/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										61
									
								
								passbook/app_gw/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								passbook/app_gw/models.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| """passbook app_gw models""" | ||||
| from django.contrib.postgres.fields import ArrayField | ||||
| from django.db import models | ||||
| from django.utils.translation import gettext as _ | ||||
|  | ||||
| from passbook.core.models import Policy, PropertyMapping, Provider | ||||
|  | ||||
|  | ||||
| class ApplicationGatewayProvider(Provider): | ||||
|     """Virtual server which proxies requests to any hostname in server_name to upstream""" | ||||
|  | ||||
|     server_name = ArrayField(models.TextField()) | ||||
|     upstream = ArrayField(models.TextField()) | ||||
|     enabled = models.BooleanField(default=True) | ||||
|  | ||||
|     authentication_header = models.TextField(default='X-Remote-User') | ||||
|     default_content_type = models.TextField(default='application/octet-stream') | ||||
|     upstream_ssl_verification = models.BooleanField(default=True) | ||||
|  | ||||
|     form = 'passbook.app_gw.forms.ApplicationGatewayProviderForm' | ||||
|  | ||||
|     @property | ||||
|     def name(self): | ||||
|         """since this model has no name property, return a joined list of server_names as name""" | ||||
|         return ', '.join(self.server_name) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return "Application Gateway %s" % ', '.join(self.server_name) | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         verbose_name = _('Application Gateway Provider') | ||||
|         verbose_name_plural = _('Application Gateway Providers') | ||||
|  | ||||
|  | ||||
| class RewriteRule(PropertyMapping): | ||||
|     """Rewrite requests matching `match` with `replacement`, if all polcies in `conditions` apply""" | ||||
|  | ||||
|     REDIRECT_INTERNAL = 'internal' | ||||
|     REDIRECT_PERMANENT = 301 | ||||
|     REDIRECT_FOUND = 302 | ||||
|  | ||||
|     REDIRECTS = ( | ||||
|         (REDIRECT_INTERNAL, _('Internal')), | ||||
|         (REDIRECT_PERMANENT, _('Moved Permanently')), | ||||
|         (REDIRECT_FOUND, _('Found')), | ||||
|     ) | ||||
|  | ||||
|     match = models.TextField() | ||||
|     halt = models.BooleanField(default=False) | ||||
|     conditions = models.ManyToManyField(Policy) | ||||
|     replacement = models.TextField() # python formatted strings, use {match.1} | ||||
|     redirect = models.CharField(max_length=50, choices=REDIRECTS) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return "Rewrite Rule %s" % self.name | ||||
|  | ||||
|     class Meta: | ||||
|  | ||||
|         verbose_name = _('Rewrite Rule') | ||||
|         verbose_name_plural = _('Rewrite Rules') | ||||
							
								
								
									
										2
									
								
								passbook/app_gw/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								passbook/app_gw/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| django-revproxy | ||||
| urllib3[secure] | ||||
							
								
								
									
										5
									
								
								passbook/app_gw/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								passbook/app_gw/settings.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| """Application Security Gateway settings""" | ||||
|  | ||||
| # INSTALLED_APPS = [ | ||||
| #     'revproxy' | ||||
| # ] | ||||
							
								
								
									
										2
									
								
								passbook/app_gw/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								passbook/app_gw/urls.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| """passbook app_gw urls""" | ||||
| urlpatterns = [] | ||||
| @ -34,7 +34,7 @@ SECRET_KEY = CONFIG.get('secret_key') | ||||
| # SECURITY WARNING: don't run with debug turned on in production! | ||||
| DEBUG = CONFIG.get('debug') | ||||
| INTERNAL_IPS = ['127.0.0.1'] | ||||
| ALLOWED_HOSTS = CONFIG.get('domains', []) | ||||
| ALLOWED_HOSTS = CONFIG.get('domains', []) + CONFIG.get('primary_domain') | ||||
| SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') | ||||
|  | ||||
| LOGIN_URL = 'passbook_core:auth-login' | ||||
| @ -45,6 +45,7 @@ AUTH_USER_MODEL = 'passbook_core.User' | ||||
|  | ||||
| CSRF_COOKIE_NAME = 'passbook_csrf' | ||||
| SESSION_COOKIE_NAME = 'passbook_session' | ||||
| SESSION_COOKIE_DOMAIN = CONFIG.get('primary_domain') | ||||
| LANGUAGE_COOKIE_NAME = 'passbook_language' | ||||
|  | ||||
| AUTHENTICATION_BACKENDS = [ | ||||
| @ -79,6 +80,7 @@ INSTALLED_APPS = [ | ||||
|     'passbook.pretend.apps.PassbookPretendConfig', | ||||
|     'passbook.password_expiry_policy.apps.PassbookPasswordExpiryPolicyConfig', | ||||
|     'passbook.suspicious_policy.apps.PassbookSuspiciousPolicyConfig', | ||||
|     'passbook.app_gw.apps.PassbookApplicationApplicationGatewayConfig', | ||||
| ] | ||||
|  | ||||
| # Message Tag fix for bootstrap CSS Classes | ||||
| @ -100,11 +102,12 @@ REST_FRAMEWORK = { | ||||
| } | ||||
|  | ||||
| MIDDLEWARE = [ | ||||
|     'django.middleware.security.SecurityMiddleware', | ||||
|     'django.contrib.sessions.middleware.SessionMiddleware', | ||||
|     'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||
|     'passbook.app_gw.middleware.ApplicationGatewayMiddleware', | ||||
|     'django.middleware.security.SecurityMiddleware', | ||||
|     'django.middleware.common.CommonMiddleware', | ||||
|     'django.middleware.csrf.CsrfViewMiddleware', | ||||
|     'django.contrib.auth.middleware.AuthenticationMiddleware', | ||||
|     'django.contrib.messages.middleware.MessageMiddleware', | ||||
|     'django.middleware.clickjacking.XFrameOptionsMiddleware', | ||||
|     'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware', | ||||
|  | ||||
| @ -34,6 +34,8 @@ rabbitmq: guest:guest@localhost/passbook | ||||
| error_report_enabled: true | ||||
| secret_key: 9$@r!d^1^jrn#fk#1#@ks#9&i$^s#1)_13%$rwjrhd=e8jfi_s | ||||
|  | ||||
| primary_domain: 'localhost' | ||||
|  | ||||
| passbook: | ||||
|   sign_up: | ||||
|     # Enables signup, created users are stored in internal Database and created in LDAP if ldap.create_users is true | ||||
|  | ||||
| @ -7,3 +7,4 @@ | ||||
| -r passbook/captcha_factor/requirements.txt | ||||
| -r passbook/admin/requirements.txt | ||||
| -r passbook/api/requirements.txt | ||||
| -r passbook/app_gw/requirements.txt | ||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer