Andrew Bogott has uploaded a new change for review. https://gerrit.wikimedia.org/r/274167
Change subject: Support totp auth in keystone ...................................................................... Support totp auth in keystone Bug: T105690 Change-Id: I5e067bcd326a345616139e307336e44591734aad --- M hieradata/eqiad.yaml A modules/openstack/files/kilo/keystone/totp/wmtotp.py M modules/openstack/manifests/keystone/service.pp M modules/openstack/templates/kilo/keystone/keystone.conf.erb 4 files changed, 129 insertions(+), 0 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/operations/puppet refs/changes/67/274167/1 diff --git a/hieradata/eqiad.yaml b/hieradata/eqiad.yaml index 7e82fae..3c281f6 100644 --- a/hieradata/eqiad.yaml +++ b/hieradata/eqiad.yaml @@ -129,6 +129,8 @@ auth_host: 208.80.154.92 admin_project_id: 'admin' admin_project_name: 'admin' + oath_dbname: 'labswiki' + oath_dbhost: 'silver.wikimedia.org' designateconfig: db_host: 'm5-master.eqiad.wmnet' diff --git a/modules/openstack/files/kilo/keystone/totp/wmtotp.py b/modules/openstack/files/kilo/keystone/totp/wmtotp.py new file mode 100644 index 0000000..0d499ba --- /dev/null +++ b/modules/openstack/files/kilo/keystone/totp/wmtotp.py @@ -0,0 +1,109 @@ +# Copyright 2016 Wikimedia Foundation +# +# (this is a custom hack local to the Wikimedia Labs deployment) +# +# 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. + +from oslo_log import log +from oslo_config import cfg + +from keystone import auth +from keystone.auth import plugins as auth_plugins +from keystone.common import dependency +from keystone import exception +from keystone.i18n import _ + +import oath +import base64 +import mysql.connector + +METHOD_NAME = 'mwtotp' + +LOG = log.getLogger(__name__) +CONF = cfg.CONF + +oathoptions = [ + cfg.StrOpt('dbuser', + default='wiki_user', + help='Database user for retrieving OATH secret.'), + cfg.StrOpt('dbpass', + default='12345', + help='Database password for retrieving OATH secret.'), + cfg.StrOpt('dbhost', + default='localhost', + help='Database host for retrieving OATH secret.'), + cfg.StrOpt('dbname', + default='labswiki', + help='Database name for retrieving OATH secret.'), +] + +for option in oathoptins: + conf.register_opt(option, group='oath') + + [email protected]('identity_api') +class Mwtotp(auth.AuthMethodHandler): + + method = METHOD_NAME + + def authenticate(self, context, auth_payload, auth_context): + """Try to authenticate against the identity backend.""" + user_info = auth_plugins.UserAuthInfo.create(auth_payload, self.method) + + # FIXME(gyee): identity.authenticate() can use some refactoring since + # all we care is password matches + try: + self.identity_api.authenticate( + context, + user_id=user_info.user_id, + password=user_info.password) + except AssertionError: + # authentication failed because of invalid username or password + msg = _('Invalid username or password') + raise exception.Unauthorized(msg) + + + # Password auth succeeded, check two-factor + # LOG.debug("OATH: Doing 2FA for user_info " + ( "%s(%r)" % (user_info.__class__, user_info.__dict__) ) ) + # LOG.debug("OATH: Doing 2FA for auth_payload " + ( "%s(%r)" % (auth_payload.__class__, auth_payload) ) ) + cnx = mysql.connector.connect( + user=CONF.oath.dbuser, + password=CONF.oath.dbpass, + database=CONF.oath.dbname, + host=CONF.oath.dbhost) + cur = cnx.cursor(buffered=True) + sql = ('SELECT oath.secret as secret from user ' + 'left join oathauth_users as oath on oath.id = user.user_id ' + 'where user.user_name = %s LIMIT 1') + cur.execute(sql, (user_info.user_ref['name'], )) + secret = cur.fetchone()[0] + + if secret: + if 'mwtotp' in auth_payload['user']: + (p, d) = oath.accept_totp( + base64.b16encode(base64.b32decode(secret)), + auth_payload['user']['totp']) + if p: + LOG.debug("OATH: 2FA passed") + else: + LOG.debug("OATH: 2FA failed") + msg = _('Invalid two-factor token') + raise exception.Unauthorized(msg) + else: + LOG.debug("OATH: 2FA failed, missing totp param") + msg = _('Missing two-factor token') + raise exception.Unauthorized(msg) + else: + LOG.debug("OATH: user '%s' does not have 2FA enabled.", user_info.user_ref['name']) + + auth_context['user_id'] = user_info.user_id diff --git a/modules/openstack/manifests/keystone/service.pp b/modules/openstack/manifests/keystone/service.pp index 19d50c9..5132597 100644 --- a/modules/openstack/manifests/keystone/service.pp +++ b/modules/openstack/manifests/keystone/service.pp @@ -28,6 +28,12 @@ owner => 'root', group => 'root', require => Package['keystone']; + '/usr/lib/python2.7/dist-packages/keystone/auth/plugins/wmtotp.py' + source => "puppet:///modules/openstack/${openstack_version}/keystone/totp/wmtotp.py", + mode => '0644', + owner => 'root', + group => 'root', + require => Package['keystone']; } if $::fqdn == hiera('labs_nova_controller') { diff --git a/modules/openstack/templates/kilo/keystone/keystone.conf.erb b/modules/openstack/templates/kilo/keystone/keystone.conf.erb index 3e16967..1dc09fe 100644 --- a/modules/openstack/templates/kilo/keystone/keystone.conf.erb +++ b/modules/openstack/templates/kilo/keystone/keystone.conf.erb @@ -204,3 +204,15 @@ use = egg:Paste#urlmap /v2.0 = admin_api / = admin_version_api + +[auth] +methods = external,password,token,wmtotp + +wmtotp=password = keystone.auth.plugins.wmtotp.Wmtotp + +[oath] + +dbuser = <%= @keystoneconfig["oath_dbuser"] %> +dbpass = <%= @keystoneconfig["oath_dbpass"] %> +dbname = <%= @keystoneconfig["oath_dbname"] %> +dbhost = <%= @keystoneconfig["oath_dbhost"] %> -- To view, visit https://gerrit.wikimedia.org/r/274167 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I5e067bcd326a345616139e307336e44591734aad Gerrit-PatchSet: 1 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: Andrew Bogott <[email protected]> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
