diff -pruN 2.4.1-2/AUTHORS 3.5.0-0ubuntu1/AUTHORS
--- 2.4.1-2/AUTHORS	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/AUTHORS	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,86 @@
+Adam Young <ayoung@redhat.com>
+Akihiro MOTOKI <motoki@da.jp.nec.com>
+Akihiro Motoki <amotoki@gmail.com>
+Akihiro Motoki <motoki@da.jp.nec.com>
+Andreas Jaeger <aj@suse.de>
+Bo Wang <bo.wang@easystack.cn>
+Brad Pokorny <Brad_Pokorny@symantec.com>
+Brant Knudson <bknudson@us.ibm.com>
+Brian DeHamer <brian.dehamer@hp.com>
+Colleen Murphy <colleen.murphy@suse.com>
+Colleen Murphy <colleen@gazlene.net>
+Cyril Roelandt <cyril.roelandt@enovance.com>
+Daniel Park <daniepar@cisco.com>
+David Lyle <david.lyle@hp.com>
+David Lyle <david.lyle@intel.com>
+David Lyle <dklyle0@gmail.com>
+Dirk Mueller <dirk@dmllr.de>
+Doug Fish <drfish@us.ibm.com>
+Doug Hellmann <doug@doughellmann.com>
+Einar Forselv <einar@zetta.io>
+Elvin Tubillara <edtubill@us.ibm.com>
+Eric Peterson <ericpeterson@hp.com>
+Flavio Percoco <flaper87@gmail.com>
+Gabriel Hurley <gabriel@strikeawe.com>
+Helber Maciel Guerra <helbermg@gmail.com>
+Itxaka <iserrano@redhat.com>
+James E. Blair <jeblair@openstack.org>
+James Muranga <jmured@gmail.com>
+Jamie Lennox <jamielennox@redhat.com>
+Jeremy Stanley <fungi@yuggoth.org>
+Johannes Grassler <j.grassler@syseleven.de>
+Jose Castro Leon <jose.castro.leon@cern.ch>
+Julie Pichon <jpichon@redhat.com>
+Kenji Ishii <ken-ishii@sx.jp.nec.com>
+Kieran Spear <kispear@gmail.com>
+Kirill Zaitsev <k.zaitsev@mirantis.com>
+Lin Hua Cheng <lin-hua.cheng@hp.com>
+Matthias Runge <mrunge@redhat.com>
+Maxime Vidori <maxime.vidori@enovance.com>
+Mike Hagedorn <mike.hagedorn@hp.com>
+Mohammed Naser <mnaser@vexxhost.com>
+Monty Taylor <mordred@inaugust.com>
+Ondřej Nový <ondrej.novy@firma.seznam.cz>
+Paul Karikh <pkarikh@mirantis.com>
+Paulo Ewerton Gomes Fragoso <pauloewerton@lsd.ufcg.edu.br>
+Praveen Yalagandula <ypraveen@gmail.com>
+Radomir Dopieralski <openstack@sheep.art.pl>
+Richard Jones <r1chardj0n3s@gmail.com>
+Rob Cresswell <robert.cresswell@outlook.com>
+Rob Raymond <rob.raymond@hp.com>
+Robert Mizielski <robert.mizielski@cloudwatt.com>
+Sam Stoelinga <sammiestoel@gmail.com>
+Sascha Peilicke <saschpe@gmx.de>
+Sascha Peilicke <speilicke@suse.com>
+Thai Tran <tqtran@us.ibm.com>
+Thomas Bechtold <tbechtold@suse.com>
+Thomas Goirand <thomas@goirand.fr>
+Thomas Goirand <zigo@debian.org>
+Timur Sufiev <tsufiev@mirantis.com>
+Tony Breeds <tony@bakeyournoodle.com>
+Tony Xu <hhktony@gmail.com>
+Veronica Musso <veronica.a.musso@intel.com>
+Victor Stinner <vstinner@redhat.com>
+Vincent Untz <vuntz@suse.com>
+Vlad Okhrimenko <vokhrimenko@mirantis.com>
+Xiao Hanyu <xiaohanyu1988@gmail.com>
+Yves-Gwenael Bourhis <yves-gwenael.bourhis@cloudwatt.com>
+andrewbogott <abogott@wikimedia.org>
+daisy-ycguo <guoyingc@cn.ibm.com>
+daniel-a-nguyen <dan.nguyens.mail@gmail.com>
+eric <ejpetey@gmail.com>
+eric <eric.peterson1@twcable.com>
+jichenjc <jichenjc@cn.ibm.com>
+jlopezgu <juan.pablo.lopez.gutierrez@intel.com>
+kavithahr <kavitha.r@nectechnologies.in>
+lin-hua-cheng <lin-hua.cheng@hp.com>
+lin-hua-cheng <os.lcheng@gmail.com>
+linhuacheng <lin-hua.cheng@hp.com>
+liuqing <jing.liuqing@99cloud.net>
+liyingjun <liyingjun1988@gmail.com>
+mathrock <nathanael.i.burton.work@gmail.com>
+tinytmy <tangmeiyan77@gmail.com>
+venkatamahesh <venkatamaheshkotha@gmail.com>
+woodnt <woodm1979@gmail.com>
+xhzhf <guoyongxhzhf@163.com>
+Łukasz Oleś <loles@mirantis.com>
diff -pruN 2.4.1-2/ChangeLog 3.5.0-0ubuntu1/ChangeLog
--- 2.4.1-2/ChangeLog	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/ChangeLog	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,547 @@
+CHANGES
+=======
+
+3.5.0
+-----
+
+* Manually bump Django requirement
+
+3.4.0
+-----
+
+* Fix Django 1.11 Compatibility
+* Imported Translations from Zanata
+* Fix default mutable arg in k2k.py
+* Allow for manual setting of default service region in config
+* hacking: Drop import\_exceptions from tox.ini
+
+3.3.0
+-----
+
+* Bump Django requirements cap
+* Migrate settings on a feature merged recently
+* Add Django 1.11 tox env
+* Add support for a domain dropdown menu at login
+* doc: Add configuration reference
+* doc: cleanup doc build configuration
+* Imported Translations from Zanata
+* Updated from global requirements
+* switch from oslosphinx to openstackdocstheme
+* move documentation into the new standard layout
+* Imported Translations from Zanata
+* Updated from global requirements
+* Fix doc build
+
+3.2.0
+-----
+
+* Imported Translations from Zanata
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Updated from global requirements
+* Cleanup doc warnings and enforce warning-is-error in sphinx
+* Imported Translations from Zanata
+* Updated from global requirements
+* The python 3.5 added
+* Updated from global requirements
+* Update hacking version to fix tests
+* Implement expiration date alert message
+* Updated from global requirements
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+
+3.1.1
+-----
+
+* Store the project domain ID in the Token object
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Add info logs to plugin scoping
+* Imported Translations from Zanata
+* Updated from global requirements
+* Allow federated users to auth with domain scope
+* Fix exception catch-all in domain scope auth
+
+3.1.0
+-----
+
+* Add K2K Auth Dropdown
+* Updated from global requirements
+* Refactor project and domain scoping
+* Get remote address from client, behind proxy servers, to log on console
+* Add Constraints support
+* Updated from global requirements
+* python3.0 has disable LOG.warn
+* Updated from global requirements
+* Show team and repo badges on README
+* Fix policy check short circuit
+* Updated from global requirements
+
+3.0.0
+-----
+
+* Removing token revoke / delete calls
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* Modify use of assertTrue(A in B)
+* Imported Translations from Zanata
+* Add is\_authenticated and is\_anonymous properties
+* Imported Translations from Zanata
+* Correctly initialize TestResponses
+* Fix wrong warning about keystone version
+* Imported Translations from Zanata
+* Updated from global requirements
+* Add reason attribute to TestResponse
+
+2.4.0
+-----
+
+* Fix django 1.10 tox env
+* Updated from global requirements
+* Updated from global requirements
+* Fix Django 1.10 tox env
+* [Django 1.10] Define TEMPLATES
+* Add 'is\_admin\_project' attribute in token
+* Not authorized when logout and creating instance
+* Updated from global requirements
+* Adding tenant\_id to policy default
+* Add Django 1.10 tox env
+* Updated from global requirements
+* Updated from global requirements
+* Make fix\_auth\_url\_version() delegate emitting the warning up the stack
+* Updated from global requirements
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Updated from global requirements
+* Updated from global requirements
+
+2.3.0
+-----
+
+* Clarify the confusing warning in case of Keystone v2.0 vs v3 conflict
+* Fix Keystone url version suffix when webpath is present
+* Use login endpoint as key for AVAILABLE\_REGIONS
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* When calculating session\_time, use the actual token life
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Fix token hashing with python 3
+* Don't call the Keystone client if the token is None
+
+2.2.0
+-----
+
+* Updated from global requirements
+* Update URLs to Django 1.8+ style
+* Add app\_label
+* Change log.error to log.warning
+* Fix "Add API version to identity endpoint URLs"
+* Add convenient method to get admin roles and permissions
+* Update translation setup
+* Drop supporting python3.3
+* Remove openstack-common.conf
+* Updated from global requirements
+* Updated from global requirements
+* Fix the py27dj19 tests
+* Add py27dj19 tox env
+* Updated from global requirements
+* Fix WebSSO when Keystone server hostname contains 'auth'
+* Update url\_for parameter for domain policy check
+* Unscoped PKI token should no longer be hashed multiple times
+* Python 3 deprecated the logger.warn method in favor of warning
+* Use consistent region during login
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+
+2.1.1
+-----
+
+* Fixing backward compatibility
+* Add API version to identity endpoint URLs
+* Deprecated tox -downloadcache option removed
+* Add domain initial value on login
+* Move d-o-a auth library to keystoneauth
+
+2.1.0
+-----
+
+* Imported Translations from Zanata
+* Makes policy.check aware of domain scoped token
+* Updated from global requirements
+* Add domain scoped token to session in multidomain
+* Revert - Cache the User's Project by Token ID
+* Use set comprehension instead of converting lists to sets
+* Updated from global requirements
+* Imported Translations from Zanata
+* Updated from global requirements
+* Imported Translations from Zanata
+* doa does not work with mysql
+* Imported Translations from Zanata
+* Fix the path of build docs in .gitignore
+* Imported Translations from Zanata
+* Imported Translations from Zanata
+* Updated from global requirements
+
+2.0.0
+-----
+
+* Imported Translations from Zanata
+* Remove .tx/config
+* Replace default User model PK
+* IDP specific websso
+* Updated from global requirements
+* Fix missing region field on WebSSO setup
+* Fix Python 3 issues
+* Imported Translations from Transifex
+* Updated from global requirements
+* Removing hack for python 2.6 support
+
+1.4.0
+-----
+
+* initialize the hasher for unscoped token
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Extend User from AbstractBaseUser and AnonymousUser
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Configurable token hashing
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Update supported keystone versions
+* Fix doc reference in README
+* Add message show for switch project
+* Use unscoped token for scoping to project
+* Fixing docstring formatting for param
+* Fix Login form's fields sorting for Django 1.7
+* Updated from global requirements
+* Imported Translations from Transifex
+* Fixes modules index generated by Sphinx
+* Imported Translations from Transifex
+* Add Coverage Reports To DOA
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Support removal of last\_activity session flag
+* Use graduated version of oslo.policy
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Add missing \_ import to plugin/base.py
+* Imported Translations from Transifex
+
+1.3.1
+-----
+
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Improve messaging on keystone connection issue
+* Updated from global requirements
+* Set default value for new token attributes
+* Imported Translations from Transifex
+* Adding 1.6 job for tox
+* Updated from global requirements
+* Updated from global requirements
+* Drop use of 'oslo' namespace package
+* Prepend WEBROOT to redirect URL for WebSSO
+* Imported Translations from Transifex
+
+1.3.0
+-----
+
+* Update README to work with release tools
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Uncap library requirements for liberty
+
+1.2.0
+-----
+
+* Updating Django requirements to allow 1.7
+* Fix test error for Django1.7
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Removing python 2.6 support
+* Imported Translations from Transifex
+* Updated parsing of catalog to handle bad format
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Add websso redirect test
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Hash token only for ASN1 and PKIZ tokens
+* Imported Translations from Transifex
+* Add authentication using openID and SAML
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Add token auth plugin
+* Make list\_projects a method of auth plugin
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Rename AUTH\_PLUGINS option
+* Follow ups to Authentication Plugins
+* Expose keystone client version as a plugin property
+* Create plugin model for DOA authentication
+* Updated from global requirements
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+* Fix H405 docstring issue
+* Updated from global requirements
+* Allow running individual tests via tox
+* Move to hacking 0.10
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Updated from global requirements
+* Imported Translations from Transifex
+
+1.1.9
+-----
+
+* Imported Translations from Transifex
+* Add defaulting of services\_region in User class
+* Relocating policy engine from openstack\_dashboard
+* Use keystone auth plugins
+* Imported Translations from Transifex
+* Imported Translations from Transifex
+* Allow an empty region list
+* Attempt to scope only to enabled projects
+* Add call to KS V3 revoke\_token on logout
+* add last\_activity to session
+* Workflow documentation is now in infra-manual
+* Use standard test loading features
+
+1.1.8
+-----
+
+* Horizon login page contains DOS attack mechanism
+* Domain enabled login screen needs focus on Domain field
+* Make region sticky on Login page
+* Imported Translations from Transifex
+* Make region and project sticky
+* Updated the installation instructions
+* Remove admin role name 'admin' hardcode in User.is\_superuser()
+* Imported Translations from Transifex
+* Fix inability to switch region via Switch Region dropdown
+* Updated from global requirements
+* Bump hacking to 0.9.x series
+* Remove compiled message catalogs
+* extract mock setup methods
+
+1.1.7
+-----
+
+* Updated from global requirements
+* Updated from global requirements
+* Set DJANGO\_SETTINGS\_MODULE envvar in doc/source/conf.py
+* Adding django kwargs to login and logout views
+* Fix Django 1.7 compat
+* Work toward Python 3.4 support and testing
+* Consider old version of token without 'user\_domain\_name' attr
+* Added url\_path\_replace and has\_in\_url\_path methods
+* Configurable token hashing algorithm
+* Add user\_domain\_name in the user object
+* Updated from global requirements
+* Updated from global requirements
+* Updated from global requirements
+* Adding log message for keystone API mismatch
+* Cache the User's Project by Token ID
+* Fix H4xx docstring issues
+* Replace UserManager/TenantManager with None in tests
+* Imported Translations from Transifex
+* Add CONTRIBUTING.rst
+* Imported Translations from Transifex
+* Updated from global requirements
+* Adding back the forms.Login import
+
+1.1.6
+-----
+
+* Hash the token id if it is over a maximum length
+* Restore "redirect to login page after logout" behaviour
+* Minor update to the readme file
+* Add license header to exceptions.py
+* Fix H301 and H304 hacking issues
+* Updated from global requirements
+* Set default auth\_url from django settings when auth\_url is None
+* Disable H803 check
+* Add the Python 3 classifiers
+* Do not use Exception.message
+* Redirect the user if they're already logged in
+* Fix translation setup
+* Updated from global requirements
+* Use the latest Django 1.4 release to test
+* Adding check for service roles to match users region selection
+* Updated from global requirements
+* Fix whitespace issues found by Pep8 1.5.4+
+* Fix typo of ANS1 to ASN1
+* Updated from global requirements
+* Add tox env to build docs
+* Fix H306 imports not in alphabetical order
+* Fix remaining PEP8 (E\*\*\*) and PyFlakes (F\*\*\*) issues
+* Make Hacking E1XX compliant
+
+1.1.5
+-----
+
+* Updated from global requirements
+* Import translations
+* Reverting default keystone API to v2.0
+* Adding Django 1.6 support
+* Updated from global requirements
+* TestResponse: use a default status code
+* Use mox3 rather than mox
+* Use six.moves.urllib.parse instead of urlparse
+* Updated from global requirements
+* Sort project list by name
+* Switch over to oslosphinx
+* moves default keystone API to v3
+
+1.1.4
+-----
+
+* updating version specification
+* Have tox install via setup.py develop
+* Updated from global requirements
+* Support Django 1.4, 1.5 and 1.6
+* Require user to be logged in when switching regions
+* Fixed urls import
+* Fix django.conf.urls.defaults imports
+* Refresh request.user on session updates
+* Pass OPENSTACK\_SSL\_CACERT setting to keystone
+* Giving focus on username field on log in page
+
+1.1.3
+-----
+
+* Bump version for 1.1.3
+* Import translations from Transifex for Havana RC1
+* Add I18N related configurations
+* Revoking token when switching tenant or loging out
+* Add Apache2 licence header in data\_v3.py
+* Make auth backend use OPENSTACK\_ENDPOINT\_TYPE parameter from settings
+* Missing check, supporting changes in horizon for middleware changes
+* Update message translation files
+* Align with OpenStack project standards
+
+1.1.2
+-----
+
+* Bump version for H3 release
+* Try to scope token for all available projects
+
+1.1.1
+-----
+
+* Bumping version for release
+* Fix issue with V3 Authentication
+* Add tox.ini file and flake8 ignores
+* Add OpenStack .gitreview file
+* Dump version for release w/ v3 auth
+* Add capability for Keystone V3 Authentication
+* Fix testsuite after "Support keystoneclient 0.2.5+"
+* Support keystoneclient 0.2.5+
+
+1.0.11
+------
+
+* Adding missing files from docs to sdist tarball
+
+1.0.10
+------
+
+* Bumping version for PyPI release
+* Adding basic multi-region support
+* Add username on the log for logout and rescope
+* fix typo
+* Add logging on logout and token rescoping
+* Add logging for success/failed login
+* Bump version for release to PyPI
+* setting of SECRET\_KEY is required for Django-1.5
+* Bump version for new release to PyPI
+* Fix unit tests after adding insecure flag
+* Allow insecure authentication Pass through the value of OPENSTACK\_SSL\_NO\_VERIFY from settings.py to keystoneclient. This allows connecting to servers with self-signed or otherwise invalid certificates for testing purposes. It extends commit 8759ad4804271d0f86eed514a8007157f44d4ba4
+* Updated User object for Django 1.5 compatibility
+* Fix compatibility with Django < 1.4.3
+* Allowing for more complex combinations of permissions.  Will check for logical AND of all top level permissions.  Will use logical OR for all first level tuples (check that use has one permissions in the tuple)
+* Bump version for new release
+* Support custom redirect url from the 'switch' view
+* Turn log level down for failure on delete token
+* Fixing tests that broke in transition to python-keystoneclient v0.2
+* Update openstack\_auth/views.py
+* missed obvious bug when moving to new thread
+* Fixed l10n bugs and added zh\_CN translation
+* Added german translation
+* horizon bug 1079832 Logout does not revoke the tokens created, correcting to keep tuple of endpoints and clients
+* Allow insecure authentication
+
+1.0.6
+-----
+
+* Fixes compatibility with keystoneclient v0.2
+
+1.0.5
+-----
+
+* Improves error handling; fixes failing test
+* Slimming down the session size
+
+1.0.3
+-----
+
+* Use the MD5 hash of PKI-signed tokens
+
+1.0.2
+-----
+
+* Bumping version number for bugfix release with redirect fix
+* Fix redirection in logging form
+* Bumping version number for permission support release
+* Adds permissions support
+* Catch AuthorizationFailure
+* Adding manifest file
+* Fixed typo in readme
+* Added docs to readme
+* Adding a few translation files
+* Adds docs
+* Check for expired tokens during authentication
+* Added note about unit tests
+* Fixed README typo
+* Initial commit
diff -pruN 2.4.1-2/debian/changelog 3.5.0-0ubuntu1/debian/changelog
--- 2.4.1-2/debian/changelog	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/changelog	2017-07-31 13:06:42.000000000 +0000
@@ -1,3 +1,51 @@
+python-django-openstack-auth (3.5.0-0ubuntu1) artful; urgency=medium
+
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- Corey Bryant <corey.bryant@canonical.com>  Mon, 31 Jul 2017 09:06:42 -0400
+
+python-django-openstack-auth (3.2.0-0ubuntu1) artful; urgency=medium
+
+  * New upstream release.
+  * d/control: Align (Build-)Depends with upstream.
+
+ -- James Page <james.page@ubuntu.com>  Fri, 02 Jun 2017 09:20:59 +0100
+
+python-django-openstack-auth (3.1.1-0ubuntu1) zesty; urgency=medium
+
+  * New upstream release.
+
+ -- Chuck Short <zulcss@ubuntu.com>  Thu, 09 Feb 2017 14:38:19 -0500
+
+python-django-openstack-auth (3.1.0-0ubuntu1) zesty; urgency=medium
+
+  * New upstream release.
+  * debian/control: Bump versioned dependencies.
+
+ -- Chuck Short <zulcss@ubuntu.com>  Fri, 20 Jan 2017 10:28:38 -0500
+
+python-django-openstack-auth (3.0.0-1ubuntu1) zesty; urgency=medium
+
+  [ Corey Bryant ]
+  * d/gbp.conf: Update gbp configuration file.
+  * d/control: Update Vcs-* links and maintainers.
+
+  [ Chuck Short ]
+  * debian/watch: Update URL.
+  * New upstream release. 
+  * debian/control: Bump versioned dependencies.
+  * debian/patches/Add-is_authenticated-and-is_anonymous-properties.patch: Dropped 
+    no longer needed.
+
+ -- Chuck Short <zulcss@ubuntu.com>  Wed, 09 Nov 2016 10:31:23 -0500
+
+python-django-openstack-auth (2.4.1-2ubuntu1) yakkety; urgency=medium
+
+  * Fix python3-keystoneauth1 dependency back to python-keystoneauth1.
+
+ -- Iain Lane <iain@orangesquash.org.uk>  Mon, 10 Oct 2016 09:56:05 +0100
+
 python-django-openstack-auth (2.4.1-2) unstable; urgency=medium
 
   * Uploading to unstable.
diff -pruN 2.4.1-2/debian/control 3.5.0-0ubuntu1/debian/control
--- 2.4.1-2/debian/control	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/control	2017-07-31 13:06:42.000000000 +0000
@@ -1,7 +1,8 @@
 Source: python-django-openstack-auth
 Section: python
 Priority: optional
-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
+Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
+XSBC-Original-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org>
 Uploaders: Thomas Goirand <zigo@debian.org>,
            Ivan Udovichenko <iudovichenko@mirantis.com>,
            Corey Bryant <corey.bryant@canonical.com>,
@@ -9,51 +10,52 @@ Build-Depends: debhelper (>= 9),
                dh-python,
                openstack-pkg-tools (>= 52~),
                python-all,
-               python-pbr (>= 1.8),
+               python-pbr (>= 2.0.0),
                python-setuptools,
-               python-sphinx,
+               python-sphinx (>= 1.5.1),
                python3-all,
-               python3-pbr (>= 1.8),
+               python3-pbr (>= 2.0.0),
                python3-setuptools,
 Build-Depends-Indep: python-babel (>= 2.3.4),
-                     python-coverage,
+                     python-coverage (>= 4.0),
                      python-django (>= 1.8),
                      python-hacking (>= 0.10.0),
-                     python-keystoneauth1 (>= 2.10.0),
-                     python-keystoneclient (>= 1:1.7.0),
-                     python-mock (>= 1.3),
-                     python-mox3,
-                     python-oslo.config (>= 1:3.14.0),
-                     python-oslo.policy (>= 1.9.0),
-                     python-oslosphinx (>= 2.5.0),
+                     python-keystoneauth1 (>= 2.21.0),
+                     python-keystoneclient (>= 1:3.8.0),
+                     python-mock (>= 2.0),
+                     python-mox3 (>= 0.7.0),
+                     python-openstackdocstheme (>= 1.11.0),
+                     python-oslo.config (>= 1:4.0.0),
+                     python-oslo.policy (>= 1.23.0),
                      python-six (>= 1.9.0),
-                     python-testscenarios,
+                     python-testscenarios (>= 0.4),
                      python3-babel (>= 2.3.4),
                      python3-django (>= 1.8),
-                     python3-keystoneauth1 (>= 2.10.0),
-                     python3-keystoneclient (>= 1:1.7.0),
-                     python3-mock (>= 1.3),
-                     python3-mox3,
-                     python3-oslo.config (>= 1:3.14.0),
-                     python3-oslo.policy (>= 1.9.0),
+                     python3-keystoneauth1 (>= 2.21.0),
+                     python3-keystoneclient (>= 1:3.8.0),
+                     python3-mock (>= 2.0),
+                     python3-mox3 (>= 0.7.0),
+                     python3-openstackdocstheme (>= 1.11.0),
+                     python3-oslo.config (>= 1:4.0.0),
+                     python3-oslo.policy (>= 1.23.0),
                      python3-six (>= 1.9.0),
-                     python3-testscenarios,
+                     python3-testscenarios (>= 0.4)
 Standards-Version: 3.9.8
-Vcs-Git: https://git.openstack.org/openstack/deb-python-django-openstack-auth -b debian/newton
-Vcs-Browser: https://git.openstack.org/cgit/openstack/deb-python-django-openstack-auth?h=debian%2Fnewton
+Vcs-Git: git://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-django-openstack-auth
+Vcs-Browser: https://git.launchpad.net/~ubuntu-server-dev/ubuntu/+source/python-django-openstack-auth
 Homepage: https://pypi.python.org/pypi/django_openstack_auth
 
 Package: python-django-openstack-auth
 Architecture: all
 Depends: python-django (>= 1.8),
-         python-keystoneclient (>= 1:1.7.0),
-         python-oslo.config (>= 1:3.14.0),
-         python-oslo.policy (>= 1.9.0),
-         python-pbr (>= 1.8),
+         python-keystoneauth1 (>= 2.21.0),
+         python-keystoneclient (>= 1:3.8.0),
+         python-oslo.config (>= 1:4.0.0),
+         python-oslo.policy (>= 1.23.0),
+         python-pbr (>= 2.0.0),
          python-six (>= 1.9.0),
-         python3-keystoneauth1 (>= 2.10.0),
          ${misc:Depends},
-         ${python:Depends},
+         ${python:Depends}
 Breaks: python-openstack-auth (<= 2.0.0-2),
 Replaces: python-openstack-auth (<= 2.0.0-2),
 Provides: python-openstack-auth,
@@ -69,8 +71,7 @@ Package: python-openstack-auth
 Section: oldlibs
 Priority: extra
 Architecture: all
-Depends: python-django-openstack-auth,
-         ${misc:Depends},
+Depends: python-django-openstack-auth, ${misc:Depends}
 Description: Django authentication backend for Openstack - transition package
  Django authentication backend for use with the OpenStack Keystone Identity
  backend. This Python module is used by Horizon (the Openstack Dashport web
@@ -82,14 +83,14 @@ Description: Django authentication backe
 Package: python3-django-openstack-auth
 Architecture: all
 Depends: python3-django (>= 1.8),
-         python3-keystoneauth1 (>= 2.10.0),
-         python3-keystoneclient (>= 1:1.7.0),
-         python3-oslo.config (>= 1:3.14.0),
-         python3-oslo.policy (>= 1.9.0),
-         python3-pbr (>= 1.8),
+         python3-keystoneauth1 (>= 2.21.0),
+         python3-keystoneclient (>= 1:3.8.0),
+         python3-oslo.config (>= 1:4.0.0),
+         python3-oslo.policy (>= 1.23.0),
+         python3-pbr (>= 2.0.0),
          python3-six (>= 1.9.0),
          ${misc:Depends},
-         ${python3:Depends},
+         ${python3:Depends}
 Provides: ${python3:Provides},
 Description: Django authentication backend for Openstack - Python 3.x
  Django authentication backend for use with the OpenStack Keystone Identity
diff -pruN 2.4.1-2/debian/gbp.conf 3.5.0-0ubuntu1/debian/gbp.conf
--- 2.4.1-2/debian/gbp.conf	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/gbp.conf	2017-07-31 13:06:42.000000000 +0000
@@ -1,8 +1,7 @@
 [DEFAULT]
-upstream-branch = master
-debian-branch = debian/newton
+debian-branch = master
 upstream-tag = %(version)s
-compression = xz
+pristine-tar = True
 
 [buildpackage]
-export-dir = ../build-area/
+export-dir = ../build-area
diff -pruN 2.4.1-2/debian/patches/Add-is_authenticated-and-is_anonymous-properties.patch 3.5.0-0ubuntu1/debian/patches/Add-is_authenticated-and-is_anonymous-properties.patch
--- 2.4.1-2/debian/patches/Add-is_authenticated-and-is_anonymous-properties.patch	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/patches/Add-is_authenticated-and-is_anonymous-properties.patch	1970-01-01 00:00:00.000000000 +0000
@@ -1,117 +0,0 @@
-Description: Add is_authenticated and is_anonymous properties
- See
- https://docs.djangoproject.com/en/1.10/releases/1.10/#using-user-is-authenticated-and-user-is-anonymous-as-methods
- .
- is_anonymous() and is_authenticated() functions are now properties, and
- throw critical security warnings when using python manage.py check in
- django 1.10
- .
- The duplication is just to make it explicit which code paths are being
- followed. They could be refactored to remove it, but in a few months
- when we move to the next LTS we would just end up removing the refactors
- since there would once again be a single path.
- .
- We also removed the `margin` parameter, since it is never used anywhere.
- This will be documented in a Horizon release note.
-Author: Rob Cresswell <robert.cresswell@outlook.com>
-Date: Wed, 10 Aug 2016 09:10:20 +0100
-Change-Id: I7a92089ae62a9017274002648f26f13bc34709d9
-Origin: upstream, https://review.openstack.org/374732
-Last-Update: 2016-09-27
-
-diff --git a/openstack_auth/user.py b/openstack_auth/user.py
-index c9200f4..fba75e7 100644
---- a/openstack_auth/user.py
-+++ b/openstack_auth/user.py
-@@ -14,9 +14,11 @@
- import hashlib
- import logging
- 
-+import django
- from django.conf import settings
- from django.contrib.auth import models
- from django.db import models as db_models
-+from django.utils import deprecation
- from keystoneauth1 import exceptions as keystone_exceptions
- from keystoneclient.common import cms as keystone_cms
- import six
-@@ -261,35 +263,50 @@ def is_token_expired(self, margin=None):
-             return None
-         return not utils.is_token_valid(self.token, margin)
- 
--    def is_authenticated(self, margin=None):
--        """Checks for a valid authentication.
--
--        :param margin:
--           A security time margin in seconds before end of authentication.
--           Will return ``False`` if authentication ends in less than ``margin``
--           seconds of time.
--           A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
--           django settings.
--
--        """
--        return (self.token is not None and
--                utils.is_token_valid(self.token, margin))
--
--    def is_anonymous(self, margin=None):
--        """Return if the user is not authenticated.
--
--        Returns ``True`` if not authenticated,``False`` otherwise.
--
--        :param margin:
--           A security time margin in seconds before end of an eventual
--           authentication.
--           Will return ``True`` even if authenticated but that authentication
--           ends in less than ``margin`` seconds of time.
--           A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
--           django settings.
--
--        """
--        return not self.is_authenticated(margin)
-+    if django.VERSION >= (1, 10):
-+        @property
-+        def is_authenticated(self):
-+            """Checks for a valid authentication."""
-+            if (self.token is not None and utils.is_token_valid(self.token)):
-+                return deprecation.CallableTrue
-+            else:
-+                return deprecation.CallableFalse
-+
-+        @property
-+        def is_anonymous(self):
-+            """Return if the user is not authenticated.
-+
-+            Returns ``True`` if not authenticated,``False`` otherwise.
-+            """
-+            return deprecation.CallableBool(not self.is_authenticated)
-+    else:
-+        def is_authenticated(self, margin=None):
-+            """Checks for a valid authentication.
-+
-+            :param margin:
-+               A security time margin in seconds before end of authentication.
-+               Will return ``False`` if authentication ends in less than
-+               ``margin`` seconds of time.
-+               A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
-+               django settings.
-+            """
-+            return (self.token is not None and
-+                    utils.is_token_valid(self.token, margin))
-+
-+        def is_anonymous(self, margin=None):
-+            """Return if the user is not authenticated.
-+
-+            Returns ``True`` if not authenticated,``False`` otherwise.
-+
-+            :param margin:
-+               A security time margin in seconds before end of an eventual
-+               authentication.
-+               Will return ``True`` even if authenticated but that
-+               authentication ends in less than ``margin`` seconds of time.
-+               A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
-+               django settings.
-+            """
-+            return not self.is_authenticated(margin)
- 
-     @property
-     def is_active(self):
diff -pruN 2.4.1-2/debian/patches/series 3.5.0-0ubuntu1/debian/patches/series
--- 2.4.1-2/debian/patches/series	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-Add-is_authenticated-and-is_anonymous-properties.patch
diff -pruN 2.4.1-2/debian/watch 3.5.0-0ubuntu1/debian/watch
--- 2.4.1-2/debian/watch	2016-10-04 08:50:47.000000000 +0000
+++ 3.5.0-0ubuntu1/debian/watch	2017-07-31 13:06:42.000000000 +0000
@@ -1,2 +1,3 @@
 version=3
-https://github.com/gabrielhurley/django_openstack_auth/tags .*/(\d[\d\.]+)\.tar\.gz
+pts=uversionmangle=s/(rc|a|b|c)/~$1/
+http://tarballs.openstack.org/django_openstack_auth/ django_openstack_auth-(\d.*)\.tar\.gz
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/dependency_links.txt 3.5.0-0ubuntu1/django_openstack_auth.egg-info/dependency_links.txt
--- 2.4.1-2/django_openstack_auth.egg-info/dependency_links.txt	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/dependency_links.txt	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/not-zip-safe 3.5.0-0ubuntu1/django_openstack_auth.egg-info/not-zip-safe
--- 2.4.1-2/django_openstack_auth.egg-info/not-zip-safe	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/not-zip-safe	2017-07-20 16:40:49.000000000 +0000
@@ -0,0 +1 @@
+
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/pbr.json 3.5.0-0ubuntu1/django_openstack_auth.egg-info/pbr.json
--- 2.4.1-2/django_openstack_auth.egg-info/pbr.json	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/pbr.json	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1 @@
+{"git_version": "2ca726c", "is_release": true}
\ No newline at end of file
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/PKG-INFO 3.5.0-0ubuntu1/django_openstack_auth.egg-info/PKG-INFO
--- 2.4.1-2/django_openstack_auth.egg-info/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/PKG-INFO	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,54 @@
+Metadata-Version: 1.1
+Name: django-openstack-auth
+Version: 3.5.0
+Summary: Django authentication backend for use with OpenStack Identity
+Home-page: http://www.openstack.org/
+Author: OpenStack
+Author-email: openstack-dev@lists.openstack.org
+License: UNKNOWN
+Description: ========================
+        Team and repository tags
+        ========================
+        
+        .. image:: http://governance.openstack.org/badges/django_openstack_auth.svg
+            :target: http://governance.openstack.org/reference/tags/index.html
+        
+        .. Change things from this point on
+        
+        =====================
+        Django OpenStack Auth
+        =====================
+        
+        Django OpenStack Auth is a pluggable Django authentication backend that
+        works with Django's ``contrib.auth`` framework to authenticate a user against
+        OpenStack's Keystone Identity API.
+        
+        The current version is designed to work with the Keystone v2.0 and v3 API.
+        
+        You can `view the installation instructions`_ on Read The Docs.
+        
+        .. _view the installation instructions: http://docs.openstack.org/developer/django_openstack_auth/
+        
+        * License: Apache License, Version 2.0
+        * Documentation: http://django-openstack-auth.readthedocs.org/en/latest/
+        * Source: http://git.openstack.org/cgit/openstack/django_openstack_auth/
+        * Bugs: https://bugs.launchpad.net/django-openstack-auth
+        
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: OpenStack
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Topic :: Internet :: WWW/HTTP
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/requires.txt 3.5.0-0ubuntu1/django_openstack_auth.egg-info/requires.txt
--- 2.4.1-2/django_openstack_auth.egg-info/requires.txt	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/requires.txt	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,7 @@
+pbr!=2.1.0,>=2.0.0
+Django<2.0,>=1.8
+oslo.config!=4.3.0,!=4.4.0,>=4.0.0
+oslo.policy>=1.23.0
+python-keystoneclient>=3.8.0
+keystoneauth1>=2.21.0
+six>=1.9.0
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/SOURCES.txt 3.5.0-0ubuntu1/django_openstack_auth.egg-info/SOURCES.txt
--- 2.4.1-2/django_openstack_auth.egg-info/SOURCES.txt	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/SOURCES.txt	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,79 @@
+.mailmap
+AUTHORS
+CONTRIBUTING.rst
+ChangeLog
+LICENSE
+MANIFEST.in
+README.rst
+babel-django.cfg
+requirements.txt
+setup.cfg
+setup.py
+test-requirements.txt
+tox.ini
+django_openstack_auth.egg-info/PKG-INFO
+django_openstack_auth.egg-info/SOURCES.txt
+django_openstack_auth.egg-info/dependency_links.txt
+django_openstack_auth.egg-info/not-zip-safe
+django_openstack_auth.egg-info/pbr.json
+django_openstack_auth.egg-info/requires.txt
+django_openstack_auth.egg-info/top_level.txt
+doc/source/conf.py
+doc/source/index.rst
+doc/source/configuration/index.rst
+doc/source/install/index.rst
+doc/source/reference/backend.rst
+doc/source/reference/forms.rst
+doc/source/reference/index.rst
+doc/source/reference/user.rst
+doc/source/reference/utils.rst
+doc/source/reference/views.rst
+openstack_auth/__init__.py
+openstack_auth/backend.py
+openstack_auth/exceptions.py
+openstack_auth/forms.py
+openstack_auth/models.py
+openstack_auth/policy.py
+openstack_auth/urls.py
+openstack_auth/user.py
+openstack_auth/utils.py
+openstack_auth/views.py
+openstack_auth/locale/cs/LC_MESSAGES/django.po
+openstack_auth/locale/de/LC_MESSAGES/django.po
+openstack_auth/locale/en_AU/LC_MESSAGES/django.po
+openstack_auth/locale/en_GB/LC_MESSAGES/django.po
+openstack_auth/locale/es/LC_MESSAGES/django.po
+openstack_auth/locale/es_MX/LC_MESSAGES/django.po
+openstack_auth/locale/fr/LC_MESSAGES/django.po
+openstack_auth/locale/id/LC_MESSAGES/django.po
+openstack_auth/locale/it/LC_MESSAGES/django.po
+openstack_auth/locale/ja/LC_MESSAGES/django.po
+openstack_auth/locale/ko_KR/LC_MESSAGES/django.po
+openstack_auth/locale/nl_NL/LC_MESSAGES/django.po
+openstack_auth/locale/pa_IN/LC_MESSAGES/django.po
+openstack_auth/locale/pl_PL/LC_MESSAGES/django.po
+openstack_auth/locale/pt_BR/LC_MESSAGES/django.po
+openstack_auth/locale/ru/LC_MESSAGES/django.po
+openstack_auth/locale/tr_TR/LC_MESSAGES/django.po
+openstack_auth/locale/uk/LC_MESSAGES/django.po
+openstack_auth/locale/zh_CN/LC_MESSAGES/django.po
+openstack_auth/locale/zh_TW/LC_MESSAGES/django.po
+openstack_auth/plugin/__init__.py
+openstack_auth/plugin/base.py
+openstack_auth/plugin/k2k.py
+openstack_auth/plugin/password.py
+openstack_auth/plugin/token.py
+openstack_auth/tests/__init__.py
+openstack_auth/tests/data_v2.py
+openstack_auth/tests/data_v3.py
+openstack_auth/tests/models.py
+openstack_auth/tests/run_tests.py
+openstack_auth/tests/settings.py
+openstack_auth/tests/tests.py
+openstack_auth/tests/urls.py
+openstack_auth/tests/conf/keystone_policy.json
+openstack_auth/tests/conf/nova_policy.json
+openstack_auth/tests/conf/policy.v3cloudsample.json
+openstack_auth/tests/templates/auth/blank.html
+openstack_auth/tests/templates/auth/login.html
+tools/tox_install.sh
\ No newline at end of file
diff -pruN 2.4.1-2/django_openstack_auth.egg-info/top_level.txt 3.5.0-0ubuntu1/django_openstack_auth.egg-info/top_level.txt
--- 2.4.1-2/django_openstack_auth.egg-info/top_level.txt	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/django_openstack_auth.egg-info/top_level.txt	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1 @@
+openstack_auth
diff -pruN 2.4.1-2/doc/source/configuration/index.rst 3.5.0-0ubuntu1/doc/source/configuration/index.rst
--- 2.4.1-2/doc/source/configuration/index.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/configuration/index.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,425 @@
+=============
+Configuration
+=============
+
+Django OpenStack Auth is configured through Django ``settings.py`` file.
+In most cases it is used combined with the OpenStack Dashboard,
+so the settings file will be ``local/local_settings.py`` file
+in your OpenStack Dashboard deployment.
+
+This page covers the configuration options referred by Django OpenStack Auth.
+
+:ref:`Some settings <settings-shared-with-horizon>` are also referred to
+by Horizon. Configure them carefully.
+
+General settings
+================
+
+``AUTHENTICATION_PLUGINS``
+--------------------------
+
+Default: ``['openstack_auth.plugin.password.PasswordPlugin', 'openstack_auth.plugin.token.TokenPlugin']``
+
+A list of authentication plugins to be used.
+In most cases, there is no need to configure this.
+
+``AVAILABLE_REGIONS``
+---------------------
+
+Default: ``None``
+
+A list of tuples which define multiple regions. The tuple format is
+``('http://{{ keystone_host }}:5000/v2.0', '{{ region_name }}')``. If any regions
+are specified the login form will have a dropdown selector for authenticating
+to the appropriate region, and there will be a region switcher dropdown in
+the site header when logged in.
+
+You should also define ``OPENSTACK_KEYSTONE_URL`` to indicate which of
+the regions is the default one.
+
+
+``DEFAULT_SERVICE_REGIONS``
+---------------------------
+
+Default: ``{}``
+
+The default service region is set on a per-endpoint basis, meaning that once
+the user logs into some Keystone endpoint, if a default service region is
+defined for it in this setting and exists within Keystone catalog, it will be
+set as the initial service region in this endpoint. By default it is an empty
+dictionary because upstream can neither predict service region names in a
+specific deployment, nor tell whether this behavior is desired. The key of the
+dictionary is a full url of a Keystone endpoint with version suffix, the value
+is a region name.
+
+Example::
+
+    DEFAULT_SERVICE_REGIONS = {
+        OPENSTACK_KEYSTONE_URL: 'RegionOne'
+    }
+
+
+``OPENSTACK_API_VERSIONS``
+--------------------------
+
+Default::
+
+    {
+        "identity": 2.0,
+        ...,
+    }
+
+Overrides for OpenStack API versions. Use this setting to force the
+OpenStack dashboard to use a specific API version for a given service API.
+Django OpenStack Auth refers to only the ``"identity"`` entry.
+The current valid values are "2.0" or "3".
+
+.. note::
+
+   See `Horizon settings
+   <https://docs.openstack.org/developer/horizon/install/settings.html#openstack-api-versions>`__
+   for the full description of this setting.
+
+``OPENSTACK_ENDPOINT_TYPE``
+---------------------------
+
+Default: ``"publicURL"``
+
+A string which specifies the endpoint type to use for the endpoints in the
+Keystone service catalog. The default value for all services except for
+identity is ``"publicURL"``. The default value for the identity service is
+``"internalURL"``.
+
+``OPENSTACK_KEYSTONE_ADMIN_ROLES``
+----------------------------------
+
+Default: ``["admin"]``
+
+The list of roles that have administrator privileges in this OpenStack
+installation. This check is very basic and essentially only works with
+keystone v2.0 and v3 with the default policy file. The setting assumes there
+is a common ``admin`` like role(s) across services. Example uses of this
+setting are:
+
+* to rename the ``admin`` role to ``cloud-admin``
+* allowing multiple roles to have administrative privileges, like
+  ``["admin", "cloud-admin", "net-op"]``
+
+``OPENSTACK_KEYSTONE_DEFAULT_DOMAIN``
+-------------------------------------
+
+Default: ``"Default"``
+
+Overrides the default domain used when running on single-domain model
+with Keystone V3. All entities will be created in the default domain.
+
+.. note::
+
+   This value must be the name of the default domain, NOT the ID.
+   Also, you will most likely have a value in the keystone policy file like
+   ``"cloud_admin": "rule:admin_required and domain_id:<your domain id>"``.
+   This value must be the name of the domain whose ID is specified there.
+
+``OPENSTACK_KEYSTONE_DOMAIN_CHOICES``
+-------------------------------------
+
+.. versionadded:: 12.0.0(Pike)
+
+Default::
+
+        (
+          ('Default', 'Default'),
+        )
+
+If OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN is enabled, this option can be used to
+set the available domains to choose from. This is a list of pairs whose first
+value is the domain name and the second is the display name.
+
+``OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN``
+--------------------------------------
+
+.. versionadded:: 12.0.0(Pike)
+
+Default: ``False``
+Set this to True if you want available domains displayed as a dropdown menu on
+the login screen. It is strongly advised NOT to enable this for public clouds,
+as advertising enabled domains to unauthenticated customers irresponsibly
+exposes private information. This should only be used for private clouds where
+the dashboard sits behind a corporate firewall.
+
+``OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT``
+------------------------------------------
+
+Default: ``False``
+
+Set this to True if running on multi-domain model. When this is enabled, it
+will require user to enter the Domain name in addition to username for login.
+
+``OPENSTACK_KEYSTONE_URL``
+--------------------------
+
+Default: ``"http://%s:5000/v2.0" % OPENSTACK_HOST``
+
+The full URL for the Keystone endpoint used for authentication. Unless you
+are using HTTPS, running your Keystone server on a nonstandard port, or using
+a nonstandard URL scheme you shouldn't need to touch this setting.
+
+``OPENSTACK_SSL_CACERT``
+------------------------
+
+Default: ``None``
+
+When unset or set to ``None`` the default CA certificate on the system is used
+for SSL verification.
+
+When set with the path to a custom CA certificate file, this overrides use of
+the default system CA certificate. This custom certificate is used to verify all
+connections to openstack services when making API calls.
+
+``OPENSTACK_SSL_NO_VERIFY``
+---------------------------
+
+Default: ``False``
+
+Disable SSL certificate checks in the OpenStack clients (useful for self-signed
+certificates).
+
+``OPENSTACK_TOKEN_HASH_ALGORITHM``
+----------------------------------
+
+Default: ``"md5"``
+
+The hash algorithm to use for authentication tokens. This must match the hash
+algorithm that the identity (Keystone) server and the auth_token middleware
+are using. Allowed values are the algorithms supported by Python's hashlib
+library.
+
+``OPENSTACK_TOKEN_HASH_ENABLED``
+--------------------------------
+
+(Deprecated)
+
+Default: ``True``
+
+Hashing tokens from Keystone keeps the Horizon session data smaller, but it
+doesn't work in some cases when using PKI tokens.  Uncomment this value and
+set it to False if using PKI tokens and there are 401 errors due to token
+hashing.
+
+This option is now marked as "deprecated" and will be removed in Ocata or a
+later release. PKI tokens currently work with hashing, and Keystone will soon
+deprecate usage of PKI tokens.
+
+``PASSWORD_EXPIRES_WARNING_THRESHOLD_DAYS``
+-------------------------------------------
+
+Default: ``-1``
+
+Password will have an expiration date when using keystone v3 and enabling the
+feature. This setting allows you to set the number of days that the user will
+be alerted prior to the password expiration. Once the password expires keystone
+will deny the access and users must contact an admin to change their password.
+Setting this value to ``N`` days means the user will be alerted when the
+password expires in less than ``N+1`` days. ``-1`` disables the feature.
+
+``POLICY_FILES``
+----------------
+
+Default: ``{'identity': 'keystone_policy.json', 'compute': 'nova_policy.json'}``
+
+This should essentially be the mapping of the contents of ``POLICY_FILES_PATH``
+to service types.  When policy.json files are added to ``POLICY_FILES_PATH``,
+they should be included here too.
+
+``POLICY_FILES_PATH``
+---------------------
+
+Default:  ``os.path.join(ROOT_PATH, "conf")``
+
+Specifies where service based policy files are located. These are used to
+define the policy rules actions are verified against.
+
+``SECURE_PROXY_ADDR_HEADER``
+----------------------------
+
+Default: ``False``
+
+If horizon is behind a proxy server and the proxy is configured, the IP address
+from request is passed using header variables inside the request. The header
+name depends on a proxy or a load-balancer. This setting specifies the name of
+the header with remote IP address. The main use is for authentication log
+(success or fail) displaing the IP address of the user.
+The commom value for this setting is ``HTTP_X_REAL_IP`` or
+``HTTP_X_FORWARDED_FOR``.
+If not present, then ``REMOTE_ADDR`` header is used. (``REMOTE_ADDR`` is the
+field of Django HttpRequest object which contains IP address of the client.)
+
+``SESSION_TIMEOUT``
+-------------------
+
+Default: ``"3600"``
+
+This ``SESSION_TIMEOUT`` is a method to supercede the token timeout with a
+shorter horizon session timeout (in seconds).  So if your token expires in
+60 minutes, a value of 1800 will log users out after 30 minutes.
+
+``TOKEN_DELETION_DISABLED``
+---------------------------
+
+Default: ``False``
+
+This setting allows deployers to control whether a token is deleted on log out.
+This can be helpful when there are often long running processes being run
+in the Horizon environment.
+
+``TOKEN_TIMEOUT_MARGIN``
+------------------------
+
+Default: ``0``
+
+A time margin in seconds to subtract from the real token's validity.
+An example usage is that the token can be valid once the middleware
+passed, and invalid (timed-out) during a view rendering and this
+generates authorization errors during the view rendering.
+By setting this value to some smaller seconds, you can avoid token
+expiration during a view rendering.
+
+``WEBROOT``
+-----------
+
+Default: ``"/"``
+
+Specifies the location where the access to the dashboard is configured in
+the web server.
+
+For example, if you're accessing the Dashboard via
+https://<your server>/dashboard, you would set this to ``"/dashboard/"``.
+
+.. note::
+
+    Additional settings may be required in the config files of your webserver
+    of choice. For example to make ``"/dashboard/"`` the web root in Apache,
+    the ``"sites-available/horizon.conf"`` requires a couple of additional
+    aliases set::
+
+        Alias /dashboard/static %HORIZON_DIR%/static
+
+        Alias /dashboard/media %HORIZON_DIR%/openstack_dashboard/static
+
+    Apache also requires changing your WSGIScriptAlias to reflect the desired
+    path.  For example, you'd replace ``/`` with ``/dashboard`` for the
+    alias.
+
+Web SSO (Single Sign On) settings
+=================================
+
+``WEBSSO_ENABLED``
+------------------
+
+Default: ``False``
+
+Enables keystone web single-sign-on if set to True. For this feature to work,
+make sure that you are using Keystone V3 and Django OpenStack Auth V1.2.0 or
+later.
+
+``WEBSSO_INITIAL_CHOICE``
+-------------------------
+
+Default: ``"credentials"``
+
+Determines the default authentication mechanism. When user lands on the login
+page, this is the first choice they will see.
+
+``WEBSSO_CHOICES``
+------------------
+
+Default::
+
+        (
+          ("credentials", _("Keystone Credentials")),
+          ("oidc", _("OpenID Connect")),
+          ("saml2", _("Security Assertion Markup Language"))
+        )
+
+This is the list of authentication mechanisms available to the user. It
+includes Keystone federation protocols such as OpenID Connect and SAML, and
+also keys that map to specific identity provider and federation protocol
+combinations (as defined in ``WEBSSO_IDP_MAPPING``). The list of choices is
+completely configurable, so as long as the id remains intact. Do not remove
+the credentials mechanism unless you are sure. Once removed, even admins will
+have no way to log into the system via the dashboard.
+
+``WEBSSO_IDP_MAPPING``
+----------------------
+
+Default: ``{}``
+
+A dictionary of specific identity provider and federation protocol combinations.
+From the selected authentication mechanism, the value will be looked up as keys
+in the dictionary. If a match is found, it will redirect the user to a identity
+provider and federation protocol specific WebSSO endpoint in keystone, otherwise
+it will use the value as the protocol_id when redirecting to the WebSSO by
+protocol endpoint.
+
+Example::
+
+        WEBSSO_CHOICES =  (
+            ("credentials", _("Keystone Credentials")),
+            ("oidc", _("OpenID Connect")),
+            ("saml2", _("Security Assertion Markup Language")),
+            ("acme_oidc", "ACME - OpenID Connect"),
+            ("acme_saml2", "ACME - SAML2")
+        )
+
+        WEBSSO_IDP_MAPPING = {
+            "acme_oidc": ("acme", "oidc"),
+            "acme_saml2": ("acme", "saml2")
+        }
+
+.. note::
+  The value is expected to be a tuple formatted as: (<idp_id>, <protocol_id>).
+
+K2K (Keystone to Keystone) Federation settings
+==============================================
+
+``KEYSTONE_PROVIDER_IDP_NAME``
+------------------------------
+
+Default: ``Local Keystone``
+
+The Keystone Provider drop down uses Keystone to Keystone federation
+to switch between Keystone service providers.
+This sets display name for Identity Provider (dropdown display name).
+
+``KEYSTONE_PROVIDER_IDP_ID``
+----------------------------
+
+Default:: ``localkeystone``
+
+This ID is used for only for comparison with the service provider IDs.
+This ID should not match any service provider IDs.
+
+.. _settings-shared-with-horizon:
+
+Settings shared with Horizon
+============================
+
+The following settings in Django OpenStack Auth are also used by Horizon.
+
+* ``AVAILABLE_REGIONS``
+* ``OPENSTACK_API_VERSIONS``
+* ``OPENSTACK_KEYSTONE_URL``
+* ``OPENSTACK_ENDPOINT_TYPE``
+* ``OPENSTACK_SSL_CACERT``
+* ``OPENSTACK_SSL_NO_VERIFY``
+* ``WEBROOT``
+
+Django OpenStack Auth also refers to the following Django settings.
+For more detail, see `Django settings documentation
+<https://docs.djangoproject.com/en/1.11/ref/settings/#auth>`__.
+They are usually configured as part of Horizon settings.
+
+* ``LOGIN_REDIRECT_URL``
+* ``LOGIN_URL``
+* ``SESSION_ENGINE``
+* ``USE_TZ``
diff -pruN 2.4.1-2/doc/source/conf.py 3.5.0-0ubuntu1/doc/source/conf.py
--- 2.4.1-2/doc/source/conf.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/conf.py	2017-07-20 16:39:18.000000000 +0000
@@ -13,8 +13,12 @@
 
 import os
 
+import django
+
 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'openstack_auth.tests.settings')
 
+django.setup()
+
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -27,7 +31,13 @@ os.environ.setdefault('DJANGO_SETTINGS_M
 
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'oslosphinx']
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'openstackdocstheme']
+
+# openstackdocstheme options
+repository_name = 'openstack/django_openstack_auth'
+bug_project = 'django-openstack-auth'
+bug_tag = ''
+html_last_updated_fmt = '%Y-%m-%d %H:%M'
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -84,7 +94,7 @@ modindex_common_prefix = ['openstack_aut
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+html_theme = 'openstackdocs'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -113,7 +123,7 @@ html_theme = 'default'
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+#html_static_path = []
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
@@ -158,78 +168,3 @@ html_static_path = ['_static']
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'DjangoOpenStackAuthdoc'
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-    # The paper size ('letterpaper' or 'a4paper').
-    #'papersize': 'letterpaper',
-
-    # The font size ('10pt', '11pt' or '12pt').
-    #'pointsize': '10pt',
-
-    # Additional stuff for the LaTeX preamble.
-    #'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-  ('index', 'DjangoOpenStackAuth.tex', u'Django OpenStack Auth Documentation',
-   u'Gabriel Hurley', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# If true, show page references after internal links.
-#latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-#latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    ('index', 'djangoopenstackauth', u'Django OpenStack Auth Documentation',
-     [u'Gabriel Hurley'], 1)
-]
-
-# If true, show URL addresses after external links.
-#man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-  ('index', 'DjangoOpenStackAuth', u'Django OpenStack Auth Documentation',
-   u'Gabriel Hurley', 'DjangoOpenStackAuth', 'One line description of project.',
-   'Miscellaneous'),
-]
-
-# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
-
-# If false, no module index is generated.
-#texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
diff -pruN 2.4.1-2/doc/source/index.rst 3.5.0-0ubuntu1/doc/source/index.rst
--- 2.4.1-2/doc/source/index.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/index.rst	2017-07-20 16:39:18.000000000 +0000
@@ -11,15 +11,9 @@ The current version is designed to work
 .. toctree::
    :maxdepth: 2
 
-   installation
-   ref/user
-   ref/views
-   ref/forms
-   ref/backend
-   ref/utils
-
-Indices and tables
-==================
+   install/index
+   configuration/index
+   reference/index
 
 * :ref:`genindex`
 * :ref:`modindex`
diff -pruN 2.4.1-2/doc/source/install/index.rst 3.5.0-0ubuntu1/doc/source/install/index.rst
--- 2.4.1-2/doc/source/install/index.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/install/index.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,63 @@
+===============
+Getting Started
+===============
+
+Installation
+============
+
+Installing is quick and easy:
+
+#. Run ``pip install django_openstack_auth``.
+
+#. Add ``openstack_auth`` to ``settings.INSTALLED_APPS``.
+
+#. Add ``'openstack_auth.backend.KeystoneBackend'`` to your
+   ``settings.AUTHENTICATION_BACKENDS``, e.g.::
+
+        AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',)
+
+#. Configure your API endpoint(s) in ``settings.py``::
+
+        OPENSTACK_KEYSTONE_URL = "http://example.com:5000/v3"
+
+#. Include ``'openstack_auth.urls'`` somewhere in your ``urls.py`` file.
+
+#. Use it as you would any other Django auth backend.
+
+Running Tests
+=============
+
+Before running tests, you should have ``tox`` installed and available in your
+environment:
+
+.. code-block:: bash
+
+    $ pip install tox
+
+.. NOTE::
+
+    You may need to perform both the above operation and the next inside a
+    python virtualenv, or prefix the above command with ``sudo``, depending on
+    your preference.
+
+To execute the full suite of tests maintained within the project, simply run:
+
+.. code-block:: bash
+
+    $ tox
+
+.. NOTE::
+
+    The first time you run ``tox``, it will take additional time to build
+    virtualenvs. You can later use the ``-r`` option with ``tox`` to rebuild
+    your virtualenv in a similar manner.
+
+To run tests for one or more specific test environments (for example, the most
+common configuration of Python 2.7 and PEP-8), list the environments with the
+``-e`` option, separated by spaces:
+
+.. code-block:: bash
+
+    $ tox -e py27,pep8
+
+See ``tox.ini`` for the full list of available test environments.
diff -pruN 2.4.1-2/doc/source/installation.rst 3.5.0-0ubuntu1/doc/source/installation.rst
--- 2.4.1-2/doc/source/installation.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/installation.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,63 +0,0 @@
-===============
-Getting Started
-===============
-
-Installation
-============
-
-Installing is quick and easy:
-
-#. Run ``pip install django_openstack_auth``.
-
-#. Add ``openstack_auth`` to ``settings.INSTALLED_APPS``.
-
-#. Add ``'openstack_auth.backend.KeystoneBackend'`` to your
-   ``settings.AUTHENTICATION_BACKENDS``, e.g.::
-
-        AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',)
-
-#. Configure your API endpoint(s) in ``settings.py``::
-
-        OPENSTACK_KEYSTONE_URL = "http://example.com:5000/v3"
-
-#. Include ``'openstack_auth.urls'`` somewhere in your ``urls.py`` file.
-
-#. Use it as you would any other Django auth backend.
-
-Running Tests
-=============
-
-Before running tests, you should have ``tox`` installed and available in your
-environment:
-
-.. code-block:: bash
-
-    $ pip install tox
-
-.. NOTE::
-
-    You may need to perform both the above operation and the next inside a
-    python virtualenv, or prefix the above command with ``sudo``, depending on
-    your preference.
-
-To execute the full suite of tests maintained within the project, simply run:
-
-.. code-block:: bash
-
-    $ tox
-
-.. NOTE::
-
-    The first time you run ``tox``, it will take additional time to build
-    virtualenvs. You can later use the ``-r`` option with ``tox`` to rebuild
-    your virtualenv in a similar manner.
-
-To run tests for one or more specific test environments (for example, the most
-common configuration of Python 2.7 and PEP-8), list the environments with the
-``-e`` option, separated by spaces:
-
-.. code-block:: bash
-
-    $ tox -e py27,pep8
-
-See ``tox.ini`` for the full list of available test environments.
diff -pruN 2.4.1-2/doc/source/ref/backend.rst 3.5.0-0ubuntu1/doc/source/ref/backend.rst
--- 2.4.1-2/doc/source/ref/backend.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/ref/backend.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-==================
-The Backend Module
-==================
-
-.. automodule:: openstack_auth.backend
-   :members:
diff -pruN 2.4.1-2/doc/source/ref/forms.rst 3.5.0-0ubuntu1/doc/source/ref/forms.rst
--- 2.4.1-2/doc/source/ref/forms.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/ref/forms.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-================
-The Forms Module
-================
-
-.. automodule:: openstack_auth.forms
-   :members:
diff -pruN 2.4.1-2/doc/source/ref/user.rst 3.5.0-0ubuntu1/doc/source/ref/user.rst
--- 2.4.1-2/doc/source/ref/user.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/ref/user.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-==================
-The ``User`` Class
-==================
-
-.. automodule:: openstack_auth.user
-   :members:
diff -pruN 2.4.1-2/doc/source/ref/utils.rst 3.5.0-0ubuntu1/doc/source/ref/utils.rst
--- 2.4.1-2/doc/source/ref/utils.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/ref/utils.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-================
-The Utils Module
-================
-
-.. automodule:: openstack_auth.utils
-   :members:
diff -pruN 2.4.1-2/doc/source/ref/views.rst 3.5.0-0ubuntu1/doc/source/ref/views.rst
--- 2.4.1-2/doc/source/ref/views.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/ref/views.rst	1970-01-01 00:00:00.000000000 +0000
@@ -1,6 +0,0 @@
-================
-The Views Module
-================
-
-.. automodule:: openstack_auth.views
-   :members:
diff -pruN 2.4.1-2/doc/source/reference/backend.rst 3.5.0-0ubuntu1/doc/source/reference/backend.rst
--- 2.4.1-2/doc/source/reference/backend.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/backend.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,6 @@
+==================
+The Backend Module
+==================
+
+.. automodule:: openstack_auth.backend
+   :members:
diff -pruN 2.4.1-2/doc/source/reference/forms.rst 3.5.0-0ubuntu1/doc/source/reference/forms.rst
--- 2.4.1-2/doc/source/reference/forms.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/forms.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,6 @@
+================
+The Forms Module
+================
+
+.. automodule:: openstack_auth.forms
+   :members:
diff -pruN 2.4.1-2/doc/source/reference/index.rst 3.5.0-0ubuntu1/doc/source/reference/index.rst
--- 2.4.1-2/doc/source/reference/index.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/index.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,13 @@
+=====================================
+ Django OpenStack Auth API Reference
+=====================================
+
+.. toctree::
+   :maxdepth: 2
+
+   user
+   views
+   forms
+   backend
+   utils
+
diff -pruN 2.4.1-2/doc/source/reference/user.rst 3.5.0-0ubuntu1/doc/source/reference/user.rst
--- 2.4.1-2/doc/source/reference/user.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/user.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,6 @@
+==============
+The User Class
+==============
+
+.. automodule:: openstack_auth.user
+   :members:
diff -pruN 2.4.1-2/doc/source/reference/utils.rst 3.5.0-0ubuntu1/doc/source/reference/utils.rst
--- 2.4.1-2/doc/source/reference/utils.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/utils.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,6 @@
+================
+The Utils Module
+================
+
+.. automodule:: openstack_auth.utils
+   :members:
diff -pruN 2.4.1-2/doc/source/reference/views.rst 3.5.0-0ubuntu1/doc/source/reference/views.rst
--- 2.4.1-2/doc/source/reference/views.rst	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/doc/source/reference/views.rst	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,6 @@
+================
+The Views Module
+================
+
+.. automodule:: openstack_auth.views
+   :members:
diff -pruN 2.4.1-2/.gitignore 3.5.0-0ubuntu1/.gitignore
--- 2.4.1-2/.gitignore	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/.gitignore	1970-01-01 00:00:00.000000000 +0000
@@ -1,14 +0,0 @@
-*.pyc
-*.egg
-*.egg-info
-*.mo
-.DS_STORE
-doc/build
-build
-dist
-.tox
-AUTHORS
-ChangeLog
-.coverage
-reports
-coverage.xml
diff -pruN 2.4.1-2/.gitreview 3.5.0-0ubuntu1/.gitreview
--- 2.4.1-2/.gitreview	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/.gitreview	1970-01-01 00:00:00.000000000 +0000
@@ -1,5 +0,0 @@
-[gerrit]
-host=review.openstack.org
-port=29418
-project=openstack/django_openstack_auth.git
-defaultbranch=stable/newton
diff -pruN 2.4.1-2/openstack_auth/backend.py 3.5.0-0ubuntu1/openstack_auth/backend.py
--- 2.4.1-2/openstack_auth/backend.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/backend.py	2017-07-20 16:39:18.000000000 +0000
@@ -18,9 +18,8 @@ import logging
 import pytz
 
 from django.conf import settings
-from django.utils.module_loading import import_string  # noqa
+from django.utils.module_loading import import_string
 from django.utils.translation import ugettext_lazy as _
-from keystoneauth1 import exceptions as keystone_exceptions
 
 from openstack_auth import exceptions
 from openstack_auth import user as auth_user
@@ -69,8 +68,11 @@ class KeystoneBackend(object):
         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.
+        .. 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"]):
@@ -110,51 +112,23 @@ class KeystoneBackend(object):
                         '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.ConnectFailure 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)
+        # 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')
+        unscoped_auth_ref = plugin.get_access_info(unscoped_auth)
 
         # Check expiry for our unscoped auth ref.
         self.check_auth_expiry(unscoped_auth_ref)
 
-        # domain support can require domain scoped tokens to perform
-        # identity operations depending on the policy files being used
-        # for keystone.
-        domain_auth = None
-        domain_auth_ref = None
-        if utils.get_keystone_version() >= 3 and 'user_domain_name' in kwargs:
-            try:
-                token = unscoped_auth_ref.auth_token
-                domain_auth = utils.get_token_auth_plugin(
-                    auth_url,
-                    token,
-                    domain_name=kwargs['user_domain_name'])
-                domain_auth_ref = domain_auth.get_access(session)
-            except Exception:
-                LOG.debug('Error getting domain scoped token.', exc_info=True)
-
-        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]
+        domain_name = kwargs.get('user_domain_name', None)
+        domain_auth, domain_auth_ref = plugin.get_domain_scoped_auth(
+            unscoped_auth, unscoped_auth_ref, domain_name)
+        scoped_auth, scoped_auth_ref = plugin.get_project_scoped_auth(
+            unscoped_auth, unscoped_auth_ref, recent_project=recent_project)
 
         # Abort if there are no projects for this user and a valid domain
         # token has not been obtained
@@ -171,54 +145,17 @@ class KeystoneBackend(object):
         #                    token)
         #                 3) user cannot obtain a domain scoped token, but can
         #                    obtain a project scoped token
-        if not projects and not domain_auth_ref:
+        if not scoped_auth_ref and domain_auth_ref:
+            # if the user can't obtain a project scoped token, set the scoped
+            # token to be the domain token, if valid
+            scoped_auth = domain_auth
+            scoped_auth_ref = domain_auth_ref
+        elif not scoped_auth_ref and not domain_auth_ref:
             msg = _('You are not authorized for any projects.')
             if utils.get_keystone_version() >= 3:
                 msg = _('You are not authorized for any projects or domains.')
             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:
-            # if the user can't obtain a project scoped token, set the scoped
-            # token to be the domain token, if valid
-            if domain_auth_ref:
-                scoped_auth = domain_auth
-                scoped_auth_ref = domain_auth_ref
-            else:
-                # if no domain or project token for user, abort
-                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)
 
@@ -256,6 +193,9 @@ class KeystoneBackend(object):
             services_region=region_name)
 
         if request is not None:
+            # if no k2k providers exist then the function returns quickly
+            utils.store_initial_k2k_session(auth_url, request, scoped_auth_ref,
+                                            unscoped_auth_ref)
             request.session['unscoped_token'] = unscoped_token
             if domain_auth_ref:
                 # check django session engine, if using cookies, this will not
@@ -276,6 +216,8 @@ class KeystoneBackend(object):
             session_time = min(timeout, int(token_life.total_seconds()))
             request.session.set_expiry(session_time)
 
+            keystone_client_class = utils.get_keystone_client().Client
+            session = utils.get_session()
             scoped_client = keystone_client_class(session=session,
                                                   auth=scoped_auth)
 
diff -pruN 2.4.1-2/openstack_auth/forms.py 3.5.0-0ubuntu1/openstack_auth/forms.py
--- 2.4.1-2/openstack_auth/forms.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/forms.py	2017-07-20 16:39:18.000000000 +0000
@@ -15,11 +15,11 @@ import collections
 import logging
 
 from django.conf import settings
-from django.contrib.auth import authenticate  # noqa
+from django.contrib.auth import authenticate
 from django.contrib.auth import forms as django_auth_forms
 from django import forms
 from django.utils.translation import ugettext_lazy as _
-from django.views.decorators.debug import sensitive_variables  # noqa
+from django.views.decorators.debug import sensitive_variables
 
 from openstack_auth import exceptions
 from openstack_auth import utils
@@ -61,11 +61,22 @@ class Login(django_auth_forms.Authentica
                    'OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT',
                    False):
             last_domain = self.request.COOKIES.get('login_domain', None)
-            self.fields['domain'] = forms.CharField(
-                initial=last_domain,
-                label=_("Domain"),
-                required=True,
-                widget=forms.TextInput(attrs={"autofocus": "autofocus"}))
+            if getattr(settings,
+                       'OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN',
+                       False):
+                self.fields['domain'] = forms.ChoiceField(
+                    label=_("Domain"),
+                    initial=last_domain,
+                    required=True,
+                    choices=getattr(settings,
+                                    'OPENSTACK_KEYSTONE_DOMAIN_CHOICES',
+                                    ()))
+            else:
+                self.fields['domain'] = forms.CharField(
+                    initial=last_domain,
+                    label=_("Domain"),
+                    required=True,
+                    widget=forms.TextInput(attrs={"autofocus": "autofocus"}))
             self.fields['username'].widget = forms.widgets.TextInput()
             fields_ordering = ['domain', 'username', 'password', 'region']
         self.fields['region'].choices = self.get_region_choices()
@@ -124,12 +135,18 @@ class Login(django_auth_forms.Authentica
                                            password=password,
                                            user_domain_name=domain,
                                            auth_url=region)
-            msg = 'Login successful for user "%(username)s".' % \
-                {'username': username}
+            msg = 'Login successful for user "%(username)s", remote address '\
+                '%(remote_ip)s.' % {
+                    'username': username,
+                    'remote_ip': utils.get_client_ip(self.request)
+                }
             LOG.info(msg)
         except exceptions.KeystoneAuthException as exc:
-            msg = 'Login failed for user "%(username)s".' % \
-                {'username': username}
+            msg = 'Login failed for user "%(username)s", remote address '\
+                '%(remote_ip)s.' % {
+                    'username': username,
+                    'remote_ip': utils.get_client_ip(self.request)
+                }
             LOG.warning(msg)
             raise forms.ValidationError(exc)
         if hasattr(self, 'check_for_test_cookie'):  # Dropped in django 1.7
diff -pruN 2.4.1-2/openstack_auth/locale/ar/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ar/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ar/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ar/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,50 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: ar\n"
-"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
-"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Arabic\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "حدث خطأ أثناء المصادقة , يرجى اعادة المحاولة لاحقا."
-
-msgid "Domain"
-msgstr "نطاق"
-
-msgid "Password"
-msgstr "كلمة المرور"
-
-msgid "Region"
-msgstr "المجال"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "انتهت صلاحية الرمز الموثوق الصادر عن خدمة الهوية"
-
-msgid "Unable to authenticate to any available projects."
-msgstr "لايمكن المصادقة لولوج أيٍّ من المشاريع المتاحة."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "لايمكن اظهار المشاريع المتاحة."
-
-msgid "User Name"
-msgstr "اسم المستخدم"
-
-msgid "You are not authorized for any projects."
-msgstr "لايوجد لديك تصريح لدخول أي مشروع."
diff -pruN 2.4.1-2/openstack_auth/locale/ca/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ca/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ca/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ca/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,51 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: ca\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Catalan\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr ""
-"S'ha produït un error d'autenticació. Si us plau, prova de nou més tard."
-
-msgid "Domain"
-msgstr "Domini "
-
-msgid "Password"
-msgstr "Contrasenya"
-
-msgid "Region"
-msgstr "Regió"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr ""
-"La autentificació ha trobat un problema pel servei d'identitat hagi expirat."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "No es pot autenticar als projectes disponibles."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "No es poden recuperar els projectes autoritzats."
-
-msgid "User Name"
-msgstr "Nom d'usuari"
-
-msgid "You are not authorized for any projects."
-msgstr "No esta autoritzat per a cap projecte."
diff -pruN 2.4.1-2/openstack_auth/locale/cs/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/cs/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/cs/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/cs/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,9 +8,9 @@
 # Stanislav Ulrych <stanislav.ulrych@ultimum.io>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.3.1.dev3\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-06-08 21:45+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -58,9 +58,6 @@ msgstr "Změna projektu \"%(project_name
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Autentizační token poskytnutý službou identit vypršel."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Nelze se přihlásit do žádných dostupných projektů."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Nelze se připojit ke keystone endpointu."
 
diff -pruN 2.4.1-2/openstack_auth/locale/de/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/de/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/de/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/de/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,20 +8,22 @@
 # Robert Simai, 2015
 # Robert Simai, 2015
 # Frank Kloeker <eumel@arcor.de>, 2016. #zanata
+# Andreas Jaeger <jaegerandi@gmail.com>, 2017. #zanata
+# Robert Simai <robert.simai@suse.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev9\n"
+"Project-Id-Version: django_openstack_auth 3.1.2.dev14\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-23 11:12+0000\n"
+"POT-Creation-Date: 2017-04-07 13:52+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-03-07 07:54+0000\n"
-"Last-Translator: Andreas Jaeger <jaegerandi@gmail.com>\n"
+"PO-Revision-Date: 2017-03-28 08:35+0000\n"
+"Last-Translator: Robert Simai <robert.simai@suse.com>\n"
 "Language: de\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: German\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -32,12 +34,18 @@ msgstr ""
 msgid "Authenticate using"
 msgstr "Authentifizieren mit"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Dienstanbieter ID in Keystone nicht gefunden."
+
 msgid "Domain"
 msgstr "Domäne"
 
 msgid "Invalid credentials."
 msgstr "Unzureichende Berechtigung."
 
+msgid "K2K Federation not setup for this session"
+msgstr "K2K Verbund ist für diese Sitzung nicht eingerichtet"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -49,6 +57,10 @@ msgid "Password"
 msgstr "Passwort"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr "Bitte ändern Sie Ihr Passwort. Es läuft in %s Minuten ab."
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "Projektumschaltung für Benutzer \"%(username)s\" fehlgeschlagen."
 
@@ -56,6 +68,15 @@ msgid "Region"
 msgstr "Region"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "Dienstanbieter Authentifizierung fehlgeschlagen. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr ""
+"Umschalten zum Keystone Anbieter \"%(keystone_provider)s\" erfolgreich."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "Umschalten zum Projekt \"%(project_name)s\" erfolgreich."
 
@@ -63,12 +84,12 @@ msgid "The authentication token issued b
 msgstr ""
 "Das vom Identitätsdienst ausgegebene Authentifizierungs-Token ist abgelaufen."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Außerstande bei irgendeinem verfügbaren Projekt zu authentifizieren."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Es kann keine Verbindung zum Keystone Endpunkt aufgebaut werden."
 
+msgid "Unable to retrieve authorized domains."
+msgstr "Die authorisierten Domänen können nicht abgerufen werden."
+
 msgid "Unable to retrieve authorized projects."
 msgstr "Authorisierte Projekte können nicht abgerufen werden."
 
diff -pruN 2.4.1-2/openstack_auth/locale/en_AU/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/en_AU/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/en_AU/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/en_AU/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -9,9 +9,9 @@
 # Tom Fifield <tom@openstack.org>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev1\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-20 22:54+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -59,9 +59,6 @@ msgstr "Switch to project \"%(project_na
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "The authentication token issued by the Identity service has expired."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Unable to authenticate to any available projects."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Unable to establish connection to keystone endpoint."
 
diff -pruN 2.4.1-2/openstack_auth/locale/en_GB/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/en_GB/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/en_GB/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/en_GB/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -9,9 +9,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.3.1.dev3\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-06-08 21:45+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -59,9 +59,6 @@ msgstr "Switch to project \"%(project_na
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "The authentication token issued by the Identity service has expired."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Unable to authenticate to any available projects."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Unable to establish connection to keystone endpoint."
 
diff -pruN 2.4.1-2/openstack_auth/locale/es/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/es/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/es/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/es/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -12,9 +12,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -62,9 +62,6 @@ msgstr "Cambio al proyecto \"%(project_n
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "El token de autenticación emitido por Identity Service ha expirado."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "No se puede autenticar en ninguno de los proyectos disponibles."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "No ha sido posible establecer conexión con el endpoint de keystone."
 
diff -pruN 2.4.1-2/openstack_auth/locale/es_MX/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/es_MX/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/es_MX/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/es_MX/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,9 +8,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -61,9 +61,6 @@ msgid "The authentication token issued b
 msgstr ""
 "El token de autenticación otorgado por el servicio de identidad ha expirado."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "No se puede autenticar a los proyectos disponibles."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "No es posible establecer conexión a punto final de la clave base."
 
diff -pruN 2.4.1-2/openstack_auth/locale/fi_FI/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/fi_FI/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/fi_FI/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/fi_FI/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,50 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Toni Willberg <twillber@redhat.com>, 2014
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: fi-FI\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Finnish (Finland)\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "Tunnistautumisvirhe. Yritä uudelleen myöhemmin."
-
-msgid "Domain"
-msgstr "Toimialue"
-
-msgid "Password"
-msgstr "Salasana"
-
-msgid "Region"
-msgstr "Alue"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "Tunnistuspalvelun myöntämä tunniste on vanhentunut."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "Tunnistautuminen projekteihin epäonnistui."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "Projektilistan nouto ei onnistunut."
-
-msgid "User Name"
-msgstr "Käyttäjätunnus"
-
-msgid "You are not authorized for any projects."
-msgstr "Sinulla ei ole oikeutta yhteenkään projektiin."
diff -pruN 2.4.1-2/openstack_auth/locale/fr/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/fr/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/fr/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/fr/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -10,18 +10,19 @@
 # Maxime COQUEREL <max.coquerel@gmail.com>, 2015
 # Patte D <pattedeph@gmail.com>, 2015
 # Xavier Gauvrit <xavier.gauvrit@cloudwatt.com>, 2014
-# Adrien Cunin <adrien@adriencunin.fr>, 2016. #zanata
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# Gérald LONLAS <g.lonlas@gmail.com>, 2016. #zanata
+# JF Taltavull <jftalta@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev1\n"
+"Project-Id-Version: django_openstack_auth 3.1.2.dev2\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-20 22:54+0000\n"
+"POT-Creation-Date: 2017-02-04 23:47+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-08-09 12:52+0000\n"
-"Last-Translator: Adrien Cunin <adrien@adriencunin.fr>\n"
+"PO-Revision-Date: 2017-02-05 10:44+0000\n"
+"Last-Translator: JF Taltavull <jftalta@gmail.com>\n"
 "Language: fr\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "Generated-By: Babel 2.0\n"
@@ -36,11 +37,17 @@ msgstr ""
 msgid "Authenticate using"
 msgstr "Mode d'authentification"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Impossible de trouver l'ID du fournisseur de services sur Keystone."
+
 msgid "Domain"
 msgstr "Domaine"
 
 msgid "Invalid credentials."
-msgstr "Informations d'identification non valides."
+msgstr "Informations d'authentification non valides."
+
+msgid "K2K Federation not setup for this session"
+msgstr "La fédération K2K n'a pas été configurée pour cette session"
 
 msgid ""
 "No authentication backend could be determined to handle the provided "
@@ -58,6 +65,15 @@ msgid "Region"
 msgstr "Région"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "L'authentification du fournisseur de services a échoué. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr ""
+"Bascule vers le fournisseur Keystone \"%(keystone_provider)s\" réussie."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "Bascule vers le projet \"%(project_name)s\" réussie. "
 
@@ -65,11 +81,11 @@ msgid "The authentication token issued b
 msgstr ""
 "Le jeton d'authentification délivré par le service d'Identité a expiré."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Authentification impossible quel que soit le projet."
-
 msgid "Unable to establish connection to keystone endpoint."
-msgstr "Impossible d'établir la connexion avec le point d'accès keystone."
+msgstr "Impossible d'établir la connexion avec le endpoint keystone."
+
+msgid "Unable to retrieve authorized domains."
+msgstr "Impossible de récupérer les domaines autorisés."
 
 msgid "Unable to retrieve authorized projects."
 msgstr "Impossible de récupérer les projets autorisés."
@@ -80,6 +96,5 @@ msgstr "Nom d'utilisateur"
 msgid "You are not authorized for any projects or domains."
 msgstr "Vous n'êtes autorisé sur aucun projet ou domaine."
 
-#, fuzzy
 msgid "You are not authorized for any projects."
 msgstr "Vous n'êtes autorisé sur aucun projet."
diff -pruN 2.4.1-2/openstack_auth/locale/hi/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/hi/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/hi/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/hi/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,49 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: hi\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Hindi\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "पहचान सेवा में त्रुटि. बाद में पुन: प्रयास करें."
-
-msgid "Domain"
-msgstr "अनुक्षेत्र"
-
-msgid "Password"
-msgstr "पासवर्ड"
-
-msgid "Region"
-msgstr "क्षेत्र"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "पहचान सेवा द्वारा जारी प्रमाणीकरण टोकन समाप्त हो गया है."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "किसी भी उपलब्ध परियोजनाओं को प्रमाणित करने में असमर्थ."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "अधिकृत परियोजनाओं को पुनः प्राप्त करने में असमर्थ."
-
-msgid "User Name"
-msgstr "उपयोगकर्ता"
-
-msgid "You are not authorized for any projects."
-msgstr "आप किसी भी परियोजनाओं के लिए अधिकृत नहीं हैं."
diff -pruN 2.4.1-2/openstack_auth/locale/id/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/id/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/id/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/id/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -6,20 +6,21 @@
 # Translators:
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 # suhartono <cloudsuhartono@gmail.com>, 2016. #zanata
+# suhartono <cloudsuhartono@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev1\n"
+"Project-Id-Version: django_openstack_auth 3.1.2.dev15\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-20 22:54+0000\n"
+"POT-Creation-Date: 2017-04-10 01:40+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-09-11 02:55+0000\n"
+"PO-Revision-Date: 2017-04-11 03:47+0000\n"
 "Last-Translator: suhartono <cloudsuhartono@gmail.com>\n"
 "Language: id\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Indonesian\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -28,12 +29,18 @@ msgstr "Terjadi kesalahan otentikasi. Si
 msgid "Authenticate using"
 msgstr "Otentikasi penggunaan"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Tidak dapat menemukan provider layanan ID di Keystone."
+
 msgid "Domain"
 msgstr "Domain"
 
 msgid "Invalid credentials."
 msgstr "Kredensial tidak valid."
 
+msgid "K2K Federation not setup for this session"
+msgstr "K2K Federation tidak menyiapkan untuk sesi ini"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -45,6 +52,11 @@ msgid "Password"
 msgstr "Password"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr ""
+"Silakan mempertimbangkan mengubah sandi Anda, inu akan berakhir pada %s menit"
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "Switch proyek gagal untuk pengguna \"%(username)s\"."
 
@@ -52,6 +64,14 @@ msgid "Region"
 msgstr "Region"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "Ootentikasi provider layanan gagal. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr "Switch ke Keystone Provider \"%(keystone_provider)s\" berhasil."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "Switch proyek \"%(project_name)s\" sukses."
 
@@ -59,12 +79,12 @@ msgid "The authentication token issued b
 msgstr ""
 "Token otentikasi yang dikeluarkan oleh layanan Identity telah berakhir."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Tidak dapat otentikasi ke proyek-proyek yang tersedia."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Tidak dapat melakukan koneksi ke endpoint keystone."
 
+msgid "Unable to retrieve authorized domains."
+msgstr "Tidak dapat mengambil domain yang berwenang."
+
 msgid "Unable to retrieve authorized projects."
 msgstr "Tidak dapat mengambil proyek yang berwenang (authorized)"
 
diff -pruN 2.4.1-2/openstack_auth/locale/it/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/it/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/it/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/it/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,9 +8,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -60,10 +60,6 @@ msgstr ""
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Il token di autenticazione che stai usando è scaduto."
 
-msgid "Unable to authenticate to any available projects."
-msgstr ""
-"Impossibile effettuare l'autenticazione su nessun progetto disponibile."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Impossibile stabilire una connessione con gli endpoint di keystone. "
 
diff -pruN 2.4.1-2/openstack_auth/locale/ja/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ja/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ja/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ja/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -10,20 +10,22 @@
 # ykatabam <ykatabam@redhat.com>, 2015
 # Mie Yamamoto <myamamot@redhat.com>, 2016. #zanata
 # Yuko Katabami <yukokatabami@gmail.com>, 2016. #zanata
+# Akihiro Motoki <amotoki@gmail.com>, 2017. #zanata
+# Yuko Katabami <yukokatabami@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev9\n"
+"Project-Id-Version: django_openstack_auth 3.3.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-23 11:12+0000\n"
+"POT-Creation-Date: 2017-07-12 14:10+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-09-24 05:51+0000\n"
-"Last-Translator: Mie Yamamoto <myamamot@redhat.com>\n"
+"PO-Revision-Date: 2017-07-11 02:05+0000\n"
+"Last-Translator: Akihiro Motoki <amotoki@gmail.com>\n"
 "Language: ja\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Japanese\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -32,12 +34,18 @@ msgstr "認証中にエラーが発生
 msgid "Authenticate using"
 msgstr "使用する認証方法"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Keystone でサービスプロバイダー ID を見つけることができませんでした。"
+
 msgid "Domain"
 msgstr "ドメイン"
 
 msgid "Invalid credentials."
 msgstr "無効な認証情報です。"
 
+msgid "K2K Federation not setup for this session"
+msgstr "このセッションには K2K フェデレーションは設定されていません。"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -47,6 +55,11 @@ msgid "Password"
 msgstr "パスワード"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr ""
+"パスワードの変更をお薦めします。今のパスワードはあと %s 分で無効になります。"
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "ユーザー \"%(username)s\" のプロジェクト切り替えに失敗しました。"
 
@@ -54,18 +67,28 @@ msgid "Region"
 msgstr "リージョン"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "サービスプロバイダーの認証に失敗しました。%s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr ""
+"Keystone プロバイダー \"%(keystone_provider)s\" への切り替えが正常に完了しま"
+"した。"
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "プロジェクト \"%(project_name)s\" へ正常に切り替えました。"
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Identity サービスにより発行された認証トークンの期限が切れました。"
 
-msgid "Unable to authenticate to any available projects."
-msgstr "利用可能などのプロジェクトに対しても認証できませんでした。"
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Keystone エンドポイントへの接続を確立できません。"
 
+msgid "Unable to retrieve authorized domains."
+msgstr "認証されたドメインを取得できません。"
+
 msgid "Unable to retrieve authorized projects."
 msgstr "権限を持っているプロジェクトの情報を取得できません。"
 
diff -pruN 2.4.1-2/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ko_KR/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,20 +8,22 @@
 # Sungjin Kang <potopro@gmail.com>, 2015
 # Andrea Young Oak Li <youli@redhat.com>, 2016. #zanata
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# Jun-Sik Shin <jsshin@smartx.kr>, 2017. #zanata
+# Sungjin Kang <gang.sungjin@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.4.1.dev1\n"
+"Project-Id-Version: django_openstack_auth 3.2.1.dev2\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-09-20 22:54+0000\n"
+"POT-Creation-Date: 2017-06-07 17:46+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-09-15 11:45+0000\n"
-"Last-Translator: Andrea Young Oak Li <youli@redhat.com>\n"
+"PO-Revision-Date: 2017-06-08 01:53+0000\n"
+"Last-Translator: Jun-Sik Shin <jsshin@smartx.kr>\n"
 "Language: ko-KR\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Korean (South Korea)\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -30,12 +32,18 @@ msgstr "인증 중 오류가 발생했
 msgid "Authenticate using"
 msgstr "인증 방법"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Keystone 에서 서비스 프로바이더 ID 를 찾지 못하였습니다."
+
 msgid "Domain"
 msgstr "도메인"
 
 msgid "Invalid credentials."
 msgstr "올바르지 않은 인증정보입니다."
 
+msgid "K2K Federation not setup for this session"
+msgstr "이 세션에는 K2K Federation 이 설정되지 않았습니다."
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -46,6 +54,10 @@ msgid "Password"
 msgstr "암호"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr "암호는 %s 분 후에 만료되므로 변경해 주시기 바랍니다."
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "사용자 \"%(username)s\" 에 대한 프로젝트 전환에 실패했습니다."
 
@@ -53,18 +65,26 @@ msgid "Region"
 msgstr "지역"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "서비스 프로바이더 인증에 실패했습니다. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr "Keystone 프로바이더 \"%(keystone_provider)s\" 로 변경하였습니다."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "프로젝트 \"%(project_name)s\" 로 전환에 성공하였습니다."
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Identity 서비스에서 발급한 인증 토큰이 만료되었습니다."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "사용 가능한 어떤 프로젝트에서도 인증할 수 없습니다."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Keystone 엔드포인트에 접속할 수 없습니다."
 
+msgid "Unable to retrieve authorized domains."
+msgstr "인증된 도메인을 찾지 못했습니다."
+
 msgid "Unable to retrieve authorized projects."
 msgstr "인증된 프로젝트를 가져올 수 없습니다."
 
diff -pruN 2.4.1-2/openstack_auth/locale/ne/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ne/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ne/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ne/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,50 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Surit Aryal <surit_people@hotmail.com>, 2014
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: ne\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Nepali\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "प्रमाणीकरणमा त्रुटि भयो। पछि फेरि प्रयास गर्नुहोस्।"
-
-msgid "Domain"
-msgstr "डोमेन"
-
-msgid "Password"
-msgstr "पासवर्ड"
-
-msgid "Region"
-msgstr "क्षेत्र"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "पहिचान सेवा द्वारा जारी प्रमाणीकरण टोकन समाप्त भएको छ।"
-
-msgid "Unable to authenticate to any available projects."
-msgstr "कुनै पनि उपलब्ध परियोजनाहरु प्रमाणीकरण गर्न असमर्थ।"
-
-msgid "Unable to retrieve authorized projects."
-msgstr "अधिकृत परियोजनाहरू प्राप्त गर्न सकिएन।"
-
-msgid "User Name"
-msgstr "प्रयोगकर्ताको नाम"
-
-msgid "You are not authorized for any projects."
-msgstr "तपाईलाई कुनै पनि परियोजनाको अधिकार छैन।"
diff -pruN 2.4.1-2/openstack_auth/locale/nl_NL/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/nl_NL/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/nl_NL/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/nl_NL/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,9 +8,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -42,9 +42,6 @@ msgid "The authentication token issued b
 msgstr ""
 "De door de identiteitsdienst verstrekte authenticatietoken is verlopen."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Niet in staat u te authenticeren bij enig beschikbaar project."
-
 msgid "Unable to retrieve authorized projects."
 msgstr "Niet in staat om de geauthentificeerde projecten op te halen."
 
diff -pruN 2.4.1-2/openstack_auth/locale/pa_IN/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/pa_IN/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/pa_IN/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/pa_IN/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -7,9 +7,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -55,9 +55,6 @@ msgstr "\"%(project_name)s\" ਪ੍ਰ
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "ਪਛਾਣ ਸੇਵਾ ਵਲੋਂ ਜਾਰੀ ਕੀਤੇ ਪਰਮਾਣਕਿਤਾ ਟੋਕਨ ਦੀ ਮਿਆਦ ਪੁੱਗ ਚੁੱਕੀ ਹੈ।"
 
-msgid "Unable to authenticate to any available projects."
-msgstr "ਕਿਸੇ ਵੀ ਉਪਲੱਬਧ ਪ੍ਰਾਜੈਕਟਾਂ ਨਾਲ ਪ੍ਰਮਾਣਿਕ ਹੋਣ ਤੋਂ ਅਸਮਰੱਥ।"
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "ਕੀਅਸਟੋਨ ਅੰਤ ਬਿੰਦੂ ਨਾਲ ਸੰਬੰਧ ਸਥਾਪਤ ਕਰਨ ਤੋਂ ਅਸਮਰੱਥ।"
 
diff -pruN 2.4.1-2/openstack_auth/locale/pl_PL/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/pl_PL/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/pl_PL/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/pl_PL/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -8,9 +8,9 @@
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
@@ -59,9 +59,6 @@ msgstr "Przełączono na projekt „%(pr
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Token uwierzytelniania wydany przez usługę uwierzytelniania wygasł."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Nie można uwierzytelnić do żadnego z istniejących projektów."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Nie można nawiązać połączenia z usługą keystone."
 
diff -pruN 2.4.1-2/openstack_auth/locale/pt/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/pt/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/pt/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/pt/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,50 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# alfalb_mansil, 2014
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: pt\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Portuguese\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "Ocorreu um erro de autenticação. Por favor, tente de novo mais tarde."
-
-msgid "Domain"
-msgstr "Domínio"
-
-msgid "Password"
-msgstr "Senha"
-
-msgid "Region"
-msgstr "Região"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "A senha de autenticação gerada pelo serviço de identidade expirou."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "Não foi possível autenticar qualquer projeto disponível."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "Não foi possível obter os projetos autorizados."
-
-msgid "User Name"
-msgstr "Nome de Utilizador"
-
-msgid "You are not authorized for any projects."
-msgstr "Não não está autorizado para quaisquer projetos."
diff -pruN 2.4.1-2/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/pt_BR/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -7,20 +7,21 @@
 # Andre Campos Bezerra <andrecbezerra@gmail.com>, 2015
 # Gabriel Wainer, 2015
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# Fernando Pimenta <fernando.c.pimenta@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.2.1.dev5\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-06-28 12:08+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-03-09 02:54+0000\n"
-"Last-Translator: Marcelo Dieder <marcelodieder@gmail.com>\n"
+"PO-Revision-Date: 2017-06-28 12:37+0000\n"
+"Last-Translator: Fernando Pimenta <fernando.c.pimenta@gmail.com>\n"
 "Language: pt-BR\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Portuguese (Brazil)\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -29,12 +30,18 @@ msgstr "Um erro ocorreu autenticando. Po
 msgid "Authenticate using"
 msgstr "Autenticar usando"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Não consegui encontrar o ID do provedor de serviço no Keystone."
+
 msgid "Domain"
 msgstr "Domínio"
 
 msgid "Invalid credentials."
 msgstr "Credencial Inválida"
 
+msgid "K2K Federation not setup for this session"
+msgstr "K2K Federation não está configurada para esta sessão"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -46,6 +53,11 @@ msgid "Password"
 msgstr "Senha"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr ""
+"Por favor, considere a alteração de sua senha, ela irá expirar em %s minutos"
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "A troca de projeto falhou para o usuário \"%(username)s\"."
 
@@ -53,18 +65,28 @@ msgid "Region"
 msgstr "Região"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "Autenticação do provedor de serviço falhou. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr ""
+"Troca para o Provedor Keystone \"%(keystone_provider)s\" realizada com "
+"sucesso."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "Troca para o projeto \"%(project_name)s\" realizada com sucesso."
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "O token de autenticação emitido pelo serviço de identidade expirou."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Não foi possível autenticar nos projetos disponíveis."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Não foi possível estabelecer conexão com o endpoint do Keystone."
 
+msgid "Unable to retrieve authorized domains."
+msgstr "Não foi possível recuperar domínios autorizados."
+
 msgid "Unable to retrieve authorized projects."
 msgstr "Não foi possível obter os projetos autorizados."
 
diff -pruN 2.4.1-2/openstack_auth/locale/ru/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/ru/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/ru/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/ru/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -10,16 +10,17 @@
 # Ilya Shakhat <shakhat@gmail.com>, 2015
 # Nikita Burtsev, 2015
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# Artem <amikhalev90@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev1\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-01-25 19:41+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-12-21 09:13+0000\n"
-"Last-Translator: Kirill Zaitsev <k.zaitsev@me.com>\n"
+"PO-Revision-Date: 2017-01-23 12:43+0000\n"
+"Last-Translator: Artem <amikhalev90@gmail.com>\n"
 "Language: ru\n"
 "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
 "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
@@ -34,6 +35,9 @@ msgstr "Произошла ошибка
 msgid "Authenticate using"
 msgstr "Аутентификация с использованием"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Не удалось найти ИД поставщика служб в Keystone."
+
 msgid "Domain"
 msgstr "Домен"
 
@@ -57,15 +61,16 @@ msgid "Region"
 msgstr "Регион"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "Неудачная аутентикация поставщика службы. %s"
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "Переключение на проект \"%(project_name)s\" выполнено успешно."
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "Время действия токена, выданного сервисом идентификации, истекло."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Невозможно аутентифицировать ни в одном доступном проекте"
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Невозможно установить соединение с точкой доступа keystone."
 
diff -pruN 2.4.1-2/openstack_auth/locale/sl_SI/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/sl_SI/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/sl_SI/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/sl_SI/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,50 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: sl-SI\n"
-"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n"
-"%100==4 ? 2 : 3);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Slovenian (Slovenia)\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "Pri avtentikaciji je prišlo do napake. Poskusite znova kasneje."
-
-msgid "Domain"
-msgstr "Domena"
-
-msgid "Password"
-msgstr "Geslo"
-
-msgid "Region"
-msgstr "Regija"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr "Dostopovni žeton, ki ga uporablja Keystone, je potekel."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "Prijava v razpoložljive projekte ni uspela."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "Seznama avtoriziranih projektov ni bilo mogoče prikazati."
-
-msgid "User Name"
-msgstr "Uporabniško ime"
-
-msgid "You are not authorized for any projects."
-msgstr "Za nobenega od projektov nimate ustreznih uporabniških pravic."
diff -pruN 2.4.1-2/openstack_auth/locale/sr/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/sr/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/sr/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/sr/LC_MESSAGES/django.po	1970-01-01 00:00:00.000000000 +0000
@@ -1,52 +0,0 @@
-# Translations template for django_openstack_auth.
-# Copyright (C) 2015 ORGANIZATION
-# This file is distributed under the same license as the
-# django_openstack_auth project.
-#
-# Translators:
-# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
-msgid ""
-msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-07-16 01:34+0000\n"
-"Last-Translator: openstackjenkins <jenkins@openstack.org>\n"
-"Language: sr\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
-"Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
-"Language-Team: Serbian\n"
-
-msgid "An error occurred authenticating. Please try again later."
-msgstr "Greška u proveri autentičnosti. Pokušajte ponovo kasnije."
-
-msgid "Domain"
-msgstr "Domen"
-
-msgid "Password"
-msgstr "Lozinka"
-
-msgid "Region"
-msgstr "Region"
-
-msgid "The authentication token issued by the Identity service has expired."
-msgstr ""
-"Token za dokaz autentičnosti dodeljen od servisa za identifikaciju je "
-"istekao."
-
-msgid "Unable to authenticate to any available projects."
-msgstr "Nema projekata za koje je Vaša autentičnost odgovarajuća."
-
-msgid "Unable to retrieve authorized projects."
-msgstr "Nije moguće dosegnuti autorizovane projekte."
-
-msgid "User Name"
-msgstr "Korisničko ime"
-
-msgid "You are not authorized for any projects."
-msgstr "Vi nemate projekat u kome ste autorizovani."
diff -pruN 2.4.1-2/openstack_auth/locale/tr_TR/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/tr_TR/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/tr_TR/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/tr_TR/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -6,20 +6,21 @@
 # Translators:
 # İşbaran Akçayır <isbaran@gmail.com>, 2015
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# işbaran akçayır <isbaran@gmail.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.2.dev20\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-05-18 13:23+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-03-04 01:43+0000\n"
-"Last-Translator: Mücahit Büyükyılmaz <mucahit@deltanoc.com>\n"
+"PO-Revision-Date: 2017-05-22 09:01+0000\n"
+"Last-Translator: Copied by Zanata <copied-by-zanata@zanata.org>\n"
 "Language: tr-TR\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Turkish (Turkey)\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -28,12 +29,18 @@ msgstr "Bilinmeyen bir hata oluştu. Lü
 msgid "Authenticate using"
 msgstr "Kimlik doğrulama"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "Keystone için servis sağlayıcı ID'si bulunamadı."
+
 msgid "Domain"
 msgstr "Domain"
 
 msgid "Invalid credentials."
 msgstr "Geçersiz giriş bilgileri."
 
+msgid "K2K Federation not setup for this session"
+msgstr "K2K Birleşimi bu oturum için kurulmamış"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -45,6 +52,11 @@ msgid "Password"
 msgstr "Şifre"
 
 #, python-format
+msgid "Please consider changing your password, it will expire in %s minutes"
+msgstr ""
+"Lütfen parolanızı değiştirmeyin düşünün, %s dakikada süresini dolduracak"
+
+#, python-format
 msgid "Project switch failed for user \"%(username)s\"."
 msgstr "\"%(username)s\" kullanıcısı için proje geçişi başarısız."
 
@@ -52,6 +64,14 @@ msgid "Region"
 msgstr "Bölge"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "Servis sağlayıcı kimlik doğrulama başarısız. %s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr "\"%(keystone_provider)s\" Keystone Sağlayıcısına geçiş başarılı."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "\"%(project_name)s\" projesine geçiş başarılı."
 
@@ -59,12 +79,12 @@ msgid "The authentication token issued b
 msgstr ""
 "Kimlik servisi tarafından verilen kimlik doğrulama belirtecinin süresi doldu."
 
-msgid "Unable to authenticate to any available projects."
-msgstr "Mevcut projelerde kimlik doğrulanamadı."
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "Keystone uç noktasına bağlantı kurulamadı."
 
+msgid "Unable to retrieve authorized domains."
+msgstr "Yetkili alanlar alınamadı."
+
 msgid "Unable to retrieve authorized projects."
 msgstr "Yetkiniz bulunan projeler alınamadı."
 
diff -pruN 2.4.1-2/openstack_auth/locale/zh_CN/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/zh_CN/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/zh_CN/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/zh_CN/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -10,20 +10,21 @@
 # Ying Chun Guo <daisy.ycguo@gmail.com>, 2015
 # 刘俊朋 <liujunpeng@inspur.com>, 2015
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# liujunpeng <liujunpeng@inspur.com>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.2.dev10\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-03-14 12:20+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-03-23 06:22+0000\n"
-"Last-Translator: qingszhao <zdqyuqing@163.com>\n"
+"PO-Revision-Date: 2017-02-10 12:14+0000\n"
+"Last-Translator: liujunpeng <liujunpeng@inspur.com>\n"
 "Language: zh-CN\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
-"X-Generator: Zanata 3.7.3\n"
+"X-Generator: Zanata 3.9.6\n"
 "Language-Team: Chinese (China)\n"
 
 msgid "An error occurred authenticating. Please try again later."
@@ -32,12 +33,18 @@ msgstr "认证出现错误。请稍后
 msgid "Authenticate using"
 msgstr "使用认证"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "在Keystone上不能找到服务提供者ID。"
+
 msgid "Domain"
 msgstr "域"
 
 msgid "Invalid credentials."
 msgstr "凭据无效."
 
+msgid "K2K Federation not setup for this session"
+msgstr "会话没有建立K2K联邦"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -54,18 +61,26 @@ msgid "Region"
 msgstr "区域"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "服务提供者认证失败。%s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr "成功切换到 Keystone 提供者\"%(keystone_provider)s\"."
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "成功切换到项目\"%(project_name)s\""
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "身份认证令牌已过期。"
 
-msgid "Unable to authenticate to any available projects."
-msgstr "无法验证任何可用的项目。"
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "无法连接keystone端点。"
 
+msgid "Unable to retrieve authorized domains."
+msgstr "无法获取授权域。"
+
 msgid "Unable to retrieve authorized projects."
 msgstr "无法获取授权的项目。"
 
diff -pruN 2.4.1-2/openstack_auth/locale/zh_TW/LC_MESSAGES/django.po 3.5.0-0ubuntu1/openstack_auth/locale/zh_TW/LC_MESSAGES/django.po
--- 2.4.1-2/openstack_auth/locale/zh_TW/LC_MESSAGES/django.po	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/locale/zh_TW/LC_MESSAGES/django.po	2017-07-20 16:39:18.000000000 +0000
@@ -6,16 +6,17 @@
 # Translators:
 # Zhang Xiaowei <zero00072@gmail.com>, 2015
 # Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
+# Ching Kuo <gene@openstack.org>, 2017. #zanata
 msgid ""
 msgstr ""
-"Project-Id-Version: django_openstack_auth 2.2.1.dev12\n"
+"Project-Id-Version: django_openstack_auth 3.1.1.dev12\n"
 "Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-05-09 19:52+0000\n"
+"POT-Creation-Date: 2017-02-02 16:33+0000\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2016-03-22 09:32+0000\n"
-"Last-Translator: Jennifer <cristxu@tw.ibm.com>\n"
+"PO-Revision-Date: 2017-02-02 07:53+0000\n"
+"Last-Translator: Ching Kuo <gene@openstack.org>\n"
 "Language: zh-TW\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
 "Generated-By: Babel 2.0\n"
@@ -28,12 +29,18 @@ msgstr "認證發生錯誤。請稍後
 msgid "Authenticate using"
 msgstr "認證使用"
 
+msgid "Could not find service provider ID on Keystone."
+msgstr "在Keystone找不到服務提供者ID"
+
 msgid "Domain"
 msgstr "地域"
 
 msgid "Invalid credentials."
 msgstr "無效的認證。"
 
+msgid "K2K Federation not setup for this session"
+msgstr "這個session並未設定K2K聯合"
+
 msgid ""
 "No authentication backend could be determined to handle the provided "
 "credentials."
@@ -50,18 +57,26 @@ msgid "Region"
 msgstr "區域"
 
 #, python-format
+msgid "Service provider authentication failed. %s"
+msgstr "服務來源認證錯誤。%s"
+
+#, python-format
+msgid "Switch to Keystone Provider \"%(keystone_provider)s\"successful."
+msgstr "成功切換認證來源到 \"%(keystone_provider)s\""
+
+#, python-format
 msgid "Switch to project \"%(project_name)s\" successful."
 msgstr "成功切換至專案 \"%(project_name)s\"。"
 
 msgid "The authentication token issued by the Identity service has expired."
 msgstr "認證伺服器發佈的門票已經過期。"
 
-msgid "Unable to authenticate to any available projects."
-msgstr "無法認證到任何可用的專案。"
-
 msgid "Unable to establish connection to keystone endpoint."
 msgstr "無法建立與 Keystone 端點的連線。"
 
+msgid "Unable to retrieve authorized domains."
+msgstr "無法獲得認證過的地域。"
+
 msgid "Unable to retrieve authorized projects."
 msgstr "無法取回已授權的專案。"
 
diff -pruN 2.4.1-2/openstack_auth/models.py 3.5.0-0ubuntu1/openstack_auth/models.py
--- 2.4.1-2/openstack_auth/models.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/models.py	2017-07-20 16:39:18.000000000 +0000
@@ -12,4 +12,7 @@
 # limitations under the License.
 
 # import the User model in here so Django can find it
-from openstack_auth.user import User        # noqa
+from openstack_auth.user import User
+
+
+__all__ = ['User']
diff -pruN 2.4.1-2/openstack_auth/plugin/base.py 3.5.0-0ubuntu1/openstack_auth/plugin/base.py
--- 2.4.1-2/openstack_auth/plugin/base.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/plugin/base.py	2017-07-20 16:39:18.000000000 +0000
@@ -11,6 +11,7 @@
 # under the License.
 
 import abc
+import logging
 
 from django.utils.translation import ugettext_lazy as _
 from keystoneauth1 import exceptions as keystone_exceptions
@@ -21,6 +22,7 @@ import six
 from openstack_auth import exceptions
 from openstack_auth import utils
 
+LOG = logging.getLogger(__name__)
 __all__ = ['BasePlugin']
 
 
@@ -95,3 +97,145 @@ class BasePlugin(object):
                 keystone_exceptions.AuthorizationFailure):
             msg = _('Unable to retrieve authorized projects.')
             raise exceptions.KeystoneAuthException(msg)
+
+    def list_domains(self, session, auth_plugin, auth_ref=None):
+        try:
+            if self.keystone_version >= 3:
+                client = v3_client.Client(session=session, auth=auth_plugin)
+                return client.auth.domains()
+            else:
+                return []
+        except (keystone_exceptions.ClientException,
+                keystone_exceptions.AuthorizationFailure):
+            msg = _('Unable to retrieve authorized domains.')
+            raise exceptions.KeystoneAuthException(msg)
+
+    def get_access_info(self, keystone_auth):
+        """Get the access info from an unscoped auth
+
+        This function provides the base functionality that the
+        plugins will use to authenticate and get the access info object.
+
+        :param keystone_auth: keystoneauth1 identity plugin
+        :raises: exceptions.KeystoneAuthException on auth failure
+        :returns: keystoneclient.access.AccessInfo
+        """
+        session = utils.get_session()
+
+        try:
+            unscoped_auth_ref = keystone_auth.get_access(session)
+        except keystone_exceptions.ConnectFailure 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)
+        return unscoped_auth_ref
+
+    def get_project_scoped_auth(self, unscoped_auth, unscoped_auth_ref,
+                                recent_project=None):
+        """Get the project scoped keystone auth and access info
+
+        This function returns a project scoped keystone token plugin
+        and AccessInfo object.
+
+        :param unscoped_auth: keystone auth plugin
+        :param unscoped_auth_ref: keystoneclient.access.AccessInfo` or None.
+        :param recent_project: project that we should try to scope to
+        :return: keystone token auth plugin, AccessInfo object
+        """
+        auth_url = unscoped_auth.auth_url
+        session = utils.get_session()
+
+        projects = self.list_projects(
+            session, unscoped_auth, unscoped_auth_ref)
+        # Attempt to scope only to enabled projects
+        projects = [project for project in projects if project.enabled]
+
+        # 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
+
+        scoped_auth = None
+        scoped_auth_ref = None
+        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):
+                LOG.info('Attempted scope to project %s failed, will attempt'
+                         'to scope to another project.' % project.name)
+                pass
+            else:
+                break
+
+        return scoped_auth, scoped_auth_ref
+
+    def get_domain_scoped_auth(self, unscoped_auth, unscoped_auth_ref,
+                               domain_name=None):
+        """Get the domain scoped keystone auth and access info
+
+        This function returns a domain scoped keystone token plugin
+        and AccessInfo object.
+
+        :param unscoped_auth: keystone auth plugin
+        :param unscoped_auth_ref: keystoneclient.access.AccessInfo` or None.
+        :param domain_name: domain that we should try to scope to
+        :return: keystone token auth plugin, AccessInfo object
+        """
+        session = utils.get_session()
+        auth_url = unscoped_auth.auth_url
+
+        if utils.get_keystone_version() < 3:
+            return None, None
+        if domain_name:
+            domains = [domain_name]
+        else:
+            domains = self.list_domains(session,
+                                        unscoped_auth,
+                                        unscoped_auth_ref)
+            domains = [domain.name for domain in domains if domain.enabled]
+
+        # domain support can require domain scoped tokens to perform
+        # identity operations depending on the policy files being used
+        # for keystone.
+        domain_auth = None
+        domain_auth_ref = None
+        for domain_name in domains:
+            token = unscoped_auth_ref.auth_token
+            domain_auth = utils.get_token_auth_plugin(
+                auth_url,
+                token,
+                domain_name=domain_name)
+            try:
+                domain_auth_ref = domain_auth.get_access(session)
+            except (keystone_exceptions.ClientException,
+                    keystone_exceptions.AuthorizationFailure):
+                LOG.info('Attempted scope to domain %s failed, will attempt'
+                         'to scope to another domain.' % domain_name)
+                pass
+            else:
+                if len(domains) > 1:
+                    LOG.info("More than one valid domain found for user %s,"
+                             " scoping to %s" %
+                             (unscoped_auth_ref.user_id, domain_name))
+                break
+        return domain_auth, domain_auth_ref
diff -pruN 2.4.1-2/openstack_auth/plugin/__init__.py 3.5.0-0ubuntu1/openstack_auth/plugin/__init__.py
--- 2.4.1-2/openstack_auth/plugin/__init__.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/plugin/__init__.py	2017-07-20 16:39:18.000000000 +0000
@@ -10,11 +10,13 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
-from openstack_auth.plugin.base import *  # noqa
-from openstack_auth.plugin.password import *  # noqa
-from openstack_auth.plugin.token import *  # noqa
+from openstack_auth.plugin.base import BasePlugin
+from openstack_auth.plugin.k2k import K2KAuthPlugin
+from openstack_auth.plugin.password import PasswordPlugin
+from openstack_auth.plugin.token import TokenPlugin
 
 
 __all__ = ['BasePlugin',
            'PasswordPlugin',
-           'TokenPlugin']
+           'TokenPlugin',
+           'K2KAuthPlugin']
diff -pruN 2.4.1-2/openstack_auth/plugin/k2k.py 3.5.0-0ubuntu1/openstack_auth/plugin/k2k.py
--- 2.4.1-2/openstack_auth/plugin/k2k.py	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/plugin/k2k.py	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,107 @@
+# 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.
+
+import logging
+
+from django.conf import settings
+from django.utils.translation import ugettext_lazy as _
+from keystoneauth1.identity import v3 as v3_auth
+
+from openstack_auth import exceptions
+from openstack_auth.plugin import base
+from openstack_auth import utils
+
+LOG = logging.getLogger(__name__)
+
+__all__ = ['K2KAuthPlugin']
+
+
+class K2KAuthPlugin(base.BasePlugin):
+
+    def get_plugin(self, service_provider=None, auth_url=None, plugins=None,
+                   **kwargs):
+        """Authenticate using keystone to keystone federation.
+
+        This plugin uses other v3 plugins to authenticate a user to a
+        identity provider in order to authenticate the user to a service
+        provider
+
+        :param service_provider: service provider ID
+        :param auth_url: Keystone auth url
+        :param plugins: list of openstack_auth plugins to check
+        :returns Keystone2Keystone keystone auth plugin
+        """
+
+        # Avoid mutable default arg for plugins
+        plugins = plugins or []
+
+        # service_provider being None prevents infinite recursion
+        if utils.get_keystone_version() < 3 or not service_provider:
+            return None
+
+        keystone_idp_id = getattr(settings, 'KEYSTONE_PROVIDER_IDP_ID',
+                                  'localkeystone')
+        if service_provider == keystone_idp_id:
+            return None
+
+        for plugin in plugins:
+            unscoped_idp_auth = plugin.get_plugin(plugins=plugins,
+                                                  auth_url=auth_url, **kwargs)
+            if unscoped_idp_auth:
+                break
+        else:
+            LOG.debug('Could not find base authentication backend for '
+                      'K2K plugin with the provided credentials.')
+            return None
+
+        idp_exception = None
+        scoped_idp_auth = None
+        unscoped_auth_ref = base.BasePlugin.get_access_info(
+            self, unscoped_idp_auth)
+        try:
+            scoped_idp_auth, __ = self.get_project_scoped_auth(
+                unscoped_idp_auth, unscoped_auth_ref)
+        except exceptions.KeystoneAuthException as idp_excp:
+            idp_exception = idp_excp
+
+        if not scoped_idp_auth or idp_exception:
+            msg = 'Identity provider authentication Failed.'
+            raise exceptions.KeystoneAuthException(msg)
+
+        session = utils.get_session()
+
+        if scoped_idp_auth.get_sp_auth_url(session, service_provider) is None:
+            msg = _('Could not find service provider ID on Keystone.')
+            raise exceptions.KeystoneAuthException(msg)
+
+        unscoped_auth = v3_auth.Keystone2Keystone(
+            base_plugin=scoped_idp_auth,
+            service_provider=service_provider)
+        return unscoped_auth
+
+    def get_access_info(self, unscoped_auth):
+        """Get the access info object
+
+        We attempt to get the auth ref. If it fails and if the K2K auth plugin
+        was being used then we will prepend a message saying that the error was
+        on the service provider side.
+        :param: unscoped_auth: Keystone auth plugin for unscoped user
+        :returns: keystoneclient.access.AccessInfo object
+        """
+        try:
+            unscoped_auth_ref = base.BasePlugin.get_access_info(
+                self, unscoped_auth)
+        except exceptions.KeystoneAuthException as excp:
+            msg = _('Service provider authentication failed. %s')
+            raise exceptions.KeystoneAuthException(msg % str(excp))
+        return unscoped_auth_ref
diff -pruN 2.4.1-2/openstack_auth/policy.py 3.5.0-0ubuntu1/openstack_auth/policy.py
--- 2.4.1-2/openstack_auth/policy.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/policy.py	2017-07-20 16:39:18.000000000 +0000
@@ -75,7 +75,8 @@ def check(actions, request, target=None)
     to policy setting.
 
     :param actions: list of scope and action to do policy checks on,
-        the composition of which is (scope, action)
+        the composition of which is (scope, action). Multiple actions
+        are treated as a logical AND.
 
         * scope: service type managing the policy for action
 
@@ -153,12 +154,16 @@ def check(actions, request, target=None)
             # needed when a domain scoped token is present
             if scope == 'identity' and domain_credentials:
                 # use domain credentials
-                return _check_credentials(
-                    enforcer[scope], action, target, domain_credentials)
+                if not _check_credentials(enforcer[scope],
+                                          action,
+                                          target,
+                                          domain_credentials):
+                    return False
 
             # use project credentials
-            return _check_credentials(
-                enforcer[scope], action, target, credentials)
+            if not _check_credentials(enforcer[scope],
+                                      action, target, credentials):
+                return False
 
         # if no policy for scope, allow action, underlying API will
         # ultimately block the action if not permitted, treat as though
diff -pruN 2.4.1-2/openstack_auth/tests/data_v3.py 3.5.0-0ubuntu1/openstack_auth/tests/data_v3.py
--- 2.4.1-2/openstack_auth/tests/data_v3.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/tests/data_v3.py	2017-07-20 16:39:18.000000000 +0000
@@ -55,7 +55,8 @@ class TestResponse(requests.Response):
         return self._text
 
 
-def generate_test_data(pki=False):
+def generate_test_data(pki=False, service_providers=False,
+                       endpoint='localhost'):
     '''Builds a set of test_data data as returned by Keystone V2.'''
     test_data = TestDataContainer()
 
@@ -64,19 +65,19 @@ def generate_test_data(pki=False):
         'id': uuid.uuid4().hex,
         'endpoints': [
             {
-                'url': 'http://admin.localhost:35357/v3',
+                'url': 'http://admin.%s:35357/v3' % endpoint,
                 'region': 'RegionOne',
                 'interface': 'admin',
                 'id': uuid.uuid4().hex,
             },
             {
-                'url': 'http://internal.localhost:5000/v3',
+                'url': 'http://internal.%s:5000/v3' % endpoint,
                 'region': 'RegionOne',
                 'interface': 'internal',
                 'id': uuid.uuid4().hex
             },
             {
-                'url': 'http://public.localhost:5000/v3',
+                'url': 'http://public.%s:5000/v3' % endpoint,
                 'region': 'RegionOne',
                 'interface': 'public',
                 'id': uuid.uuid4().hex
@@ -131,43 +132,43 @@ def generate_test_data(pki=False):
         'id': uuid.uuid4().hex,
         'endpoints': [
             {
-                'url': ('http://nova-admin.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova-admin.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionOne',
                 'interface': 'admin',
                 'id': uuid.uuid4().hex,
             },
             {
-                'url': ('http://nova-internal.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova-internal.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionOne',
                 'interface': 'internal',
                 'id': uuid.uuid4().hex
             },
             {
-                'url': ('http://nova-public.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova-public.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionOne',
                 'interface': 'public',
                 'id': uuid.uuid4().hex
             },
             {
-                'url': ('http://nova2-admin.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova2-admin.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionTwo',
                 'interface': 'admin',
                 'id': uuid.uuid4().hex,
             },
             {
-                'url': ('http://nova2-internal.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova2-internal.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionTwo',
                 'interface': 'internal',
                 'id': uuid.uuid4().hex
             },
             {
-                'url': ('http://nova2-public.localhost:8774/v2.0/%s'
-                        % (project_dict_1['id'])),
+                'url': ('http://nova2-public.%s:8774/v2.0/%s'
+                        % (endpoint, project_dict_1['id'])),
                 'region': 'RegionTwo',
                 'interface': 'public',
                 'id': uuid.uuid4().hex
@@ -218,6 +219,19 @@ def generate_test_data(pki=False):
         }
     }
 
+    sp_list = None
+    if service_providers:
+        test_data.sp_auth_url = 'http://service_provider_endp:5000/v3'
+        test_data.service_provider_id = 'k2kserviceprovider'
+        # The access info for the identity provider
+        # should return a list of service providers
+        sp_list = [
+            {'auth_url': test_data.sp_auth_url,
+             'id': test_data.service_provider_id,
+             'sp_url': 'https://k2kserviceprovider/sp_url'}
+        ]
+        scoped_token_dict['token']['service_providers'] = sp_list
+
     test_data.scoped_access_info = access.create(
         resp=auth_response,
         body=scoped_token_dict
@@ -264,6 +278,9 @@ def generate_test_data(pki=False):
         }
     }
 
+    if service_providers:
+        unscoped_token_dict['token']['service_providers'] = sp_list
+
     test_data.unscoped_access_info = access.create(
         resp=auth_response,
         body=unscoped_token_dict
diff -pruN 2.4.1-2/openstack_auth/tests/settings.py 3.5.0-0ubuntu1/openstack_auth/tests/settings.py
--- 2.4.1-2/openstack_auth/tests/settings.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/tests/settings.py	2017-07-20 16:39:18.000000000 +0000
@@ -13,6 +13,8 @@
 
 import os
 
+ALLOWED_HOSTS = ['*']
+
 DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3'}}
 
 INSTALLED_APPS = [
@@ -70,3 +72,5 @@ TEMPLATES = [
         'APP_DIRS': True,
     },
 ]
+
+AUTH_USER_MODEL = 'openstack_auth.User'
diff -pruN 2.4.1-2/openstack_auth/tests/tests.py 3.5.0-0ubuntu1/openstack_auth/tests/tests.py
--- 2.4.1-2/openstack_auth/tests/tests.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/tests/tests.py	2017-07-20 16:39:18.000000000 +0000
@@ -29,7 +29,7 @@ from keystoneclient.v2_0 import client a
 from keystoneclient.v3 import client as client_v3
 import mock
 from mox3 import mox
-from testscenarios import load_tests_apply_scenarios  # noqa
+from testscenarios import load_tests_apply_scenarios
 
 from openstack_auth import policy
 from openstack_auth.tests import data_v2
@@ -55,6 +55,7 @@ class OpenStackAuthTestsMixin(object):
         plugin = self._create_password_auth()
         plugin.get_access(mox.IsA(session.Session)). \
             AndReturn(self.data.unscoped_access_info)
+        plugin.auth_url = settings.OPENSTACK_KEYSTONE_URL
         return self.ks_client_module.Client(session=mox.IsA(session.Session),
                                             auth=plugin)
 
@@ -75,15 +76,18 @@ class OpenStackAuthTestsMixin(object):
         plugin.get_access(mox.IsA(session.Session)).AndRaise(exc)
 
     def _mock_scoped_client_for_tenant(self, auth_ref, tenant_id, url=None,
-                                       client=True):
+                                       client=True, token=None):
         if url is None:
             url = settings.OPENSTACK_KEYSTONE_URL
 
+        if not token:
+            token = self.data.unscoped_access_info.auth_token
+
         plugin = self._create_token_auth(
             tenant_id,
-            token=self.data.unscoped_access_info.auth_token,
+            token=token,
             url=url)
-
+        self.scoped_token_auth = plugin
         plugin.get_access(mox.IsA(session.Session)).AndReturn(auth_ref)
         if client:
             return self.ks_client_module.Client(
@@ -97,6 +101,53 @@ class OpenStackAuthTestsMixin(object):
                 'username': user.name}
 
 
+class OpenStackAuthFederatedTestsMixin(object):
+    """Common functions for federation"""
+    def _mock_unscoped_federated_list_projects(self, client, projects):
+        client.federation = self.mox.CreateMockAnything()
+        client.federation.projects = self.mox.CreateMockAnything()
+        client.federation.projects.list().AndReturn(projects)
+
+    def _mock_unscoped_list_domains(self, client, domains):
+        client.auth = self.mox.CreateMockAnything()
+        client.auth.domains().AndReturn(domains)
+
+    def _mock_unscoped_token_client(self, unscoped, auth_url=None,
+                                    client=True, plugin=None):
+        if not auth_url:
+            auth_url = settings.OPENSTACK_KEYSTONE_URL
+        if unscoped and not plugin:
+            plugin = self._create_token_auth(
+                None,
+                token=unscoped.auth_token,
+                url=auth_url)
+            plugin.get_access(mox.IsA(session.Session)).AndReturn(unscoped)
+        plugin.auth_url = auth_url
+        if client:
+            return self.ks_client_module.Client(
+                session=mox.IsA(session.Session),
+                auth=plugin)
+
+    def _mock_plugin(self, unscoped, auth_url=None):
+        if not auth_url:
+            auth_url = settings.OPENSTACK_KEYSTONE_URL
+        plugin = self._create_token_auth(
+            None,
+            token=unscoped.auth_token,
+            url=auth_url)
+        plugin.get_access(mox.IsA(session.Session)).AndReturn(unscoped)
+        plugin.auth_url = settings.OPENSTACK_KEYSTONE_URL
+        return plugin
+
+    def _mock_federated_client_list_projects(self, unscoped_auth, projects):
+        client = self._mock_unscoped_token_client(None, plugin=unscoped_auth)
+        self._mock_unscoped_federated_list_projects(client, projects)
+
+    def _mock_federated_client_list_domains(self, unscoped_auth, domains):
+        client = self._mock_unscoped_token_client(None, plugin=unscoped_auth)
+        self._mock_unscoped_list_domains(client, domains)
+
+
 class OpenStackAuthTestsV2(OpenStackAuthTestsMixin, test.TestCase):
 
     def setUp(self):
@@ -130,20 +181,6 @@ class OpenStackAuthTestsV2(OpenStackAuth
         client = self._mock_unscoped_client(user)
         self._mock_unscoped_list_tenants(client, tenants)
 
-    def _mock_client_delete_token(self, user, token, url=None):
-        if not url:
-            url = settings.OPENSTACK_KEYSTONE_URL
-
-        plugin = token_endpoint.Token(
-            endpoint=url,
-            token=self.data.unscoped_access_info.auth_token)
-
-        client = self.ks_client_module.Client(session=mox.IsA(session.Session),
-                                              auth=plugin)
-        client.tokens = self.mox.CreateMockAnything()
-        client.tokens.delete(token=token)
-        return client
-
     def _create_password_auth(self, username=None, password=None, url=None):
         if not username:
             username = self.data.user.name
@@ -340,7 +377,6 @@ class OpenStackAuthTestsV2(OpenStackAuth
 
         self._mock_unscoped_client_list_tenants(user, tenants)
         self._mock_scoped_client_for_tenant(unscoped, self.data.tenant_one.id)
-        self._mock_client_delete_token(user, unscoped.auth_token, endpoint)
         self._mock_scoped_client_for_tenant(scoped, tenant.id, url=endpoint,
                                             client=False)
 
@@ -445,7 +481,9 @@ class OpenStackAuthTestsV2(OpenStackAuth
         self.assertEqual(tenant_list, expected_tenants)
 
 
-class OpenStackAuthTestsV3(OpenStackAuthTestsMixin, test.TestCase):
+class OpenStackAuthTestsV3(OpenStackAuthTestsMixin,
+                           OpenStackAuthFederatedTestsMixin,
+                           test.TestCase):
 
     def _mock_unscoped_client_list_projects(self, user, projects):
         client = self._mock_unscoped_client(user)
@@ -460,6 +498,13 @@ class OpenStackAuthTestsV3(OpenStackAuth
         self._mock_unscoped_list_projects_fail(client, user)
 
     def _mock_unscoped_list_projects_fail(self, client, user):
+        plugin = self._create_token_auth(
+            project_id=None,
+            domain_name=DEFAULT_DOMAIN,
+            token=self.data.unscoped_access_info.auth_token,
+            url=settings.OPENSTACK_KEYSTONE_URL)
+        plugin.get_access(mox.IsA(session.Session)).AndReturn(
+            self.data.domain_scoped_access_info)
         client.projects = self.mox.CreateMockAnything()
         client.projects.list(user=user.id).AndRaise(
             keystone_exceptions.AuthorizationFailure)
@@ -546,6 +591,7 @@ class OpenStackAuthTestsV3(OpenStackAuth
         self.mox.StubOutClassWithMocks(v3_auth, 'Token')
         self.mox.StubOutClassWithMocks(v3_auth, 'Password')
         self.mox.StubOutClassWithMocks(client_v3, 'Client')
+        self.mox.StubOutClassWithMocks(v3_auth, 'Keystone2Keystone')
 
     def test_login(self):
         projects = [self.data.project_one, self.data.project_two]
@@ -788,6 +834,247 @@ class OpenStackAuthTestsV3(OpenStackAuth
     def test_switch_region_with_next(self, next=None):
         self.test_switch_region(next='/next_url')
 
+    def test_switch_keystone_provider_remote_fail(self):
+        auth_url = settings.OPENSTACK_KEYSTONE_URL
+        target_provider = 'k2kserviceprovider'
+        self.data = data_v3.generate_test_data(service_providers=True)
+        self.sp_data = data_v3.generate_test_data(endpoint='http://sp2')
+        projects = [self.data.project_one, self.data.project_two]
+        user = self.data.user
+        unscoped = self.data.unscoped_access_info
+        form_data = self.get_form_data(user)
+
+        # mock authenticate
+        self._mock_unscoped_and_domain_list_projects(user, projects)
+        self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
+
+        # mock switch
+        plugin = v3_auth.Token(auth_url=auth_url,
+                               token=unscoped.auth_token,
+                               project_id=None,
+                               reauthenticate=False)
+        plugin.get_access(mox.IsA(session.Session)
+                          ).AndReturn(self.data.unscoped_access_info)
+        plugin.auth_url = auth_url
+        client = self.ks_client_module.Client(session=mox.IsA(session.Session),
+                                              auth=plugin)
+
+        self._mock_unscoped_list_projects(client, user, projects)
+        plugin = self._create_token_auth(
+            self.data.project_one.id,
+            token=self.data.unscoped_access_info.auth_token,
+            url=settings.OPENSTACK_KEYSTONE_URL)
+        plugin.get_access(mox.IsA(session.Session)).AndReturn(
+            settings.OPENSTACK_KEYSTONE_URL)
+        plugin.get_sp_auth_url(
+            mox.IsA(session.Session), target_provider
+        ).AndReturn('https://k2kserviceprovider/sp_url')
+
+        # let the K2K plugin fail when logging in
+        plugin = v3_auth.Keystone2Keystone(
+            base_plugin=plugin, service_provider=target_provider)
+        plugin.get_access(mox.IsA(session.Session)).AndRaise(
+            keystone_exceptions.AuthorizationFailure)
+        self.mox.ReplayAll()
+
+        # Log in
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.post(url, form_data)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Switch
+        url = reverse('switch_keystone_provider', args=[target_provider])
+        form_data['keystone_provider'] = target_provider
+        response = self.client.get(url, form_data, follow=True)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Assert that provider has not changed because of failure
+        self.assertEqual(self.client.session['keystone_provider_id'],
+                         'localkeystone')
+        # These should never change
+        self.assertEqual(self.client.session['k2k_base_unscoped_token'],
+                         unscoped.auth_token)
+        self.assertEqual(self.client.session['k2k_auth_url'], auth_url)
+
+    def test_switch_keystone_provider_remote(self):
+        auth_url = settings.OPENSTACK_KEYSTONE_URL
+        target_provider = 'k2kserviceprovider'
+        self.data = data_v3.generate_test_data(service_providers=True)
+        self.sp_data = data_v3.generate_test_data(endpoint='http://sp2')
+        projects = [self.data.project_one, self.data.project_two]
+        domains = []
+        user = self.data.user
+        unscoped = self.data.unscoped_access_info
+        form_data = self.get_form_data(user)
+
+        # mock authenticate
+        self._mock_unscoped_and_domain_list_projects(user, projects)
+        self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
+
+        # mock switch
+        plugin = v3_auth.Token(auth_url=auth_url,
+                               token=unscoped.auth_token,
+                               project_id=None,
+                               reauthenticate=False)
+        plugin.get_access(mox.IsA(session.Session)).AndReturn(
+            self.data.unscoped_access_info)
+
+        plugin.auth_url = auth_url
+        client = self.ks_client_module.Client(session=mox.IsA(session.Session),
+                                              auth=plugin)
+
+        self._mock_unscoped_list_projects(client, user, projects)
+        plugin = self._create_token_auth(
+            self.data.project_one.id,
+            token=self.data.unscoped_access_info.auth_token,
+            url=settings.OPENSTACK_KEYSTONE_URL)
+        plugin.get_access(mox.IsA(session.Session)).AndReturn(
+            settings.OPENSTACK_KEYSTONE_URL)
+
+        plugin.get_sp_auth_url(
+            mox.IsA(session.Session), target_provider
+        ).AndReturn('https://k2kserviceprovider/sp_url')
+        plugin = v3_auth.Keystone2Keystone(base_plugin=plugin,
+                                           service_provider=target_provider)
+        plugin.get_access(mox.IsA(session.Session)). \
+            AndReturn(self.sp_data.unscoped_access_info)
+        plugin.auth_url = 'http://service_provider_endp:5000/v3'
+
+        # mock authenticate for service provider
+        sp_projects = [self.sp_data.project_one, self.sp_data.project_two]
+        sp_unscoped = self.sp_data.federated_unscoped_access_info
+        sp_unscoped_auth = self._mock_plugin(sp_unscoped,
+                                             auth_url=plugin.auth_url)
+        client = self._mock_unscoped_token_client(None, plugin.auth_url,
+                                                  plugin=sp_unscoped_auth)
+        self._mock_unscoped_list_domains(client, domains)
+        client = self._mock_unscoped_token_client(None, plugin.auth_url,
+                                                  plugin=sp_unscoped_auth)
+        self._mock_unscoped_federated_list_projects(client, sp_projects)
+        self._mock_scoped_client_for_tenant(sp_unscoped,
+                                            self.sp_data.project_one.id,
+                                            url=plugin.auth_url,
+                                            token=sp_unscoped.auth_token)
+
+        self.mox.ReplayAll()
+
+        # Log in
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.post(url, form_data)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Switch
+        url = reverse('switch_keystone_provider', args=[target_provider])
+        form_data['keystone_provider'] = target_provider
+        response = self.client.get(url, form_data, follow=True)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Assert keystone provider has changed
+        self.assertEqual(self.client.session['keystone_provider_id'],
+                         target_provider)
+        # These should not change
+        self.assertEqual(self.client.session['k2k_base_unscoped_token'],
+                         unscoped.auth_token)
+        self.assertEqual(self.client.session['k2k_auth_url'], auth_url)
+
+    def test_switch_keystone_provider_local(self):
+        auth_url = settings.OPENSTACK_KEYSTONE_URL
+        self.data = data_v3.generate_test_data(service_providers=True)
+        keystone_provider = 'localkeystone'
+        projects = [self.data.project_one, self.data.project_two]
+        domains = []
+        user = self.data.user
+        unscoped = self.data.unscoped_access_info
+        form_data = self.get_form_data(user)
+
+        # mock authenticate
+        self._mock_unscoped_and_domain_list_projects(user, projects)
+        self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
+        self._mock_unscoped_token_client(unscoped,
+                                         auth_url=auth_url,
+                                         client=False)
+        unscoped_auth = self._mock_plugin(unscoped)
+        client = self._mock_unscoped_token_client(None, auth_url=auth_url,
+                                                  plugin=unscoped_auth)
+        self._mock_unscoped_list_domains(client, domains)
+        client = self._mock_unscoped_token_client(None, auth_url=auth_url,
+                                                  plugin=unscoped_auth)
+        self._mock_unscoped_list_projects(client, user, projects)
+        self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
+
+        self.mox.ReplayAll()
+
+        # Log in
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.post(url, form_data)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Switch
+        url = reverse('switch_keystone_provider', args=[keystone_provider])
+        form_data['keystone_provider'] = keystone_provider
+        response = self.client.get(url, form_data, follow=True)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Assert nothing has changed since we are going from local to local
+        self.assertEqual(self.client.session['keystone_provider_id'],
+                         keystone_provider)
+        self.assertEqual(self.client.session['k2k_base_unscoped_token'],
+                         unscoped.auth_token)
+        self.assertEqual(self.client.session['k2k_auth_url'], auth_url)
+
+    def test_switch_keystone_provider_local_fail(self):
+        auth_url = settings.OPENSTACK_KEYSTONE_URL
+        self.data = data_v3.generate_test_data(service_providers=True)
+        keystone_provider = 'localkeystone'
+        projects = [self.data.project_one, self.data.project_two]
+        user = self.data.user
+        unscoped = self.data.unscoped_access_info
+        form_data = self.get_form_data(user)
+
+        # mock authenticate
+        self._mock_unscoped_and_domain_list_projects(user, projects)
+        self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
+
+        # Let using the base token for logging in fail
+        plugin = v3_auth.Token(auth_url=auth_url,
+                               token=unscoped.auth_token,
+                               project_id=None,
+                               reauthenticate=False)
+        plugin.get_access(mox.IsA(session.Session)). \
+            AndRaise(keystone_exceptions.AuthorizationFailure)
+        plugin.auth_url = auth_url
+        self.mox.ReplayAll()
+
+        # Log in
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+
+        response = self.client.post(url, form_data)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Switch
+        url = reverse('switch_keystone_provider', args=[keystone_provider])
+        form_data['keystone_provider'] = keystone_provider
+        response = self.client.get(url, form_data, follow=True)
+        self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
+
+        # Assert
+        self.assertEqual(self.client.session['keystone_provider_id'],
+                         keystone_provider)
+        self.assertEqual(self.client.session['k2k_base_unscoped_token'],
+                         unscoped.auth_token)
+        self.assertEqual(self.client.session['k2k_auth_url'], auth_url)
+
     def test_tenant_sorting(self):
         projects = [self.data.project_two, self.data.project_one]
         expected_projects = [self.data.project_one, self.data.project_two]
@@ -804,8 +1091,38 @@ class OpenStackAuthTestsV3(OpenStackAuth
             token=unscoped.auth_token)
         self.assertEqual(project_list, expected_projects)
 
+    def test_login_form_multidomain(self):
+        override = self.settings(OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT=True)
+        override.enable()
+        self.addCleanup(override.disable)
+
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'id="id_domain"')
+        self.assertContains(response, 'name="domain"')
+
+    def test_login_form_multidomain_dropdown(self):
+        override = self.settings(OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT=True,
+                                 OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN=True,
+                                 OPENSTACK_KEYSTONE_DOMAIN_CHOICES=(
+                                     ('Default', 'Default'),)
+                                 )
+        override.enable()
+        self.addCleanup(override.disable)
+
+        url = reverse('login')
+        response = self.client.get(url)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'id="id_domain"')
+        self.assertContains(response, 'name="domain"')
+        self.assertContains(response, 'option value="Default"')
+        settings.OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN = False
+
 
-class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin, test.TestCase):
+class OpenStackAuthTestsWebSSO(OpenStackAuthTestsMixin,
+                               OpenStackAuthFederatedTestsMixin,
+                               test.TestCase):
 
     def _create_token_auth(self, project_id=None, token=None, url=None):
         if not token:
@@ -819,25 +1136,6 @@ class OpenStackAuthTestsWebSSO(OpenStack
                              project_id=project_id,
                              reauthenticate=False)
 
-    def _mock_unscoped_client(self, unscoped):
-        plugin = self._create_token_auth(
-            None,
-            token=unscoped.auth_token,
-            url=settings.OPENSTACK_KEYSTONE_URL)
-        plugin.get_access(mox.IsA(session.Session)).AndReturn(unscoped)
-
-        return self.ks_client_module.Client(session=mox.IsA(session.Session),
-                                            auth=plugin)
-
-    def _mock_unscoped_federated_list_projects(self, client, projects):
-        client.federation = self.mox.CreateMockAnything()
-        client.federation.projects = self.mox.CreateMockAnything()
-        client.federation.projects.list().AndReturn(projects)
-
-    def _mock_unscoped_client_list_projects(self, unscoped, projects):
-        client = self._mock_unscoped_client(unscoped)
-        self._mock_unscoped_federated_list_projects(client, projects)
-
     def setUp(self):
         super(OpenStackAuthTestsWebSSO, self).setUp()
 
@@ -917,11 +1215,14 @@ class OpenStackAuthTestsWebSSO(OpenStack
 
     def test_websso_login(self):
         projects = [self.data.project_one, self.data.project_two]
+        domains = []
         unscoped = self.data.federated_unscoped_access_info
         token = unscoped.auth_token
+        unscoped_auth = self._mock_plugin(unscoped)
 
         form_data = {'token': token}
-        self._mock_unscoped_client_list_projects(unscoped, projects)
+        self._mock_federated_client_list_domains(unscoped_auth, domains)
+        self._mock_federated_client_list_projects(unscoped_auth, projects)
         self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
 
         self.mox.ReplayAll()
@@ -936,11 +1237,14 @@ class OpenStackAuthTestsWebSSO(OpenStack
         settings.OPENSTACK_KEYSTONE_URL = 'http://auth.openstack.org:5000/v3'
 
         projects = [self.data.project_one, self.data.project_two]
+        domains = []
         unscoped = self.data.federated_unscoped_access_info
         token = unscoped.auth_token
+        unscoped_auth = self._mock_plugin(unscoped)
 
         form_data = {'token': token}
-        self._mock_unscoped_client_list_projects(unscoped, projects)
+        self._mock_federated_client_list_domains(unscoped_auth, domains)
+        self._mock_federated_client_list_projects(unscoped_auth, projects)
         self._mock_scoped_client_for_tenant(unscoped, self.data.project_one.id)
 
         self.mox.ReplayAll()
@@ -959,8 +1263,8 @@ class PolicyLoaderTestCase(test.TestCase
         policy.reset()
         enforcer = policy._get_enforcer()
         self.assertEqual(2, len(enforcer))
-        self.assertTrue('identity' in enforcer)
-        self.assertTrue('compute' in enforcer)
+        self.assertIn('identity', enforcer)
+        self.assertIn('compute', enforcer)
 
     def test_policy_reset(self):
         policy._get_enforcer()
@@ -1178,3 +1482,41 @@ class UserTestCase(test.TestCase):
         self.assertTrue(created_token._is_pki_token(
                         self.data.domain_scoped_access_info.auth_token))
         self.assertFalse(created_token._is_pki_token(None))
+
+
+class BehindProxyTestCase(test.TestCase):
+
+    def setUp(self):
+        self.request = http.HttpRequest()
+
+    def test_without_proxy(self):
+        self.request.META['REMOTE_ADDR'] = '10.111.111.2'
+        from openstack_auth.utils import get_client_ip
+        self.assertEqual('10.111.111.2', get_client_ip(self.request))
+
+    def test_with_proxy_no_settings(self):
+        from openstack_auth.utils import get_client_ip
+        self.request.META['REMOTE_ADDR'] = '10.111.111.2'
+        self.request.META['HTTP_X_REAL_IP'] = '192.168.15.33'
+        self.request.META['HTTP_X_FORWARDED_FOR'] = '172.18.0.2'
+        self.assertEqual('10.111.111.2', get_client_ip(self.request))
+
+    def test_with_settings_without_proxy(self):
+        from openstack_auth.utils import get_client_ip
+        self.request.META['REMOTE_ADDR'] = '10.111.111.2'
+        self.assertEqual('10.111.111.2', get_client_ip(self.request))
+
+    @override_settings(SECURE_PROXY_ADDR_HEADER='HTTP_X_FORWARDED_FOR')
+    def test_with_settings_with_proxy_forwardfor(self):
+        from openstack_auth.utils import get_client_ip
+        self.request.META['REMOTE_ADDR'] = '10.111.111.2'
+        self.request.META['HTTP_X_FORWARDED_FOR'] = '172.18.0.2'
+        self.assertEqual('172.18.0.2', get_client_ip(self.request))
+
+    @override_settings(SECURE_PROXY_ADDR_HEADER='HTTP_X_REAL_IP')
+    def test_with_settings_with_proxy_real_ip(self):
+        from openstack_auth.utils import get_client_ip
+        self.request.META['REMOTE_ADDR'] = '10.111.111.2'
+        self.request.META['HTTP_X_REAL_IP'] = '192.168.15.33'
+        self.request.META['HTTP_X_FORWARDED_FOR'] = '172.18.0.2'
+        self.assertEqual('192.168.15.33', get_client_ip(self.request))
diff -pruN 2.4.1-2/openstack_auth/urls.py 3.5.0-0ubuntu1/openstack_auth/urls.py
--- 2.4.1-2/openstack_auth/urls.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/urls.py	2017-07-20 16:39:18.000000000 +0000
@@ -26,7 +26,10 @@ urlpatterns = [
         name='switch_tenants'),
     url(r'^switch_services_region/(?P<region_name>[^/]+)/$',
         views.switch_region,
-        name='switch_services_region')
+        name='switch_services_region'),
+    url(r'^switch_keystone_provider/(?P<keystone_provider>[^/]+)/$',
+        views.switch_keystone_provider,
+        name='switch_keystone_provider')
 ]
 
 if utils.is_websso_enabled():
diff -pruN 2.4.1-2/openstack_auth/user.py 3.5.0-0ubuntu1/openstack_auth/user.py
--- 2.4.1-2/openstack_auth/user.py	2017-07-31 16:10:12.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/user.py	2017-07-20 16:39:18.000000000 +0000
@@ -11,6 +11,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import datetime
 import hashlib
 import logging
 
@@ -42,11 +43,15 @@ def set_session_from_user(request, user)
 
 def create_user_from_token(request, token, endpoint, services_region=None):
     # if the region is provided, use that, otherwise use the preferred region
+    default_service_regions = getattr(settings, 'DEFAULT_SERVICE_REGIONS', {})
+    default_service_region = default_service_regions.get(endpoint)
     svc_region = services_region or \
-        utils.default_services_region(token.serviceCatalog, request)
+        utils.default_services_region(token.serviceCatalog, request,
+                                      selected_region=default_service_region)
     return User(id=token.user['id'],
                 token=token,
                 user=token.user['name'],
+                password_expires_at=token.user['password_expires_at'],
                 user_domain_id=token.user_domain_id,
                 # We need to consider already logged-in users with an old
                 # version of Token without user_domain_name.
@@ -76,9 +81,11 @@ class Token(object):
     """
     def __init__(self, auth_ref, unscoped_token=None):
         # User-related attributes
-        user = {}
-        user['id'] = auth_ref.user_id
-        user['name'] = auth_ref.username
+        user = {'id': auth_ref.user_id, 'name': auth_ref.username}
+        data = getattr(auth_ref, '_data', {})
+        expiration_date = data.get('token', {}).get('user', {})\
+            .get('password_expires_at')
+        user['password_expires_at'] = expiration_date
         self.user = user
         self.user_domain_id = auth_ref.user_domain_id
         self.user_domain_name = auth_ref.user_domain_name
@@ -105,6 +112,7 @@ class Token(object):
         project['name'] = auth_ref.project_name
         project['is_admin_project'] = getattr(auth_ref, 'is_admin_project',
                                               False)
+        project['domain_id'] = getattr(auth_ref, 'project_domain_id', None)
         self.project = project
         self.tenant = self.project
 
@@ -194,6 +202,11 @@ class User(models.AbstractBaseUser, mode
 
         Unscoped Keystone token.
 
+    .. attribute:: password_expires_at
+
+        Password expiration date. This attribute could be None when using
+        keystone version < 3.0 or if the feature is not enabled in keystone.
+
     """
 
     keystone_user_id = db_models.CharField(primary_key=True, max_length=255)
@@ -204,8 +217,8 @@ class User(models.AbstractBaseUser, mode
                  authorized_tenants=None, endpoint=None, enabled=False,
                  services_region=None, user_domain_id=None,
                  user_domain_name=None, domain_id=None, domain_name=None,
-                 project_id=None, project_name=None,
-                 is_federated=False, unscoped_token=None, password=None):
+                 project_id=None, project_name=None, is_federated=False,
+                 unscoped_token=None, password=None, password_expires_at=None):
         self.id = id
         self.pk = id
         self.token = token
@@ -227,6 +240,7 @@ class User(models.AbstractBaseUser, mode
         self.enabled = enabled
         self._authorized_tenants = authorized_tenants
         self.is_federated = is_federated
+        self.password_expires_at = password_expires_at
 
         # Unscoped token is used for listing user's project that works
         # for both federated and keystone user.
@@ -248,8 +262,9 @@ class User(models.AbstractBaseUser, mode
     def is_token_expired(self, margin=None):
         """Determine if the token is expired.
 
-        Returns ``True`` if the token is expired, ``False`` if not, and
-        ``None`` if there is no token set.
+        :returns:
+          ``True`` if the token is expired, ``False`` if not, and
+          ``None`` if there is no token set.
 
         :param margin:
            A security time margin in seconds before real expiration.
@@ -276,7 +291,7 @@ class User(models.AbstractBaseUser, mode
         def is_anonymous(self):
             """Return if the user is not authenticated.
 
-            Returns ``True`` if not authenticated,``False`` otherwise.
+            :returns: ``True`` if not authenticated,``False`` otherwise.
             """
             return deprecation.CallableBool(not self.is_authenticated)
     else:
@@ -296,7 +311,7 @@ class User(models.AbstractBaseUser, mode
         def is_anonymous(self, margin=None):
             """Return if the user is not authenticated.
 
-            Returns ``True`` if not authenticated,``False`` otherwise.
+            :returns: ``True`` if not authenticated,``False`` otherwise.
 
             :param margin:
                A security time margin in seconds before end of an eventual
@@ -316,7 +331,7 @@ class User(models.AbstractBaseUser, mode
     def is_superuser(self):
         """Evaluates whether this user has admin privileges.
 
-        Returns ``True`` or ``False``.
+        :returns: ``True`` or ``False``.
         """
         admin_roles = utils.get_admin_roles()
         user_roles = {role['name'].lower() for role in self.roles}
@@ -423,5 +438,17 @@ class User(models.AbstractBaseUser, mode
                     return False
         return True
 
+    def time_until_expiration(self):
+        """Returns the number of remaining days until user's password expires.
+
+        Calculates the number days until the user must change their password,
+        once the password expires the user will not able to log in until an
+        admin changes its password.
+        """
+        if self.password_expires_at is not None:
+            expiration_date = datetime.datetime.strptime(
+                self.password_expires_at, "%Y-%m-%dT%H:%M:%S.%f")
+            return expiration_date - datetime.datetime.now()
+
     class Meta(object):
         app_label = 'openstack_auth'
diff -pruN 2.4.1-2/openstack_auth/utils.py 3.5.0-0ubuntu1/openstack_auth/utils.py
--- 2.4.1-2/openstack_auth/utils.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/utils.py	2017-07-20 16:39:18.000000000 +0000
@@ -17,7 +17,6 @@ import re
 
 from django.conf import settings
 from django.contrib import auth
-from django.contrib.auth import middleware
 from django.contrib.auth import models
 from django.utils import timezone
 from keystoneauth1.identity import v2 as v2_auth
@@ -62,6 +61,10 @@ def get_user(request):
 
 
 def patch_middleware_get_user():
+    # NOTE(adriant): We can't import middleware until our customer user model
+    # is actually registered, otherwise a call to get_user_model within the
+    # middleware module will fail.
+    from django.contrib.auth import middleware
     middleware.get_user = middleware_get_user
     auth.get_user = get_user
 
@@ -144,6 +147,7 @@ def get_keystone_client():
 
 
 def is_token_deletion_disabled():
+    LOG.warning("Deprecated TOKEN_DELETION_DISABLED setting is no longer used")
     return getattr(settings, 'TOKEN_DELETION_DISABLED', False)
 
 
@@ -185,6 +189,7 @@ def get_websso_url(request, auth_url, we
     :type websso_auth: string
 
     Example of horizon WebSSO setting::
+
         WEBSSO_CHOICES = (
             ("credentials", "Keystone Credentials"),
             ("oidc", "OpenID Connect"),
@@ -206,12 +211,14 @@ def get_websso_url(request, auth_url, we
     The value in WEBSSO_IDP_MAPPING is expected to be a tuple formatted as
     (<idp_id>, <protocol_id>). Using the values found, a IdP/protocol
     specific URL will be constructed:
+
         /auth/OS-FEDERATION/identity_providers/<idp_id>
         /protocols/<protocol_id>/websso
 
     If no value is found from the WEBSSO_IDP_MAPPING dictionary, it will
     treat the value as the global WebSSO protocol <protocol_id> and
     construct the WebSSO URL by:
+
         /auth/OS-FEDERATION/websso/<protocol_id>
 
     :returns: Keystone WebSSO endpoint.
@@ -368,7 +375,8 @@ def get_project_list(*args, **kwargs):
     return projects
 
 
-def default_services_region(service_catalog, request=None):
+def default_services_region(service_catalog, request=None,
+                            selected_region=None):
     """Returns the first endpoint region for first non-identity service.
 
     Extracted from the service catalog.
@@ -392,8 +400,7 @@ def default_services_region(service_cata
                 LOG.error('No regions can be found in the service catalog.')
                 return None
 
-        selected_region = None
-        if request:
+        if request and selected_region is None:
             selected_region = request.COOKIES.get('services_region',
                                                   available_regions[0])
         if selected_region not in available_regions:
@@ -435,12 +442,14 @@ def using_cookie_backed_sessions():
 def get_admin_roles():
     """Common function for getting the admin roles from settings
 
-       Returns:
-        Set object including all admin roles.
-        If there is no role, this will return empty.
+    :return:
+      Set object including all admin roles.
+      If there is no role, this will return empty::
+
         {
             "foo", "bar", "admin"
         }
+
     """
     admin_roles = {role.lower() for role
                    in getattr(settings, 'OPENSTACK_KEYSTONE_ADMIN_ROLES',
@@ -453,9 +462,10 @@ def get_role_permission(role):
 
     This format is 'openstack.roles.xxx' and 'xxx' is a real role name.
 
-    Returns:
+    :returns:
         String like "openstack.roles.admin"
         If role is None, this will return None.
+
     """
     return "openstack.roles.%s" % role.lower()
 
@@ -465,13 +475,88 @@ def get_admin_permissions():
 
     This format is 'openstack.roles.xxx' and 'xxx' is a real role name.
 
-    Returns:
-        Set object including all admin permission.
-        If there is no permission, this will return empty.
+    :returns:
+       Set object including all admin permission.
+       If there is no permission, this will return empty::
+
         {
             "openstack.roles.foo",
             "openstack.roles.bar",
             "openstack.roles.admin"
         }
+
     """
     return {get_role_permission(role) for role in get_admin_roles()}
+
+
+def get_client_ip(request):
+    """Return client ip address using SECURE_PROXY_ADDR_HEADER variable.
+
+    If not present or not defined on settings then REMOTE_ADDR is used.
+
+    :param request: Django http request object.
+    :type request: django.http.HttpRequest
+
+    :returns: Possible client ip address
+    :rtype: string
+    """
+    _SECURE_PROXY_ADDR_HEADER = getattr(
+        settings, 'SECURE_PROXY_ADDR_HEADER', False
+    )
+    if _SECURE_PROXY_ADDR_HEADER:
+        return request.META.get(
+            _SECURE_PROXY_ADDR_HEADER,
+            request.META.get('REMOTE_ADDR')
+        )
+    return request.META.get('REMOTE_ADDR')
+
+
+def store_initial_k2k_session(auth_url, request, scoped_auth_ref,
+                              unscoped_auth_ref):
+    """Stores session variables if there are k2k service providers
+
+    This stores variables related to Keystone2Keystone federation. This
+    function gets skipped if there are no Keystone service providers.
+    An unscoped token to the identity provider keystone gets stored
+    so that it can be used to do federated login into the service
+    providers when switching keystone providers.
+    The settings file can be configured to set the display name
+    of the local (identity provider) keystone by setting
+    KEYSTONE_PROVIDER_IDP_NAME. The KEYSTONE_PROVIDER_IDP_ID settings
+    variable is used for comparison against the service providers.
+    It should not conflict with any of the service provider ids.
+
+    :param auth_url: base token auth url
+    :param request: Django http request object
+    :param scoped_auth_ref: Scoped Keystone access info object
+    :param unscoped_auth_ref: Unscoped Keystone access info object
+    """
+    keystone_provider_id = request.session.get('keystone_provider_id', None)
+    if keystone_provider_id:
+        return None
+
+    providers = getattr(scoped_auth_ref, 'service_providers', None)
+    if providers:
+        providers = getattr(providers, '_service_providers', None)
+
+    if providers:
+        keystone_idp_name = getattr(settings, 'KEYSTONE_PROVIDER_IDP_NAME',
+                                    'Local Keystone')
+        keystone_idp_id = getattr(
+            settings, 'KEYSTONE_PROVIDER_IDP_ID', 'localkeystone')
+        keystone_identity_provider = {'name': keystone_idp_name,
+                                      'id': keystone_idp_id}
+        # (edtubill) We will use the IDs as the display names
+        # We may want to be able to set display names in the future.
+        keystone_providers = [
+            {'name': provider_id, 'id': provider_id}
+            for provider_id in providers]
+
+        keystone_providers.append(keystone_identity_provider)
+
+        # We treat the Keystone idp ID as None
+        request.session['keystone_provider_id'] = keystone_idp_id
+        request.session['keystone_providers'] = keystone_providers
+        request.session['k2k_base_unscoped_token'] =\
+            unscoped_auth_ref.auth_token
+        request.session['k2k_auth_url'] = auth_url
diff -pruN 2.4.1-2/openstack_auth/views.py 3.5.0-0ubuntu1/openstack_auth/views.py
--- 2.4.1-2/openstack_auth/views.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/openstack_auth/views.py	2017-07-20 16:39:18.000000000 +0000
@@ -14,7 +14,7 @@ import logging
 
 from django.conf import settings
 from django.contrib import auth
-from django.contrib.auth.decorators import login_required  # noqa
+from django.contrib.auth.decorators import login_required
 from django.contrib.auth import views as django_auth_views
 from django.contrib import messages
 from django import http as django_http
@@ -22,20 +22,21 @@ from django import shortcuts
 from django.utils import functional
 from django.utils import http
 from django.utils.translation import ugettext_lazy as _
-from django.views.decorators.cache import never_cache  # noqa
-from django.views.decorators.csrf import csrf_exempt  # noqa
-from django.views.decorators.csrf import csrf_protect  # noqa
-from django.views.decorators.debug import sensitive_post_parameters  # noqa
+from django.views.decorators.cache import never_cache
+from django.views.decorators.csrf import csrf_exempt
+from django.views.decorators.csrf import csrf_protect
+from django.views.decorators.debug import sensitive_post_parameters
 from keystoneauth1 import exceptions as keystone_exceptions
-from keystoneauth1 import token_endpoint
 import six
 
 from openstack_auth import exceptions
 from openstack_auth import forms
+from openstack_auth import plugin
+
 # This is historic and is added back in to not break older versions of
 # Horizon, fix to Horizon to remove this requirement was committed in
 # Juno
-from openstack_auth.forms import Login  # noqa
+from openstack_auth.forms import Login  # noqa:F401
 from openstack_auth import user as auth_user
 from openstack_auth import utils
 
@@ -119,6 +120,16 @@ def login(request, template_name=None, e
         region_name = regions.get(login_region)
         request.session['region_endpoint'] = region
         request.session['region_name'] = region_name
+        expiration_time = request.user.time_until_expiration()
+        threshold_days = getattr(
+            settings, 'PASSWORD_EXPIRES_WARNING_THRESHOLD_DAYS', -1)
+        if expiration_time is not None and \
+                expiration_time.days <= threshold_days:
+            expiration_time = str(expiration_time).rsplit(':', 1)[0]
+            msg = (_('Please consider changing your password, it will expire'
+                     ' in %s minutes') %
+                   expiration_time).replace(':', ' Hours and ')
+            messages.warning(request, msg)
     return res
 
 
@@ -159,17 +170,6 @@ def logout(request, login_url=None, **kw
     msg = 'Logging out user "%(username)s".' % \
         {'username': request.user.username}
     LOG.info(msg)
-    endpoint = request.session.get('region_endpoint')
-
-    # delete the project scoped token
-    token = request.session.get('token')
-    if token and endpoint:
-        delete_token(endpoint=endpoint, token_id=token.id)
-
-    # delete the domain scoped token if set
-    domain_token = request.session.get('domain_token')
-    if domain_token and endpoint:
-        delete_token(endpoint=endpoint, token_id=domain_token.auth_token)
 
     """ Securely logs a user out. """
     return django_auth_views.logout_then_login(request, login_url=login_url,
@@ -178,24 +178,7 @@ def logout(request, login_url=None, **kw
 
 def delete_token(endpoint, token_id):
     """Delete a token."""
-    if utils.is_token_deletion_disabled():
-        return
-    try:
-        endpoint, __ = utils.fix_auth_url_version_prefix(endpoint)
-
-        session = utils.get_session()
-        auth_plugin = token_endpoint.Token(endpoint=endpoint,
-                                           token=token_id)
-        client = utils.get_keystone_client().Client(session=session,
-                                                    auth=auth_plugin)
-        if utils.get_keystone_version() >= 3:
-            client.tokens.revoke_token(token=token_id)
-        else:
-            client.tokens.delete(token=token_id)
-
-        LOG.info('Deleted token %s' % token_id)
-    except keystone_exceptions.ClientException:
-        LOG.info('Could not delete token')
+    LOG.warning("The delete_token method is deprecated and now does nothing")
 
 
 @login_required
@@ -234,10 +217,6 @@ def switch(request, tenant_id, redirect_
         redirect_to = settings.LOGIN_REDIRECT_URL
 
     if auth_ref:
-        old_endpoint = request.session.get('region_endpoint')
-        old_token = request.session.get('token')
-        if old_token and old_endpoint and old_token.id != auth_ref.auth_token:
-            delete_token(endpoint=old_endpoint, token_id=old_token.id)
         user = auth_user.create_user_from_token(
             request,
             auth_user.Token(auth_ref, unscoped_token=unscoped_token),
@@ -274,3 +253,75 @@ def switch_region(request, region_name,
     utils.set_response_cookie(response, 'services_region',
                               request.session['services_region'])
     return response
+
+
+@login_required
+def switch_keystone_provider(request, keystone_provider=None,
+                             redirect_field_name=auth.REDIRECT_FIELD_NAME):
+    """Switches the user's keystone provider using K2K Federation
+
+    If keystone_provider is given then we switch the user to
+    the keystone provider using K2K federation. Otherwise if keystone_provider
+    is None then we switch the user back to the Identity Provider Keystone
+    which a non federated token auth will be used.
+    """
+    base_token = request.session.get('k2k_base_unscoped_token', None)
+    k2k_auth_url = request.session.get('k2k_auth_url', None)
+    keystone_providers = request.session.get('keystone_providers', None)
+
+    if not base_token or not k2k_auth_url:
+        msg = _('K2K Federation not setup for this session')
+        raise exceptions.KeystoneAuthException(msg)
+
+    redirect_to = request.GET.get(redirect_field_name, '')
+    if not is_safe_url(url=redirect_to, host=request.get_host()):
+        redirect_to = settings.LOGIN_REDIRECT_URL
+
+    unscoped_auth_ref = None
+    keystone_idp_id = getattr(
+        settings, 'KEYSTONE_PROVIDER_IDP_ID', 'localkeystone')
+
+    if keystone_provider == keystone_idp_id:
+        current_plugin = plugin.TokenPlugin()
+        unscoped_auth = current_plugin.get_plugin(auth_url=k2k_auth_url,
+                                                  token=base_token)
+    else:
+        # Switch to service provider using K2K federation
+        plugins = [plugin.TokenPlugin()]
+        current_plugin = plugin.K2KAuthPlugin()
+
+        unscoped_auth = current_plugin.get_plugin(
+            auth_url=k2k_auth_url, service_provider=keystone_provider,
+            plugins=plugins, token=base_token)
+
+    try:
+        # Switch to identity provider using token auth
+        unscoped_auth_ref = current_plugin.get_access_info(unscoped_auth)
+    except exceptions.KeystoneAuthException as exc:
+        msg = 'Switching to Keystone Provider %s has failed. %s' \
+              % (keystone_provider, (six.text_type(exc)))
+        messages.error(request, msg)
+
+    if unscoped_auth_ref:
+        try:
+            request.user = auth.authenticate(
+                request=request, auth_url=unscoped_auth.auth_url,
+                token=unscoped_auth_ref.auth_token)
+        except exceptions.KeystoneAuthException as exc:
+            msg = 'Keystone provider switch failed: %s' % six.text_type(exc)
+            res = django_http.HttpResponseRedirect(settings.LOGIN_URL)
+            res.set_cookie('logout_reason', msg, max_age=10)
+            return res
+        auth.login(request, request.user)
+        auth_user.set_session_from_user(request, request.user)
+        request.session['keystone_provider_id'] = keystone_provider
+        request.session['keystone_providers'] = keystone_providers
+        request.session['k2k_base_unscoped_token'] = base_token
+        request.session['k2k_auth_url'] = k2k_auth_url
+        message = (
+            _('Switch to Keystone Provider "%(keystone_provider)s"'
+              'successful.') % {'keystone_provider': keystone_provider})
+        messages.success(request, message)
+
+    response = shortcuts.redirect(redirect_to)
+    return response
diff -pruN 2.4.1-2/.pc/Add-is_authenticated-and-is_anonymous-properties.patch/openstack_auth/user.py 3.5.0-0ubuntu1/.pc/Add-is_authenticated-and-is_anonymous-properties.patch/openstack_auth/user.py
--- 2.4.1-2/.pc/Add-is_authenticated-and-is_anonymous-properties.patch/openstack_auth/user.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/.pc/Add-is_authenticated-and-is_anonymous-properties.patch/openstack_auth/user.py	1970-01-01 00:00:00.000000000 +0000
@@ -1,410 +0,0 @@
-# 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.
-
-import hashlib
-import logging
-
-from django.conf import settings
-from django.contrib.auth import models
-from django.db import models as db_models
-from keystoneauth1 import exceptions as keystone_exceptions
-from keystoneclient.common import cms as keystone_cms
-import six
-
-from openstack_auth import utils
-
-
-LOG = logging.getLogger(__name__)
-_TOKEN_HASH_ENABLED = getattr(settings, 'OPENSTACK_TOKEN_HASH_ENABLED', True)
-
-
-def set_session_from_user(request, user):
-    request.session['token'] = user.token
-    request.session['user_id'] = user.id
-    request.session['region_endpoint'] = user.endpoint
-    request.session['services_region'] = user.services_region
-    # Update the user object cached in the request
-    request._cached_user = user
-    request.user = user
-
-
-def create_user_from_token(request, token, endpoint, services_region=None):
-    # if the region is provided, use that, otherwise use the preferred region
-    svc_region = services_region or \
-        utils.default_services_region(token.serviceCatalog, request)
-    return User(id=token.user['id'],
-                token=token,
-                user=token.user['name'],
-                user_domain_id=token.user_domain_id,
-                # We need to consider already logged-in users with an old
-                # version of Token without user_domain_name.
-                user_domain_name=getattr(token, 'user_domain_name', None),
-                project_id=token.project['id'],
-                project_name=token.project['name'],
-                domain_id=token.domain['id'],
-                domain_name=token.domain['name'],
-                enabled=True,
-                service_catalog=token.serviceCatalog,
-                roles=token.roles,
-                endpoint=endpoint,
-                services_region=svc_region,
-                is_federated=getattr(token, 'is_federated', False),
-                unscoped_token=getattr(token, 'unscoped_token',
-                                       request.session.get('unscoped_token')))
-
-
-class Token(object):
-    """Encapsulates the AccessInfo object from keystoneclient.
-
-    Token object provides a consistent interface for accessing the keystone
-    token information and service catalog.
-
-    Added for maintaining backward compatibility with horizon that expects
-    Token object in the user object.
-    """
-    def __init__(self, auth_ref, unscoped_token=None):
-        # User-related attributes
-        user = {}
-        user['id'] = auth_ref.user_id
-        user['name'] = auth_ref.username
-        self.user = user
-        self.user_domain_id = auth_ref.user_domain_id
-        self.user_domain_name = auth_ref.user_domain_name
-
-        # Token-related attributes
-        self.id = auth_ref.auth_token
-        self.unscoped_token = unscoped_token
-        if _TOKEN_HASH_ENABLED and self._is_pki_token(self.id):
-            algorithm = getattr(settings, 'OPENSTACK_TOKEN_HASH_ALGORITHM',
-                                'md5')
-            hasher = hashlib.new(algorithm)
-            hasher.update(self.id.encode('utf-8'))
-            self.id = hasher.hexdigest()
-            # Only hash unscoped token if needed
-            if self._is_pki_token(self.unscoped_token):
-                hasher = hashlib.new(algorithm)
-                hasher.update(self.unscoped_token.encode('utf-8'))
-                self.unscoped_token = hasher.hexdigest()
-        self.expires = auth_ref.expires
-
-        # Project-related attributes
-        project = {}
-        project['id'] = auth_ref.project_id
-        project['name'] = auth_ref.project_name
-        project['is_admin_project'] = getattr(auth_ref, 'is_admin_project',
-                                              False)
-        self.project = project
-        self.tenant = self.project
-
-        # Domain-related attributes
-        domain = {}
-        domain['id'] = auth_ref.domain_id
-        domain['name'] = auth_ref.domain_name
-        self.domain = domain
-
-        # Federation-related attributes
-        self.is_federated = auth_ref.is_federated
-        self.roles = [{'name': role} for role in auth_ref.role_names]
-        self.serviceCatalog = auth_ref.service_catalog.catalog
-
-    def _is_pki_token(self, token):
-        """Determines if this is a pki-based token (pki or pkiz)"""
-        if token is None:
-            return False
-        return (keystone_cms.is_ans1_token(token)
-                or keystone_cms.is_pkiz(token))
-
-
-class User(models.AbstractBaseUser, models.AnonymousUser):
-    """A User class with some extra special sauce for Keystone.
-
-    In addition to the standard Django user attributes, this class also has
-    the following:
-
-    .. attribute:: token
-
-        The Keystone token object associated with the current user/tenant.
-
-        The token object is deprecated, user auth_ref instead.
-
-    .. attribute:: tenant_id
-
-        The id of the Keystone tenant for the current user/token.
-
-        The tenant_id keyword argument is deprecated, use project_id instead.
-
-    .. attribute:: tenant_name
-
-        The name of the Keystone tenant for the current user/token.
-
-        The tenant_name keyword argument is deprecated, use project_name
-        instead.
-
-    .. attribute:: project_id
-
-        The id of the Keystone project for the current user/token.
-
-    .. attribute:: project_name
-
-        The name of the Keystone project for the current user/token.
-
-    .. attribute:: service_catalog
-
-        The ``ServiceCatalog`` data returned by Keystone.
-
-    .. attribute:: roles
-
-        A list of dictionaries containing role names and ids as returned
-        by Keystone.
-
-    .. attribute:: services_region
-
-        A list of non-identity service endpoint regions extracted from the
-        service catalog.
-
-    .. attribute:: user_domain_id
-
-        The domain id of the current user.
-
-    .. attribute:: user_domain_name
-
-        The domain name of the current user.
-
-    .. attribute:: domain_id
-
-        The id of the Keystone domain scoped for the current user/token.
-
-    .. attribute:: is_federated
-
-        Whether user is federated Keystone user. (Boolean)
-
-    .. attribute:: unscoped_token
-
-        Unscoped Keystone token.
-
-    """
-
-    keystone_user_id = db_models.CharField(primary_key=True, max_length=255)
-    USERNAME_FIELD = 'keystone_user_id'
-
-    def __init__(self, id=None, token=None, user=None, tenant_id=None,
-                 service_catalog=None, tenant_name=None, roles=None,
-                 authorized_tenants=None, endpoint=None, enabled=False,
-                 services_region=None, user_domain_id=None,
-                 user_domain_name=None, domain_id=None, domain_name=None,
-                 project_id=None, project_name=None,
-                 is_federated=False, unscoped_token=None, password=None):
-        self.id = id
-        self.pk = id
-        self.token = token
-        self.keystone_user_id = id
-        self.username = user
-        self.user_domain_id = user_domain_id
-        self.user_domain_name = user_domain_name
-        self.domain_id = domain_id
-        self.domain_name = domain_name
-        self.project_id = project_id or tenant_id
-        self.project_name = project_name or tenant_name
-        self.service_catalog = service_catalog
-        self._services_region = (
-            services_region
-            or utils.default_services_region(service_catalog)
-        )
-        self.roles = roles or []
-        self.endpoint = endpoint
-        self.enabled = enabled
-        self._authorized_tenants = authorized_tenants
-        self.is_federated = is_federated
-
-        # Unscoped token is used for listing user's project that works
-        # for both federated and keystone user.
-        self.unscoped_token = unscoped_token
-
-        # List of variables to be deprecated.
-        self.tenant_id = self.project_id
-        self.tenant_name = self.project_name
-
-        # Required by AbstractBaseUser
-        self.password = None
-
-    def __unicode__(self):
-        return self.username
-
-    def __repr__(self):
-        return "<%s: %s>" % (self.__class__.__name__, self.username)
-
-    def is_token_expired(self, margin=None):
-        """Determine if the token is expired.
-
-        Returns ``True`` if the token is expired, ``False`` if not, and
-        ``None`` if there is no token set.
-
-        :param margin:
-           A security time margin in seconds before real expiration.
-           Will return ``True`` if the token expires in less than ``margin``
-           seconds of time.
-           A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
-           django settings.
-
-        """
-        if self.token is None:
-            return None
-        return not utils.is_token_valid(self.token, margin)
-
-    def is_authenticated(self, margin=None):
-        """Checks for a valid authentication.
-
-        :param margin:
-           A security time margin in seconds before end of authentication.
-           Will return ``False`` if authentication ends in less than ``margin``
-           seconds of time.
-           A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
-           django settings.
-
-        """
-        return (self.token is not None and
-                utils.is_token_valid(self.token, margin))
-
-    def is_anonymous(self, margin=None):
-        """Return if the user is not authenticated.
-
-        Returns ``True`` if not authenticated,``False`` otherwise.
-
-        :param margin:
-           A security time margin in seconds before end of an eventual
-           authentication.
-           Will return ``True`` even if authenticated but that authentication
-           ends in less than ``margin`` seconds of time.
-           A default margin can be set by the TOKEN_TIMEOUT_MARGIN in the
-           django settings.
-
-        """
-        return not self.is_authenticated(margin)
-
-    @property
-    def is_active(self):
-        return self.enabled
-
-    @property
-    def is_superuser(self):
-        """Evaluates whether this user has admin privileges.
-
-        Returns ``True`` or ``False``.
-        """
-        admin_roles = utils.get_admin_roles()
-        user_roles = {role['name'].lower() for role in self.roles}
-        return not admin_roles.isdisjoint(user_roles)
-
-    @property
-    def authorized_tenants(self):
-        """Returns a memoized list of tenants this user may access."""
-        if self.is_authenticated() and self._authorized_tenants is None:
-            endpoint = self.endpoint
-            try:
-                self._authorized_tenants = utils.get_project_list(
-                    user_id=self.id,
-                    auth_url=endpoint,
-                    token=self.unscoped_token,
-                    is_federated=self.is_federated)
-            except (keystone_exceptions.ClientException,
-                    keystone_exceptions.AuthorizationFailure):
-                LOG.exception('Unable to retrieve project list.')
-        return self._authorized_tenants or []
-
-    @authorized_tenants.setter
-    def authorized_tenants(self, tenant_list):
-        self._authorized_tenants = tenant_list
-
-    @property
-    def services_region(self):
-        return self._services_region
-
-    @services_region.setter
-    def services_region(self, region):
-        self._services_region = region
-
-    @property
-    def available_services_regions(self):
-        """Returns list of unique region name values in service catalog."""
-        regions = []
-        if self.service_catalog:
-            for service in self.service_catalog:
-                service_type = service.get('type')
-                if service_type is None or service_type == 'identity':
-                    continue
-                for endpoint in service.get('endpoints', []):
-                    region = utils.get_endpoint_region(endpoint)
-                    if region not in regions:
-                        regions.append(region)
-        return regions
-
-    def save(*args, **kwargs):
-        # Presume we can't write to Keystone.
-        pass
-
-    def delete(*args, **kwargs):
-        # Presume we can't write to Keystone.
-        pass
-
-    # Check for OR'd permission rules, check that user has one of the
-    # required permission.
-    def has_a_matching_perm(self, perm_list, obj=None):
-        """Returns True if the user has one of the specified permissions.
-
-        If object is passed, it checks if the user has any of the required
-        perms for this object.
-        """
-        # If there are no permissions to check, just return true
-        if not perm_list:
-            return True
-        # Check that user has at least one of the required permissions.
-        for perm in perm_list:
-            if self.has_perm(perm, obj):
-                return True
-        return False
-
-    # Override the default has_perms method. Allowing for more
-    # complex combinations of permissions.  Will check for logical AND of
-    # all top level permissions.  Will use logical OR for all first level
-    # tuples (check that use has one permissions in the tuple)
-    #
-    # Examples:
-    #   Checks for all required permissions
-    #   ('openstack.roles.admin', 'openstack.roles.L3-support')
-    #
-    #   Checks for admin AND (L2 or L3)
-    #   ('openstack.roles.admin', ('openstack.roles.L3-support',
-    #                              'openstack.roles.L2-support'),)
-    def has_perms(self, perm_list, obj=None):
-        """Returns True if the user has all of the specified permissions.
-
-        Tuples in the list will possess the required permissions if
-        the user has a permissions matching one of the elements of
-        that tuple
-        """
-        # If there are no permissions to check, just return true
-        if not perm_list:
-            return True
-        for perm in perm_list:
-            if isinstance(perm, six.string_types):
-                # check that the permission matches
-                if not self.has_perm(perm, obj):
-                    return False
-            else:
-                # check that a permission in the tuple matches
-                if not self.has_a_matching_perm(perm, obj):
-                    return False
-        return True
-
-    class Meta(object):
-        app_label = 'openstack_auth'
diff -pruN 2.4.1-2/.pc/applied-patches 3.5.0-0ubuntu1/.pc/applied-patches
--- 2.4.1-2/.pc/applied-patches	2017-07-31 16:10:12.524699777 +0000
+++ 3.5.0-0ubuntu1/.pc/applied-patches	2017-07-31 16:10:12.712704966 +0000
@@ -1 +0,0 @@
-Add-is_authenticated-and-is_anonymous-properties.patch
diff -pruN 2.4.1-2/PKG-INFO 3.5.0-0ubuntu1/PKG-INFO
--- 2.4.1-2/PKG-INFO	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/PKG-INFO	2017-07-20 16:40:53.000000000 +0000
@@ -0,0 +1,54 @@
+Metadata-Version: 1.1
+Name: django_openstack_auth
+Version: 3.5.0
+Summary: Django authentication backend for use with OpenStack Identity
+Home-page: http://www.openstack.org/
+Author: OpenStack
+Author-email: openstack-dev@lists.openstack.org
+License: UNKNOWN
+Description: ========================
+        Team and repository tags
+        ========================
+        
+        .. image:: http://governance.openstack.org/badges/django_openstack_auth.svg
+            :target: http://governance.openstack.org/reference/tags/index.html
+        
+        .. Change things from this point on
+        
+        =====================
+        Django OpenStack Auth
+        =====================
+        
+        Django OpenStack Auth is a pluggable Django authentication backend that
+        works with Django's ``contrib.auth`` framework to authenticate a user against
+        OpenStack's Keystone Identity API.
+        
+        The current version is designed to work with the Keystone v2.0 and v3 API.
+        
+        You can `view the installation instructions`_ on Read The Docs.
+        
+        .. _view the installation instructions: http://docs.openstack.org/developer/django_openstack_auth/
+        
+        * License: Apache License, Version 2.0
+        * Documentation: http://django-openstack-auth.readthedocs.org/en/latest/
+        * Source: http://git.openstack.org/cgit/openstack/django_openstack_auth/
+        * Bugs: https://bugs.launchpad.net/django-openstack-auth
+        
+        
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: OpenStack
+Classifier: Framework :: Django
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: Information Technology
+Classifier: Intended Audience :: System Administrators
+Classifier: License :: OSI Approved :: Apache Software License
+Classifier: Operating System :: OS Independent
+Classifier: Operating System :: POSIX :: Linux
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Topic :: Internet :: WWW/HTTP
diff -pruN 2.4.1-2/README.rst 3.5.0-0ubuntu1/README.rst
--- 2.4.1-2/README.rst	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/README.rst	2017-07-20 16:39:18.000000000 +0000
@@ -1,3 +1,12 @@
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/django_openstack_auth.svg
+    :target: http://governance.openstack.org/reference/tags/index.html
+
+.. Change things from this point on
+
 =====================
 Django OpenStack Auth
 =====================
diff -pruN 2.4.1-2/requirements.txt 3.5.0-0ubuntu1/requirements.txt
--- 2.4.1-2/requirements.txt	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/requirements.txt	2017-07-20 16:39:18.000000000 +0000
@@ -1,10 +1,10 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-pbr>=1.6 # Apache-2.0
-Django<1.9,>=1.8 # BSD
-oslo.config>=3.14.0 # Apache-2.0
-oslo.policy>=1.9.0 # Apache-2.0
-python-keystoneclient!=2.1.0,>=2.0.0 # Apache-2.0
-keystoneauth1>=2.10.0 # Apache-2.0
+pbr!=2.1.0,>=2.0.0 # Apache-2.0
+Django<2.0,>=1.8 # BSD
+oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
+oslo.policy>=1.23.0 # Apache-2.0
+python-keystoneclient>=3.8.0 # Apache-2.0
+keystoneauth1>=2.21.0 # Apache-2.0
 six>=1.9.0 # MIT
diff -pruN 2.4.1-2/setup.cfg 3.5.0-0ubuntu1/setup.cfg
--- 2.4.1-2/setup.cfg	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/setup.cfg	2017-07-20 16:40:53.000000000 +0000
@@ -1,40 +1,42 @@
 [metadata]
 name = django_openstack_auth
 summary = Django authentication backend for use with OpenStack Identity
-description-file =
-    README.rst
+description-file = 
+	README.rst
 author = OpenStack
 author-email = openstack-dev@lists.openstack.org
 home-page = http://www.openstack.org/
-classifier =
-    Development Status :: 5 - Production/Stable
-    Environment :: OpenStack
-    Framework :: Django
-    Intended Audience :: Developers
-    Intended Audience :: Information Technology
-    Intended Audience :: System Administrators
-    License :: OSI Approved :: Apache Software License
-    Operating System :: OS Independent
-    Operating System :: POSIX :: Linux
-    Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
-    Programming Language :: Python :: 3
-    Programming Language :: Python :: 3.4
-    Topic :: Internet :: WWW/HTTP
+classifier = 
+	Development Status :: 5 - Production/Stable
+	Environment :: OpenStack
+	Framework :: Django
+	Intended Audience :: Developers
+	Intended Audience :: Information Technology
+	Intended Audience :: System Administrators
+	License :: OSI Approved :: Apache Software License
+	Operating System :: OS Independent
+	Operating System :: POSIX :: Linux
+	Programming Language :: Python
+	Programming Language :: Python :: 2
+	Programming Language :: Python :: 2.7
+	Programming Language :: Python :: 3
+	Programming Language :: Python :: 3.4
+	Programming Language :: Python :: 3.5
+	Topic :: Internet :: WWW/HTTP
 
 [files]
-packages =
-    openstack_auth
+packages = 
+	openstack_auth
 
 [build_sphinx]
-all_files = 1
+all-files = 1
+warning-is-error = 1
 build-dir = doc/build
 source-dir = doc/source
 
 [nosetests]
-verbosity=2
-detailed-errors=1
+verbosity = 2
+detailed-errors = 1
 
 [extract_messages]
 keywords = _ gettext ngettext l_ lazy_gettext
@@ -49,3 +51,8 @@ domain = django
 domain = django
 output_dir = openstack_auth/locale
 input_file = openstack_auth/locale/django.pot
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff -pruN 2.4.1-2/setup.py 3.5.0-0ubuntu1/setup.py
--- 2.4.1-2/setup.py	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/setup.py	2017-07-20 16:39:18.000000000 +0000
@@ -25,5 +25,5 @@ except ImportError:
     pass
 
 setuptools.setup(
-    setup_requires=['pbr>=1.8'],
+    setup_requires=['pbr>=2.0.0'],
     pbr=True)
diff -pruN 2.4.1-2/test-requirements.txt 3.5.0-0ubuntu1/test-requirements.txt
--- 2.4.1-2/test-requirements.txt	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/test-requirements.txt	2017-07-20 16:39:18.000000000 +0000
@@ -1,11 +1,11 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-hacking<0.11,>=0.10.0
-Babel>=2.3.4 # BSD
-coverage>=3.6 # Apache-2.0
+hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
+Babel!=2.4.0,>=2.3.4 # BSD
+coverage!=4.4,>=4.0 # Apache-2.0
 mock>=2.0 # BSD
-mox3>=0.7.0 # Apache-2.0
-sphinx!=1.3b1,<1.3,>=1.2.1 # BSD
-oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
+mox3!=0.19.0,>=0.7.0 # Apache-2.0
+sphinx>=1.6.2 # BSD
+openstackdocstheme>=1.11.0 # Apache-2.0
 testscenarios>=0.4 # Apache-2.0/BSD
diff -pruN 2.4.1-2/tools/tox_install.sh 3.5.0-0ubuntu1/tools/tox_install.sh
--- 2.4.1-2/tools/tox_install.sh	1970-01-01 00:00:00.000000000 +0000
+++ 3.5.0-0ubuntu1/tools/tox_install.sh	2017-07-20 16:39:18.000000000 +0000
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Client constraint file contains this client version pin that is in conflict
+# with installing the client from source. We should remove the version pin in
+# the constraints file before applying it for from-source installation.
+
+CONSTRAINTS_FILE="$1"
+shift 1
+
+set -e
+
+# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
+# published to logs.openstack.org for easy debugging.
+localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
+
+if [[ "$CONSTRAINTS_FILE" != http* ]]; then
+    CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
+fi
+# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
+curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
+
+pip install -c"$localfile" openstack-requirements
+
+# This is the main purpose of the script: Allow local installation of
+# the current repo. It is listed in constraints file and thus any
+# install will be constrained and we need to unconstrain it.
+edit-constraints "$localfile" -- "$CLIENT_NAME"
+
+pip install -c"$localfile" -U "$@"
+exit $?
diff -pruN 2.4.1-2/tox.ini 3.5.0-0ubuntu1/tox.ini
--- 2.4.1-2/tox.ini	2016-09-27 16:40:19.000000000 +0000
+++ 3.5.0-0ubuntu1/tox.ini	2017-07-20 16:39:18.000000000 +0000
@@ -1,12 +1,12 @@
 [tox]
-minversion = 1.6
+minversion = 2.0
 skipsdist = True
-envlist = py27,py27dj18,pep8,py34
+envlist = py27,py27dj18,pep8,py35
 
 [testenv]
 usedevelop = True
-install_command = pip install -U {opts} {packages}
-setenv = VIRTUAL_ENV={envdir}
+install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
+setenv = {[env-common]setenv}
          NOSE_WITH_OPENSTACK=1
          NOSE_OPENSTACK_COLOR=1
          NOSE_OPENSTACK_RED=0.05
@@ -16,8 +16,14 @@ deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
 commands = python openstack_auth/tests/run_tests.py {posargs}
 
+[env-common]
+setenv = VIRTUAL_ENV={envdir}
+         BRANCH_NAME=master
+         CLIENT_NAME=django_openstack_auth
+
 [testenv:cover]
-setenv = DJANGO_SETTINGS_MODULE=openstack_auth.tests.settings
+setenv = {[env-common]setenv}
+         DJANGO_SETTINGS_MODULE=openstack_auth.tests.settings
 commands =
     python -m coverage erase
     python -m coverage run openstack_auth/tests/run_tests.py  {posargs}
@@ -37,27 +43,22 @@ commands = pip install django>=1.9,<1.10
 commands = pip install django>=1.10,<1.11
            python openstack_auth/tests/run_tests.py {posargs}
 
+[testenv:py27dj111]
+commands = pip install django>=1.11,<2.0
+           python openstack_auth/tests/run_tests.py {posargs}
+
 [testenv:pep8]
-setenv = DJANGO_SETTINGS_MODULE=openstack_auth.tests.settings
+setenv = {[env-common]setenv}
+         DJANGO_SETTINGS_MODULE=openstack_auth.tests.settings
 commands = flake8
 
 [testenv:venv]
 commands = {posargs}
 
 [testenv:docs]
-setenv = DJANGO_SETTINGS_MODULE=openstack_auth.tests.settings
+setenv = {[env-common]setenv}
 commands = python setup.py build_sphinx
 
 [flake8]
 builtins = _
 exclude =  .venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py
-
-[hacking]
-import_exceptions = django.conf.settings,
-                    django.core.urlresolvers.reverse,
-                    django.conf.urls.include,
-                    django.conf.urls.patterns,
-                    django.conf.urls.url,
-                    django.utils.translation.pgettext_lazy,
-                    django.utils.translation.ugettext_lazy,
-                    django.utils.translation.ungettext_lazy,
