From a10e05f001a4b2b95c7cc6d9284cbb44bdbb9677 Mon Sep 17 00:00:00 2001 From: Eyal Date: Sun, 9 Jul 2017 17:03:01 +0300 Subject: [PATCH] supprt keycloak first stage Change-Id: Id5dff583834ce10b47ff77653f59947dea4bb7fe --- setup.cfg | 1 + vitrageclient/auth.py | 69 ++++++++++++++++++++++++++++++++++++++++++ vitrageclient/shell.py | 3 +- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 9c77866..eedfad6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,6 +34,7 @@ console_scripts = keystoneauth1.plugin = vitrage-noauth = vitrageclient.auth:VitrageNoAuthLoader + vitrage-keycloak = vitrageclient.auth:VitrageKeycloakLoader openstack.cli.extension = rca = vitrageclient.osc diff --git a/vitrageclient/auth.py b/vitrageclient/auth.py index c8dced3..09d09a8 100644 --- a/vitrageclient/auth.py +++ b/vitrageclient/auth.py @@ -12,9 +12,14 @@ # under the License. import os +import requests from keystoneauth1 import loading from keystoneauth1 import plugin +from oslo_log import log + + +LOG = log.getLogger(__name__) class VitrageNoAuthPlugin(plugin.BaseAuthPlugin): @@ -75,3 +80,67 @@ class VitrageNoAuthLoader(loading.BaseLoader): VitrageOpt('endpoint', help='Vitrage endpoint', required=True), ]) return options + + +class VitrageKeycloakPlugin(plugin.BaseAuthPlugin): + """Authentication plugin for Keycloak """ + + def __init__(self, username, password, realm_name, roles, endpoint, + auth_url, openid_client_id): + self.username = username + self.password = password + self.realm_name = realm_name + self.roles = roles + self.endpoint = endpoint + self.auth_url = auth_url + self.client_id = openid_client_id + + def get_headers(self, session, **kwargs): + return {'X-Auth-Token': self._authenticate_keycloak(), + 'x-user-id': self.username, + 'x-project-id': self.realm_name, + 'x-roles': self.roles} + + def get_endpoint(self, session, **kwargs): + return self.endpoint + + def _authenticate_keycloak(self): + keycloak_endpoint = "%s/realms/%s/protocol/openid-connect/token" % \ + (self.auth_url, self.realm_name) + + body = { + 'grant_type': 'password', + 'username': self.username, + 'password': self.password, + 'client_id': self.client_id, + 'scope': 'profile' + } + + resp = requests.post(keycloak_endpoint, + data=body, + verify=True) + + try: + resp.raise_for_status() + except Exception as e: + LOG.error('Failed to get access token: %s', str(e)) + + return resp.json()['access_token'] + + +class VitrageKeycloakLoader(loading.BaseLoader): + plugin_class = VitrageKeycloakPlugin + + def get_options(self): + options = super(VitrageKeycloakLoader, self).get_options() + options.extend([ + VitrageOpt('username', help='User Name', required=True), + VitrageOpt('password', help='password', required=True), + VitrageOpt('realm-name', help='Realm Name', required=True), + VitrageOpt('roles', help='Roles', default="admin"), + VitrageOpt('endpoint', help='Vitrage Endpoint', required=True), + VitrageOpt('auth-url', help='Keycloak Url', required=True), + VitrageOpt('openid-client-id', help='Keycloak client id', + required=True), + ]) + return options diff --git a/vitrageclient/shell.py b/vitrageclient/shell.py index 2f06bf1..7d16797 100644 --- a/vitrageclient/shell.py +++ b/vitrageclient/shell.py @@ -114,7 +114,8 @@ class VitrageShell(app.App): plugin = self.register_keyauth_argparse_arguments(parser) - if not isinstance(plugin, auth.VitrageNoAuthLoader): + if not isinstance(plugin, (auth.VitrageNoAuthLoader, + auth.VitrageKeycloakLoader)): parser.add_argument('--endpoint', default=os.environ.get('VITRAGE_ENDPOINT'), help='Vitrage endpoint (Env: VITRAGE_ENDPOINT)'