Add ssl support for keycloak auth middleware

This patch enables ssl support for keycloak middleware. It adds 3
new config options: 'certfile', 'keyfile' and 'cafile' and substitues
their values to the request to keycloak server.

Change-Id: Id8a771af373cd9d1e198142c21957622f9d0232c
Closes-bug: #1712749
This commit is contained in:
Mike Fedosin 2017-08-24 10:43:48 +03:00
parent 1a8837b9d2
commit 1c98030a30
2 changed files with 46 additions and 1 deletions

View File

@ -12,11 +12,14 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import jwt import jwt
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
import pprint import pprint
import requests import requests
from six.moves import urllib
from mistral._i18n import _ from mistral._i18n import _
from mistral import auth from mistral import auth
@ -31,6 +34,10 @@ CONF = cfg.CONF
class KeycloakAuthHandler(auth.AuthHandler): class KeycloakAuthHandler(auth.AuthHandler):
def authenticate(self, req): def authenticate(self, req):
certfile = CONF.keycloak_oidc.certfile
keyfile = CONF.keycloak_oidc.keyfile
cafile = CONF.keycloak_oidc.cafile or self.get_system_ca_file()
insecure = CONF.keycloak_oidc.insecure
if 'X-Auth-Token' not in req.headers: if 'X-Auth-Token' not in req.headers:
msg = _("Auth token must be provided in 'X-Auth-Token' header.") msg = _("Auth token must be provided in 'X-Auth-Token' header.")
@ -64,11 +71,18 @@ class KeycloakAuthHandler(auth.AuthHandler):
(CONF.keycloak_oidc.auth_url, realm_name) (CONF.keycloak_oidc.auth_url, realm_name)
) )
verify = None
if urllib.parse.urlparse(user_info_endpoint).scheme == "https":
verify = False if insecure else cafile
cert = (certfile, keyfile) if certfile and keyfile else None
try: try:
resp = requests.get( resp = requests.get(
user_info_endpoint, user_info_endpoint,
headers={"Authorization": "Bearer %s" % access_token}, headers={"Authorization": "Bearer %s" % access_token},
verify=not CONF.keycloak_oidc.insecure verify=verify,
cert=cert
) )
except requests.ConnectionError: except requests.ConnectionError:
msg = _("Can't connect to keycloak server with address '%s'." msg = _("Can't connect to keycloak server with address '%s'."
@ -86,3 +100,21 @@ class KeycloakAuthHandler(auth.AuthHandler):
req.headers["X-Identity-Status"] = "Confirmed" req.headers["X-Identity-Status"] = "Confirmed"
req.headers["X-Project-Id"] = realm_name req.headers["X-Project-Id"] = realm_name
req.headers["X-Roles"] = roles req.headers["X-Roles"] = roles
@staticmethod
def get_system_ca_file():
"""Return path to system default CA file."""
# Standard CA file locations for Debian/Ubuntu, RedHat/Fedora,
# Suse, FreeBSD/OpenBSD, MacOSX, and the bundled ca
ca_path = ['/etc/ssl/certs/ca-certificates.crt',
'/etc/pki/tls/certs/ca-bundle.crt',
'/etc/ssl/ca-bundle.pem',
'/etc/ssl/cert.pem',
'/System/Library/OpenSSL/certs/cacert.pem',
requests.certs.where()]
for ca in ca_path:
LOG.debug("Looking for ca file %s", ca)
if os.path.exists(ca):
LOG.debug("Using ca file %s", ca)
return ca
LOG.warning("System ca file could not be found.")

View File

@ -277,6 +277,19 @@ keycloak_oidc_opts = [
'auth_url', 'auth_url',
help=_('Keycloak base url (e.g. https://my.keycloak:8443/auth)') help=_('Keycloak base url (e.g. https://my.keycloak:8443/auth)')
), ),
cfg.StrOpt(
'certfile',
help=_('Required if identity server requires client certificate')
),
cfg.StrOpt(
'keyfile',
help=_('Required if identity server requires client certificate')
),
cfg.StrOpt(
'cafile',
help=_('A PEM encoded Certificate Authority to use when verifying '
'HTTPs connections. Defaults to system CAs.')
),
cfg.BoolOpt( cfg.BoolOpt(
'insecure', 'insecure',
default=False, default=False,