Andrew Bogott has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/333983 )

Change subject: Horizon:  Forward some custom files from liberty
......................................................................

Horizon:  Forward some custom files from liberty

Change-Id: I99b29bc0195f243c13dfd313c23bb0140c820604
---
A modules/openstack/files/mitaka/horizon/keystone_policy.json
A modules/openstack/files/mitaka/horizon/openstack_auth/backend.py
A modules/openstack/files/mitaka/horizon/puppet_group_add.py
A modules/openstack/files/mitaka/horizon/puppet_prefix_tab_enable.py
A modules/openstack/files/mitaka/horizon/puppet_tab_enable.py
5 files changed, 465 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/operations/puppet 
refs/changes/83/333983/1

diff --git a/modules/openstack/files/mitaka/horizon/keystone_policy.json 
b/modules/openstack/files/mitaka/horizon/keystone_policy.json
new file mode 100644
index 0000000..0bd9546
--- /dev/null
+++ b/modules/openstack/files/mitaka/horizon/keystone_policy.json
@@ -0,0 +1,183 @@
+{
+    "admin_required": "role:admin or is_admin:1",
+    "service_role": "role:service",
+    "service_or_admin": "rule:admin_required or rule:service_role",
+    "owner" : "user_id:%(user_id)s",
+    "admin_or_owner": "rule:admin_required or rule:owner",
+    "token_subject": "user_id:%(target.token.user_id)s",
+    "admin_or_token_subject": "rule:admin_required or rule:token_subject",
+ 
+    "default": "rule:admin_required",
+ 
+    "identity:get_region": "",
+    "identity:list_regions": "rule:admin_required",
+    "identity:create_region": "rule:admin_required",
+    "identity:update_region": "rule:admin_required",
+    "identity:delete_region": "rule:admin_required",
+ 
+    "identity:get_service": "",
+    "identity:list_services": "",
+    "identity:create_service": "rule:admin_required",
+    "identity:update_service": "rule:admin_required",
+    "identity:delete_service": "rule:admin_required",
+ 
+    "identity:get_endpoint": "",
+    "identity:list_endpoints": "",
+    "identity:create_endpoint": "rule:admin_required",
+    "identity:update_endpoint": "rule:admin_required",
+    "identity:delete_endpoint": "rule:admin_required",
+ 
+    "identity:get_domain": "rule:admin_required",
+    "identity:list_domains": "rule:admin_required",
+    "identity:create_domain": "rule:admin_required",
+    "identity:update_domain": "rule:admin_required",
+    "identity:delete_domain": "rule:admin_required",
+ 
+    "identity:get_project": "rule:admin_required",
+    "identity:list_projects": "role:admin_required",
+    "identity:list_user_projects": "",
+    "identity:create_project": "rule:admin_required",
+    "identity:update_project": "rule:admin_required",
+    "identity:delete_project": "rule:admin_required",
+ 
+    "identity:get_user": "rule:admin_required",
+    "identity:list_users": "rule:admin_required",
+    "identity:create_user": "rule:admin_required",
+    "identity:update_user": "rule:admin_required",
+    "identity:delete_user": "rule:admin_required",
+    "identity:change_password": "rule:admin_or_owner",
+ 
+    "identity:get_group": "rule:admin_required",
+    "identity:list_groups": "rule:admin_required",
+    "identity:list_groups_for_user": "rule:admin_or_owner",
+    "identity:create_group": "rule:admin_required",
+    "identity:update_group": "rule:admin_required",
+    "identity:delete_group": "rule:admin_required",
+    "identity:list_users_in_group": "rule:admin_required",
+    "identity:remove_user_from_group": "rule:admin_required",
+    "identity:check_user_in_group": "rule:admin_required",
+    "identity:add_user_to_group": "rule:admin_required",
+ 
+    "identity:get_credential": "rule:admin_required",
+    "identity:list_credentials": "rule:admin_required",
+    "identity:create_credential": "rule:admin_required",
+    "identity:update_credential": "rule:admin_required",
+    "identity:delete_credential": "rule:admin_required",
+ 
+    "identity:ec2_get_credential": "rule:admin_required or (rule:owner and 
user_id:%(target.credential.user_id)s)",
+    "identity:ec2_list_credentials": "rule:admin_or_owner",
+    "identity:ec2_create_credential": "rule:admin_or_owner",
+    "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and 
user_id:%(target.credential.user_id)s)",
+ 
+    "identity:get_role": "",
+    "identity:list_roles": "rule:admin_required",
+    "identity:create_role": "rule:admin_required",
+    "identity:update_role": "rule:admin_required",
+    "identity:delete_role": "rule:admin_required",
+ 
+    "identity:check_grant": "rule:admin_required",
+    "identity:list_grants": "rule:admin_required",
+    "identity:create_grant": "rule:admin_required",
+    "identity:revoke_grant": "rule:admin_required",
+ 
+    "identity:list_role_assignments": "rule:admin_required",
+ 
+    "identity:get_policy": "rule:admin_required",
+    "identity:list_policies": "rule:admin_required",
+    "identity:create_policy": "rule:admin_required",
+    "identity:update_policy": "rule:admin_required",
+    "identity:delete_policy": "rule:admin_required",
+ 
+    "identity:check_token": "rule:admin_or_token_subject",
+    "identity:validate_token": "rule:service_admin_or_token_subject",
+    "identity:validate_token_head": "rule:service_or_admin",
+    "identity:revocation_list": "rule:service_or_admin",
+    "identity:revoke_token": "rule:admin_or_token_subject",
+ 
+    "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
+    "identity:list_trusts": "rule:admin_required",
+    "identity:list_roles_for_trust": "",
+    "identity:get_role_for_trust": "",
+    "identity:delete_trust": "",
+ 
+    "identity:create_consumer": "rule:admin_required",
+    "identity:get_consumer": "rule:admin_required",
+    "identity:list_consumers": "rule:admin_required",
+    "identity:delete_consumer": "rule:admin_required",
+    "identity:update_consumer": "rule:admin_required",
+ 
+    "identity:authorize_request_token": "rule:admin_required",
+    "identity:list_access_token_roles": "rule:admin_required",
+    "identity:get_access_token_role": "rule:admin_required",
+    "identity:list_access_tokens": "rule:admin_required",
+    "identity:get_access_token": "rule:admin_required",
+    "identity:delete_access_token": "rule:admin_required",
+ 
+    "identity:list_projects_for_endpoint": "rule:admin_required",
+    "identity:add_endpoint_to_project": "rule:admin_required",
+    "identity:check_endpoint_in_project": "rule:admin_required",
+    "identity:list_endpoints_for_project": "rule:admin_required",
+    "identity:remove_endpoint_from_project": "rule:admin_required",
+ 
+    "identity:create_endpoint_group": "rule:admin_required",
+    "identity:list_endpoint_groups": "rule:admin_required",
+    "identity:get_endpoint_group": "rule:admin_required",
+    "identity:update_endpoint_group": "rule:admin_required",
+    "identity:delete_endpoint_group": "rule:admin_required",
+    "identity:list_projects_associated_with_endpoint_group": 
"rule:admin_required",
+    "identity:list_endpoints_associated_with_endpoint_group": 
"rule:admin_required",
+    "identity:get_endpoint_group_in_project": "rule:admin_required",
+    "identity:list_endpoint_groups_for_project": "rule:admin_required",
+    "identity:add_endpoint_group_to_project": "rule:admin_required",
+    "identity:remove_endpoint_group_from_project": "rule:admin_required",
+ 
+    "identity:create_identity_provider": "rule:admin_required",
+    "identity:list_identity_providers": "rule:admin_required",
+    "identity:get_identity_providers": "rule:admin_required",
+    "identity:update_identity_provider": "rule:admin_required",
+    "identity:delete_identity_provider": "rule:admin_required",
+ 
+    "identity:create_protocol": "rule:admin_required",
+    "identity:update_protocol": "rule:admin_required",
+    "identity:get_protocol": "rule:admin_required",
+    "identity:list_protocols": "rule:admin_required",
+    "identity:delete_protocol": "rule:admin_required",
+ 
+    "identity:create_mapping": "rule:admin_required",
+    "identity:get_mapping": "rule:admin_required",
+    "identity:list_mappings": "rule:admin_required",
+    "identity:delete_mapping": "rule:admin_required",
+    "identity:update_mapping": "rule:admin_required",
+ 
+    "identity:create_service_provider": "rule:admin_required",
+    "identity:list_service_providers": "rule:admin_required",
+    "identity:get_service_provider": "rule:admin_required",
+    "identity:update_service_provider": "rule:admin_required",
+    "identity:delete_service_provider": "rule:admin_required",
+ 
+    "identity:get_auth_catalog": "",
+    "identity:get_auth_projects": "",
+    "identity:get_auth_domains": "",
+ 
+    "identity:list_projects_for_groups": "",
+    "identity:list_domains_for_groups": "",
+ 
+    "identity:list_revoke_events": "",
+ 
+    "identity:create_policy_association_for_endpoint": "rule:admin_required",
+    "identity:check_policy_association_for_endpoint": "rule:admin_required",
+    "identity:delete_policy_association_for_endpoint": "rule:admin_required",
+    "identity:create_policy_association_for_service": "rule:admin_required",
+    "identity:check_policy_association_for_service": "rule:admin_required",
+    "identity:delete_policy_association_for_service": "rule:admin_required",
+    "identity:create_policy_association_for_region_and_service": 
"rule:admin_required",
+    "identity:check_policy_association_for_region_and_service": 
"rule:admin_required",
+    "identity:delete_policy_association_for_region_and_service": 
"rule:admin_required",
+    "identity:get_policy_for_endpoint": "rule:admin_required",
+    "identity:list_endpoints_for_policy": "rule:admin_required",
+ 
+    "identity:create_domain_config": "rule:admin_required",
+    "identity:get_domain_config": "rule:admin_required",
+    "identity:update_domain_config": "rule:admin_required",
+    "identity:delete_domain_config": "rule:admin_required"
+}
diff --git a/modules/openstack/files/mitaka/horizon/openstack_auth/backend.py 
b/modules/openstack/files/mitaka/horizon/openstack_auth/backend.py
new file mode 100644
index 0000000..10f5da4
--- /dev/null
+++ b/modules/openstack/files/mitaka/horizon/openstack_auth/backend.py
@@ -0,0 +1,264 @@
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+""" Module defining the Django auth backend class for the Keystone API. """
+
+import datetime
+import logging
+import pytz
+
+from django.conf import settings
+from django.utils.module_loading import import_string  # noqa
+from django.utils.translation import ugettext_lazy as _
+from keystoneclient import exceptions as keystone_exceptions
+
+from openstack_auth import exceptions
+from openstack_auth import user as auth_user
+from openstack_auth import utils
+
+
+LOG = logging.getLogger(__name__)
+
+
+KEYSTONE_CLIENT_ATTR = "_keystoneclient"
+
+
+class KeystoneBackend(object):
+    """Django authentication backend for use with ``django.contrib.auth``."""
+
+    def __init__(self):
+        self._auth_plugins = None
+
+    @property
+    def auth_plugins(self):
+        if self._auth_plugins is None:
+            plugins = getattr(
+                settings,
+                'AUTHENTICATION_PLUGINS',
+                ['openstack_auth.plugin.password.PasswordPlugin',
+                 'openstack_auth.plugin.token.TokenPlugin'])
+
+            self._auth_plugins = [import_string(p)() for p in plugins]
+
+        return self._auth_plugins
+
+    def check_auth_expiry(self, auth_ref, margin=None):
+        if not utils.is_token_valid(auth_ref, margin):
+            msg = _("The authentication token issued by the Identity service "
+                    "has expired.")
+            LOG.warning("The authentication token issued by the Identity "
+                        "service appears to have expired before it was "
+                        "issued. This may indicate a problem with either your "
+                        "server or client configuration.")
+            raise exceptions.KeystoneAuthException(msg)
+        return True
+
+    def get_user(self, user_id):
+        """Returns the current user from the session data.
+
+        If authenticated, this return the user object based on the user ID
+        and session data.
+
+        Note: this required monkey-patching the ``contrib.auth`` middleware
+        to make the ``request`` object available to the auth backend class.
+        """
+        if (hasattr(self, 'request') and
+                user_id == self.request.session["user_id"]):
+            token = self.request.session['token']
+            endpoint = self.request.session['region_endpoint']
+            services_region = self.request.session['services_region']
+            user = auth_user.create_user_from_token(self.request, token,
+                                                    endpoint, services_region)
+            return user
+        else:
+            return None
+
+    def authenticate(self, auth_url=None, **kwargs):
+        """Authenticates a user via the Keystone Identity API."""
+        LOG.debug('Beginning user authentication')
+
+        if not auth_url:
+            auth_url = settings.OPENSTACK_KEYSTONE_URL
+
+        auth_url = utils.fix_auth_url_version(auth_url)
+
+        for plugin in self.auth_plugins:
+            unscoped_auth = plugin.get_plugin(auth_url=auth_url, **kwargs)
+
+            if unscoped_auth:
+                break
+        else:
+            msg = _('No authentication backend could be determined to '
+                    'handle the provided credentials.')
+            LOG.warn('No authentication backend could be determined to '
+                     'handle the provided credentials. This is likely a '
+                     'configuration error that should be addressed.')
+            raise exceptions.KeystoneAuthException(msg)
+
+        session = utils.get_session()
+        keystone_client_class = utils.get_keystone_client().Client
+
+        try:
+            unscoped_auth_ref = unscoped_auth.get_access(session)
+        except keystone_exceptions.ConnectionRefused as exc:
+            LOG.error(str(exc))
+            msg = _('Unable to establish connection to keystone endpoint.')
+            raise exceptions.KeystoneAuthException(msg)
+        except (keystone_exceptions.Unauthorized,
+                keystone_exceptions.Forbidden,
+                keystone_exceptions.NotFound) as exc:
+            LOG.debug(str(exc))
+            raise exceptions.KeystoneAuthException(_('Invalid credentials.'))
+        except (keystone_exceptions.ClientException,
+                keystone_exceptions.AuthorizationFailure) as exc:
+            msg = _("An error occurred authenticating. "
+                    "Please try again later.")
+            LOG.debug(str(exc))
+            raise exceptions.KeystoneAuthException(msg)
+
+        # Check expiry for our unscoped auth ref.
+        self.check_auth_expiry(unscoped_auth_ref)
+
+        projects = plugin.list_projects(session,
+                                        unscoped_auth,
+                                        unscoped_auth_ref)
+        # Attempt to scope only to enabled projects
+        projects = [project for project in projects if project.enabled]
+
+        # Abort if there are no projects for this user
+        if not projects:
+            msg = _('You are not authorized for any projects.')
+            raise exceptions.KeystoneAuthException(msg)
+
+        # the recent project id a user might have set in a cookie
+        recent_project = None
+        request = kwargs.get('request')
+
+        if request:
+            # Grab recent_project found in the cookie, try to scope
+            # to the last project used.
+            recent_project = request.COOKIES.get('recent_project')
+
+        # if a most recent project was found, try using it first
+        if recent_project:
+            for pos, project in enumerate(projects):
+                if project.id == recent_project:
+                    # move recent project to the beginning
+                    projects.pop(pos)
+                    projects.insert(0, project)
+                    break
+
+        for project in projects:
+            token = unscoped_auth_ref.auth_token
+            scoped_auth = utils.get_token_auth_plugin(auth_url,
+                                                      token=token,
+                                                      project_id=project.id)
+
+            try:
+                scoped_auth_ref = scoped_auth.get_access(session)
+            except (keystone_exceptions.ClientException,
+                    keystone_exceptions.AuthorizationFailure):
+                pass
+            else:
+                break
+        else:
+            msg = _("Unable to authenticate to any available projects.")
+            raise exceptions.KeystoneAuthException(msg)
+
+        # Check expiry for our new scoped token.
+        self.check_auth_expiry(scoped_auth_ref)
+
+        interface = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'public')
+
+        # If we made it here we succeeded. Create our User!
+        unscoped_token = unscoped_auth_ref.auth_token
+        user = auth_user.create_user_from_token(
+            request,
+            auth_user.Token(scoped_auth_ref, unscoped_token=unscoped_token),
+            scoped_auth_ref.service_catalog.url_for(endpoint_type=interface))
+
+        if request is not None:
+            request.session['unscoped_token'] = unscoped_token
+            request.user = user
+            if 'extended_session' in kwargs and kwargs['extended_session']:
+                timeout = getattr(settings, "SESSION_TIMEOUT", 86400)
+            else:
+                timeout = getattr(settings, "SESSION_SHORT_TIMEOUT", 1800)
+            token_life = user.token.expires - datetime.datetime.now(pytz.utc)
+
+            # Fix for 
https://bugs.launchpad.net/django-openstack-auth/+bug/1562452:
+            session_time = min(timeout, int(token_life.total_seconds()))
+            request.session.set_expiry(session_time)
+
+            scoped_client = keystone_client_class(session=session,
+                                                  auth=scoped_auth)
+
+            # Support client caching to save on auth calls.
+            setattr(request, KEYSTONE_CLIENT_ATTR, scoped_client)
+
+        LOG.debug('Authentication completed.')
+        return user
+
+    def get_group_permissions(self, user, obj=None):
+        """Returns an empty set since Keystone doesn't support "groups"."""
+        # Keystone V3 added "groups". The Auth token response includes the
+        # roles from the user's Group assignment. It should be fine just
+        # returning an empty set here.
+        return set()
+
+    def get_all_permissions(self, user, obj=None):
+        """Returns a set of permission strings that the user has.
+
+        This permission available to the user is derived from the user's
+        Keystone "roles".
+
+        The permissions are returned as ``"openstack.{{ role.name }}"``.
+        """
+        if user.is_anonymous() or obj is not None:
+            return set()
+        # TODO(gabrielhurley): Integrate policy-driven RBAC
+        #                      when supported by Keystone.
+        role_perms = set(["openstack.roles.%s" % role['name'].lower()
+                          for role in user.roles])
+
+        services = []
+        for service in user.service_catalog:
+            try:
+                service_type = service['type']
+            except KeyError:
+                continue
+            service_regions = [utils.get_endpoint_region(endpoint) for endpoint
+                               in service.get('endpoints', [])]
+            if user.services_region in service_regions:
+                services.append(service_type.lower())
+        service_perms = set(["openstack.services.%s" % service
+                             for service in services])
+        return role_perms | service_perms
+
+    def has_perm(self, user, perm, obj=None):
+        """Returns True if the given user has the specified permission."""
+        if not user.is_active:
+            return False
+        return perm in self.get_all_permissions(user, obj)
+
+    def has_module_perms(self, user, app_label):
+        """Returns True if user has any permissions in the given app_label.
+
+        Currently this matches for the app_label ``"openstack"``.
+        """
+        if not user.is_active:
+            return False
+        for perm in self.get_all_permissions(user):
+            if perm[:perm.index('.')] == app_label:
+                return True
+        return False
diff --git a/modules/openstack/files/mitaka/horizon/puppet_group_add.py 
b/modules/openstack/files/mitaka/horizon/puppet_group_add.py
new file mode 100644
index 0000000..67f27b7
--- /dev/null
+++ b/modules/openstack/files/mitaka/horizon/puppet_group_add.py
@@ -0,0 +1,6 @@
+# The name of the panel group to be added to HORIZON_CONFIG. Required.
+PANEL_GROUP = 'puppet'
+# The display name of the PANEL_GROUP. Required.
+PANEL_GROUP_NAME = 'Puppet'
+# The name of the dashboard the PANEL_GROUP associated with. Required.
+PANEL_GROUP_DASHBOARD = 'project'
diff --git a/modules/openstack/files/mitaka/horizon/puppet_prefix_tab_enable.py 
b/modules/openstack/files/mitaka/horizon/puppet_prefix_tab_enable.py
new file mode 100644
index 0000000..4764131
--- /dev/null
+++ b/modules/openstack/files/mitaka/horizon/puppet_prefix_tab_enable.py
@@ -0,0 +1,5 @@
+PANEL = 'prefixpuppetpanel'
+PANEL_GROUP = 'puppet'
+PANEL_DASHBOARD = 'project'
+ADD_PANEL = ('wikimediapuppettab.prefixpanel.prefixpanel.PrefixPuppetPanel')
+AUTO_DISCOVER_STATIC_FILES = True
diff --git a/modules/openstack/files/mitaka/horizon/puppet_tab_enable.py 
b/modules/openstack/files/mitaka/horizon/puppet_tab_enable.py
new file mode 100644
index 0000000..a2d62ed
--- /dev/null
+++ b/modules/openstack/files/mitaka/horizon/puppet_tab_enable.py
@@ -0,0 +1,7 @@
+PANEL = 'projectpuppetpanel'
+PANEL_GROUP = 'puppet'
+PANEL_DASHBOARD = 'project'
+ADD_PANEL = ('wikimediapuppettab.projectpanel.ProjectPuppetPanel')
+ADD_INSTALLED_APPS = ['wikimediapuppettab']
+AUTO_DISCOVER_STATIC_FILES = True
+ADD_SCSS_FILES = ['dashboard/puppet/puppet.scss']

-- 
To view, visit https://gerrit.wikimedia.org/r/333983
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I99b29bc0195f243c13dfd313c23bb0140c820604
Gerrit-PatchSet: 1
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Andrew Bogott <abog...@wikimedia.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to