Basic Keystone Auth support
Note: This has been verified as working by the end customer
This commit is contained in:
parent
eb612d606c
commit
066637f496
6 changed files with 151 additions and 1 deletions
|
@ -0,0 +1,26 @@
|
|||
"""Add keystone login service
|
||||
|
||||
Revision ID: 2bf8af5bad95
|
||||
Revises: 154f2befdfbe
|
||||
Create Date: 2015-06-29 21:19:13.053165
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '2bf8af5bad95'
|
||||
down_revision = '154f2befdfbe'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade(tables):
|
||||
op.bulk_insert(tables.loginservice, [{'id': 6, 'name': 'keystone'}])
|
||||
|
||||
|
||||
def downgrade(tables):
|
||||
op.execute(
|
||||
tables.loginservice.delete()
|
||||
.where(tables.loginservice.c.name == op.inline_literal('keystone'))
|
||||
)
|
||||
|
|
@ -8,6 +8,9 @@ import jwt
|
|||
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timedelta
|
||||
from keystoneclient.v2_0 import client as kclient
|
||||
from keystoneclient.exceptions import AuthorizationFailure as KeystoneAuthorizationFailure
|
||||
from keystoneclient.exceptions import Unauthorized as KeystoneUnauthorized
|
||||
|
||||
import features
|
||||
|
||||
|
@ -53,6 +56,37 @@ def _get_federated_user(username, email, federated_service, create_new_user):
|
|||
return (db_user, None)
|
||||
|
||||
|
||||
class KeystoneUsers(object):
|
||||
""" Delegates authentication to OpenStack Keystone. """
|
||||
def __init__(self, auth_url, admin_username, admin_password, admin_tenant):
|
||||
self.auth_url = auth_url
|
||||
self.admin_username = admin_username
|
||||
self.admin_password = admin_password
|
||||
self.admin_tenant = admin_tenant
|
||||
|
||||
def verify_user(self, username_or_email, password, create_new_user=True):
|
||||
try:
|
||||
keystone_client = kclient.Client(username=username_or_email, password=password,
|
||||
auth_url=self.auth_url)
|
||||
user_id = keystone_client.user_id
|
||||
except KeystoneAuthorizationFailure as kaf:
|
||||
logger.exception('Keystone auth failure for user: %s', username_or_email)
|
||||
return (None, kaf.message or 'Invalid username or password')
|
||||
except KeystoneUnauthorized as kut:
|
||||
logger.exception('Keystone unauthorized for user: %s', username_or_email)
|
||||
return (None, kut.message or 'Invalid username or password')
|
||||
|
||||
try:
|
||||
admin_client = kclient.Client(username=self.admin_username, password=self.admin_password,
|
||||
tenant_name=self.admin_tenant, auth_url=self.auth_url)
|
||||
user = admin_client.users.get(user_id)
|
||||
except KeystoneUnauthorized as kut:
|
||||
logger.exception('Keystone unauthorized admin')
|
||||
return (None, 'Keystone admin credentials are invalid: %s' % kut.message)
|
||||
|
||||
return _get_federated_user(username_or_email, user.email, 'keystone', create_new_user)
|
||||
|
||||
|
||||
class ExternalJWTAuthN(object):
|
||||
""" Delegates authentication to a REST endpoint that returns JWTs. """
|
||||
PUBLIC_KEY_FILENAME = 'jwt-authn.cert'
|
||||
|
@ -336,6 +370,13 @@ class UserAuthentication(object):
|
|||
max_fresh_s = app.config.get('JWT_AUTH_MAX_FRESH_S', 300)
|
||||
users = ExternalJWTAuthN(verify_url, issuer, override_config_dir, max_fresh_s,
|
||||
app.config['HTTPCLIENT'])
|
||||
elif authentication_type == 'Keystone':
|
||||
auth_url = app.config.get('KEYSTONE_AUTH_URL')
|
||||
keystone_admin_username = app.config.get('KEYSTONE_ADMIN_USERNAME')
|
||||
keystone_admin_password = app.config.get('KEYSTONE_ADMIN_PASSWORD')
|
||||
keystone_admin_tenant = app.config.get('KEYSTONE_ADMIN_TENANT')
|
||||
users = KeystoneUsers(auth_url, keystone_admin_username, keystone_admin_password,
|
||||
keystone_admin_tenant)
|
||||
else:
|
||||
raise RuntimeError('Unknown authentication type: %s' % authentication_type)
|
||||
|
||||
|
|
Reference in a new issue