diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000000000000000000000000000000000..9e6459bfce2ece78597afa039f44e3f48b19d3e9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,26 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+# **Help us to keep this issue-tracker clean!  For questions or support, please refer to our [mailing lists](https://simplesamlphp.org/lists)**
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots or logs**
+If applicable, add screenshots and/or log files to help explain your problem.
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000000000000000000000000000000000..066b2d920a28db73b4ba3a0b35e6905eeeef5772
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
index 999acce9ba938ae8201919dff1e4b8fa8b236740..fb3a09cd190bf979a8da7b66a3eab10c71280664 100644
--- a/.gitignore
+++ b/.gitignore
@@ -169,3 +169,64 @@ crashlytics-build.properties
 ### php-cs-fixer ###
 .php_cs.cache
 cs_fixer_tmp*
+
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# Typescript v1 declaration files
+typings/
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
diff --git a/.travis.yml b/.travis.yml
index 4f67b010417a5eafb731118788272afe99ed384c..1b15ddce8aac23946a8c68bc3104851cbe144c8e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,22 +1,22 @@
 language: php
 php:
-- 5.4
 - 5.5
 - 5.6
 - 7.0
 - 7.1
+- 7.2
 - hhvm
 matrix:
   allow_failures:
   - php: hhvm
 before_script:
 - composer update
-- if [[ "$TRAVIS_PHP_VERSION" == "7.0" ]]; then composer require --dev vimeo/psalm:0.3.72; fi
+- if [[ "$TRAVIS_PHP_VERSION" == "7.0" ]]; then composer require --dev vimeo/psalm:0.3.92; fi
 - if [[ "$TRAVIS_PHP_VERSION" == "5.6" ]]; then composer require --dev php-coveralls/php-coveralls; fi
 script:
 - bin/check-syntax.sh
-- if [[ "$TRAVIS_PHP_VERSION" == "5.6" ]]; then php vendor/phpunit/phpunit/phpunit --configuration tools/phpunit; else php vendor/phpunit/phpunit/phpunit --configuration tools/phpunit --no-coverage; fi
-- if [[ "$TRAVIS_PHP_VERSION" == "7.0" ]]; then vendor/bin/psalm --find-dead-code; fi
+- if [[ "$TRAVIS_PHP_VERSION" == "5.6" ]]; then php vendor/phpunit/phpunit/phpunit; else php vendor/phpunit/phpunit/phpunit --no-coverage; fi
+- if [[ "$TRAVIS_PHP_VERSION" == "7.0" ]]; then vendor/bin/psalm; fi
 after_success:
 - if [[ "$TRAVIS_PHP_VERSION" == "5.6" ]]; then php vendor/bin/php-coveralls -v; fi
 notifications:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8a16e72314880d702ba0368ed4cfd9bb09d23881..d16eec4696968af1e18c93acdf4a5227584b1667 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,15 +1,11 @@
 # Contribution guidelines
+**SimpleSAMLphp welcomes all contributions**. It is impossible to make a product like this without the efforts of many people, so please don't be shy and share your help with us. Even the tiniest contribution can make a difference!
 
-**SimpleSAMLphp welcomes all contributions**. It is impossible to make a product like this without the efforts of many
-people, so please don't be shy and share your help with us. Even the tiniest contribution can make a difference!
-
-This guidelines briefly explain how to contribute to SimpleSAMLphp in an effective manner, making sure to keep high
-quality standards and making it easier for your contributions to make through.
+These guidelines briefly explain how to contribute to SimpleSAMLphp effectively and consistently, making sure to keep high quality standards and making it easier for you to contribute.
 
 <!-- {{TOC}} -->
 
 ## Team members
-
 Currently, the core team members are:
 
 * Jaime PĂ©rez Crespo, *main developer and release manager*, UNINETT <jaime.perez@uninett.no>
@@ -17,83 +13,64 @@ Currently, the core team members are:
 * Andreas Ă…kre Solberg, *architect and original developer*, UNINETT <andreas.solberg@uninett.no>
 * Hanne Moa, *developer*, UNINETT <hanne.moa@uninett.no>
 
-We've been lucky to have the help of many people through the years. SimpleSAMLphp wouldn't have reached so far without
-them, and we want to thank them from here. Unfortunately, they are so many it is nearly impossible to mention all of
-them. [Github can offer a good summary on who has contributed to the project](https://github.com/simplesamlphp/simplesamlphp/graphs/contributors?from=2007-09-09&to=2015-09-06&type=c).
-Big thanks to you all!
+We have been lucky enough to have so many people help us through the years. SimpleSAMLphp wouldn't have reached so far without them. We want to thank them from here, but unfortunately they are so many it is nearly impossible to mention all of them. [Here is a Github page that summarizes everyone's contributions](https://github.com/simplesamlphp/simplesamlphp/graphs/contributors?from=2007-09-09&to=2015-09-06&type=c).
 
-## First things first
+***Big thanks to you all!***
 
-Before embarking yourself in a contribution, please make sure you are familiar with the way SimpleSAMLphp is written,
-the way it works, and what is required or not.
+## First things first
+Before embarking yourself in a contribution, please make sure you are familiar with the way SimpleSAMLphp is written, the way it works, and what is required or not.
 
-* Make sure to read [the documentation](https://simplesamlphp.org/docs/stable/). If you use the search engine in the
-website, please verify that you are reading the latest stable version. If you want to develop something, check [the
-development branch of the documentation](https://simplesamlphp.org/docs/development/).
+* Make sure to read [the documentation](https://simplesamlphp.org/docs/stable/). If you use the search engine in the website, please verify that you are reading the latest stable version. If you want to make a change, check [the development branch of the documentation](https://simplesamlphp.org/docs/development/).
 * If you have a question about **using SimpleSAMLphp**, please use [the mailing list](http://groups.google.com/group/simplesamlphp).
 * If you have a question about **developing SimpleSAMLphp**, please ask in the [development mailing list](http://groups.google.com/group/simplesamlphp-dev).
-* If you think you have discovered a bug, please check the [issue tracker](https://github.com/simplesamlphp/simplesamlphp/issues)
-and the [pull requests](https://github.com/simplesamlphp/simplesamlphp/pulls) to verify it hasn't been reported before.
+* If you think you have discovered a bug, please check the [issue tracker](https://github.com/simplesamlphp/simplesamlphp/issues) and the [pull requests](https://github.com/simplesamlphp/simplesamlphp/pulls) to verify it hasn't been reported already.
 
 ## Contributing code
-
-New features are always welcome provided they will be useful to someone apart from yourself. Please take a look at the
-[list of issues](https://github.com/simplesamlphp/simplesamlphp/issues) to see what people is demanding. Our
-[roadmap](https://simplesamlphp.org/releaseplan) might also be a good place to start if you don't know exactly what
-you can contribute with.
-
-When contributing your code, please make sure to:
-
-* Respect the coding standards. We try to comply with PHP's [PSR-2](http://www.php-fig.org/psr/psr-2/). Pay special
-attention to:
-   * Lines should not be longer than 80 characters.
-   * Use **4 spaces** instead of tabs.
-   * Keep the keywords in **lowercase**, including `true`, `false` and `null`.
-   * Make sure your classes work with *autoloading*.
-   * Never include a trailing `?>` in your files.
-   * The first line of every file must be `<?php`.
-   * Use namespaces if you are adding new files.
-* Do not include many changes in every commit. Commits should be focused and address one single problem or feature. By
-having **multiple, small commits** instead of few large ones, it is easier to track what you are doing, revert changes
-in case of an error and help you out if needed.
+New features are always welcome, provided they will be useful to someone apart from yourself. Please take a look at the [list of issues](https://github.com/simplesamlphp/simplesamlphp/issues) to see what people are asking for. Our [roadmap](https://simplesamlphp.org/releaseplan) might also be a good place to start if you do not know exactly how you can contribute.
+
+When submitting a pull request, please make sure to account for:
+
+### Coding standards
+* Respect the coding standards. We try to comply with PHP's [PSR-2](http://www.php-fig.org/psr/psr-2/). Pay special attention to the rules below:
+    * Lines should not be longer than 80 characters.
+    * Use **4 spaces** instead of tabs.
+    * Keep the keywords in **lowercase**, including `true`, `false` and `null`.
+    * Make sure your classes work with *autoloading*.
+    * Never include a trailing `?>` in your files.
+    * The first line of every file must be `<?php`.
+    * Use namespaces if you are adding new files.
+* Do not include too many changes in every commit. Commits should be focused and address one single problem or feature. By having **multiple, small commits** instead of fewer large ones, it is easier to track what you are doing, revert changes in case of an error and help you make changes if needed.
 * Try to write clean **commit messages**, largely based on the [seven rules](http://chris.beams.io/posts/git-commit/):
-   * Write a **short** subject line, followed by a blank line and a longer explanation.
-   * Prefix the subject line with the component(s) changed, e.g. "docs: Update foo", or "SAML: Don't log bar twice",
-     or "tests: Add tests for quux".
-   * Explain **what and why** in the commit message, not just _how_. Things obvious now might become quite confusing
-     when rediscovered years later.
-* **Be explicit**. Add comments. Use strict comparison operators like `===` and check for specific values when testing
-conditions.
-* **Keep things simple**. Avoid big functions, long nested loops or `if` statements.
-* Include complete **phpdoc** documentation for every property and method you add. If you change a method or property,
-make sure to update the existing *phpdoc* accordingly. Do not forget to document all parameters, returned values and
-exceptions thrown.
-* Try to keep **backwards-compatibility**. Code that breaks current configurations and installations is difficult to
-deploy, and therefore we try to avoid it.
-* Add **unit tests** to verify that your code not only works but also keeps working over time. When adding tests, keep
-the same directory structure used for regular classes. Try to cover **all your code** with tests. The bigger the test
-coverage, the more reliable and better our library is. Read our [guidelines](TESTING.md) to learn more about tests.
-* Add proper **documentation** explaining your how to use your new feature or how your code changes things.
-* Submit your code as a **pull request** in github, from a branch with a descriptive name in your own fork of the
-repository. Add a meaningful, short title, and explain in detail what you did and why in the description of the *PR*.
-Add instructions on how to test your code. We appreciate branch names like `feature/whatever-new-feature` for new
-features and `bug/something-not-working` for bug fixes, but this is not carved in stone.
-
-Sometimes it can take a long time until we are able to process your pull requests. Don't get discouraged, we'll
-eventually reach up to you. And remember that following this guidelines you are making it easier for us to analyze your
-request so the process will be smoother and faster. We really appreciate you helping us out, not only with your code,
-but also by following this guidelines.
+    * Write a **short** subject line, followed by a blank line and a longer explanation.
+    * Prefix the subject line with the component(s) changed, e.g. "docs: Update foo", or "SAML: Don't log bar twice", or "tests: Add tests for quux".
+    * Explain **what and why** in the commit message, not just _how_. Things that seem obvious now might become quite confusing when rediscovered years later.
 
-## Reporting bugs
+### Comments, comparisons, and simplicity
+* Add comments that describe why/how your code works.
+* Include complete **phpdoc** documentation for every property and method you add. If you change a method or property, make sure to update the existing *phpdoc* accordingly. Do not forget to document all parameters, returned values and exceptions thrown.
+* Use strict comparison operators like `===` and check for specific values when writing tests.
+* Avoid big functions, long nested loops or `if` statements.
+* Try to keep **backwards-compatibility**. Code that breaks current configurations and installations is difficult to deploy, and therefore we try to avoid that as much as possible.
+
+### Unit tests
+Add **unit tests** to verify that your code not only works but also keeps working over time. When adding tests, keep the same directory structure used for regular classes. Try to cover **all your code** with tests. The bigger the test coverage, the more reliable and better our library is. Read our [guidelines](TESTING.md) to learn more about tests.
+
+### Documentation
+In order to keep this library user-friendly, we ask that you add proper **documentation** explaining how to use your new feature or how your code changes things.
 
-Before reporting a bug, please make sure it is indeed a bug. Check [the documentation](https://simplesamlphp.org/docs/stable/)
-to verify what the intended behaviour is. Review the [list of issues](https://github.com/simplesamlphp/simplesamlphp/issues)
-and the [pull requests](https://github.com/simplesamlphp/simplesamlphp/pulls) to see if someone has already reported the
-same issue.
+### Pull requests
+Please follow all instructions below:
 
-Pull requests are definitely more appreciated than plain issue reports, as they are easier and faster to address, but
-please, do not hesitate to open an issue if you don't have coding skills or just can't find the bug. It's better to have
-just an issue report than nothing!
+1. Submit your code as a **pull request** in github from a branch with a descriptive name in your own fork of the repository.
+2. Add a meaningful, short title, and explain in detail what you did and why in the description of the *PR*.
+3. Add instructions on how to test your code. We appreciate branch names like `feature/whatever-new-feature` for new features and `bug/something-not-working` for bug fixes, but this is not required.
+
+Sometimes it can take a long time before we are able to process your pull requests. Do not get discouraged, we will eventually reach your change. Remember that by following these guidelines, you are making it easier for us to analyze your request so the process will be smooth and fast. We really appreciate you helping us out, not only with your code, but also by following these guidelines.
+
+## Reporting bugs
+Before reporting a bug, please make sure it is indeed a bug. Check [the documentation](https://simplesamlphp.org/docs/stable/) to verify what the intended behaviour is. Review the [issue tracker](https://github.com/simplesamlphp/simplesamlphp/issues) and the [pull requests](https://github.com/simplesamlphp/simplesamlphp/pulls) to see if someone has already reported the same issue.
+
+If you are able, a pull request is much more appreciated than just a new issue. If not, please do not hesitate to open one. It is better to have just an issue report than nothing!
 
 You can help us diagnose and fix bugs by asking and providing answers to the following questions:
 
@@ -102,18 +79,12 @@ You can help us diagnose and fix bugs by asking and providing answers to the fol
 * Are the steps to reproduce the bug clear? If not, can you describe how you might reproduce it?
 * What tags should the bug have?
 * How critical is this bug? Does it impact a large amount of users?
-* Is this a security issue? If so, how severe is it? How can an attacker exploit it? Read more about security issues in
-the next section.
+* Is this a security issue? If so, how severe is it? How can an attacker exploit it? Read more about security issues in the next section.
 
 ## Reporting vulnerabilities
+In case you find a vulnerability in SimpleSAMLphp, or you want to confirm a possible security issue in the software, please get in touch with us through [UNINETT's CERT team](https://www.uninett.no/cert). Please use our PGP public key to encrypt any possibly sensitive data that you may need to submit. We will get back to you as soon as possible according to our working hours in Central European Time.
 
-In case you find a vulnerability in SimpleSAMLphp, or you want to confirm a possible security issue in the software, please
-get in touch with us through [UNINETT's CERT team](https://www.uninett.no/cert). Please use our PGP public key to encrypt
-any possible sensitive data that you may need to submit. We will get back to you as soon as possible according to our
-working hours in Central European Time.
-
-When reporting a security issue, please add as much information as possible to help us identify, confirm, replicate and
-fix the problem. In particular, remember to include the following information in your report:
+When reporting a security issue, please add as much information as possible to help us identify, confirm, replicate and fix the problem. In particular, remember to include the following information in your report:
 
 * The version or versions of SimpleSAMLphp affected.
 * An exact version that can be used to replicate the issue.
@@ -125,42 +96,23 @@ fix the problem. In particular, remember to include the following information in
 * Context on how you discovered the issue.
 * Your own name and whether you want to be credited for the discovery or not.
 
-Please **DO NOT** report security incidents related to systems that use SimpleSAMLphp, where this software is not the
-cause of the incident. Issues related to the use (or misuse) of infrastructure, misconfiguration of the software,
-malfunction of a particular system or user-related errors should not be reported either. If you are using SimpleSAMLphp
-to authenticate or login to services, but you don't know what SimpleSAMLphp is or you are not sure about the nature of
-the issue, please contact the organization running the service for you.
+Please **DO NOT** report security incidents related to systems that use SimpleSAMLphp, where this software is not the cause of the incident. Issues related to the use (or misuse) of infrastructure, misconfiguration of the software, malfunction of a particular system or user-related errors should not be reported either. If you are using SimpleSAMLphp to authenticate or login to services, but you don't know what SimpleSAMLphp is or you are not sure about the nature of the issue, please contact the organization running the service for you.
 
-Finally, be reasonable. We'll do our best to resolve the issue according to our principles of security and transparency.
-Every confirmed vulnerability will be published and resolved in a timely manner. All we ask in return is that you
-contact us privately first in order to avoid any potential damage to those using the software.
+Finally, be reasonable. We'll do our best to resolve the issue according to our principles of security and transparency. Every confirmed vulnerability will be published and resolved in a timely manner. All we ask in return is that you contact us privately first in order to avoid any potential damage to those using the software.
 
 You can find the list of security advisories we have published [here](https://simplesamlphp.org/security).
 
 ## Translations
+SimpleSAMLphp is translated to many languages, though it needs constant updates from translators, as well as new translations to other languages. For the moment, translations can be contributed as **pull requests**. We are looking at better ways to translate the software that would make your life easier, so stay tuned! You can also join the [translators mailing list](http://groups.google.com/group/simplesamlphp-translation) to keep up to date on the latest news.
 
-SimpleSAMLphp is translated to many languages, though it needs constant updates from translators, as well as new
-translations to other languages. For the moment, translations can be contributed as **pull requests**. We are looking
-at better ways to translate the software that would make your life easier, so stay tuned! You can also join the
-[translators mailing list](http://groups.google.com/group/simplesamlphp-translation) to keep up to date on the
-latest news.
-
-Before starting a new translation, decide what style you want to use, whether you want to address the user in a polite
-manner or not, etc. Be coherent and keep that style through all your translations. If there is already a translation and
-you want to complete it, make sure to keep the same style used by your fellow translators.
+Before starting a new translation, decide what style you want to use, whether you want to address the user in a polite manner or not, etc. Be coherent and keep that style through all your translations. If there is already a translation and you want to complete it, make sure to keep the same style used by your fellow translators.
 
 ## Documentation
+Did you find a typo in the documentation? Does something make no sense? Did we use poor english? Tell us!
 
-Did you find a typo in the documentation? Does something make no sense? Did we use very poor english? Tell us!
-
-Documentation is included in our own repository in *markdown* format. You can submit pull requests with fixes. If you
-encounter some feature that's not documented, or the documentation does not reflect the real behaviour of the library,
-please do not hesitate to open an issue.
+Documentation is included in our own repository in *markdown* format. You can submit pull requests with fixes. If you encounter some feature that is not documented, or the documentation does not reflect the real behaviour of the library, please do not hesitate to open an issue.
 
 Good documentation is key to make things easier for our users!
 
 ## Community
-
-You don't feel capable of contributing with your code, but are using SimpleSAMLphp and can share your knowledge and
-experience? Please, do so! Join our [users mailing list](http://groups.google.com/group/simplesamlphp) and help other
-users when you can. Your experience might be valuable for many!
+You do not feel capable of contributing with your code, but are using SimpleSAMLphp and can share your knowledge and experience? Please, do so! Join our [users mailing list](http://groups.google.com/group/simplesamlphp) and help other users when you can. Your experience might be valuable for many!
diff --git a/attributemap/addurnprefix.php b/attributemap/addurnprefix.php
index 9d9877c0002173f18a53d51aaf50a2e7da9dd87c..c8623954f9284a5b784e78cea3e050bd19895218 100644
--- a/attributemap/addurnprefix.php
+++ b/attributemap/addurnprefix.php
@@ -1,6 +1,6 @@
 <?php
 
-$attributemap = array(
+$attributemap = [
     'sn'                         => 'urn:mace:dir:attribute-def:sn',
     'telephoneNumber'            => 'urn:mace:dir:attribute-def:telephoneNumber',
     'facsimileTelephoneNumber'   => 'urn:mace:dir:attribute-def:facsimileTelephoneNumber',
@@ -17,4 +17,4 @@ $attributemap = array(
     'eduPersonEntitlement'       => 'urn:mace:dir:attribute-def:eduPersonEntitlement',
     'eduPersonOrgDN'             => 'urn:mace:dir:attribute-def:eduPersonOrgDN',
     'eduPersonOrgUnitDN'         => 'urn:mace:dir:attribute-def:eduPersonOrgUnitDN',
-);
+];
diff --git a/attributemap/deprecatedSchacNS.php b/attributemap/deprecatedSchacNS.php
index 5f90e03ab7a95cf2720c3706674cb80a7d71840e..4a613348e15ed5f84f236a755c76e8d1c26421be 100644
--- a/attributemap/deprecatedSchacNS.php
+++ b/attributemap/deprecatedSchacNS.php
@@ -11,7 +11,7 @@ if (!defined('SCHAC_NEW_NS')) {
     define('SCHAC_NEW_NS', 'urn:schac:attribute-def:');
 }
 
-$attributemap = array(
+$attributemap = [
     SCHAC_NEW_NS.'schacCountryOfCitizenship' => SCHAC_OLD_NS.'schacCountryOfCitizenship',
     SCHAC_NEW_NS.'schacCountryOfResidence' => SCHAC_OLD_NS.'schacCountryOfResidence',
     SCHAC_NEW_NS.'schacDateOfBirth' => SCHAC_OLD_NS.'schacDateOfBirth',
@@ -32,4 +32,4 @@ $attributemap = array(
     SCHAC_NEW_NS.'schacUserPresenceID' => SCHAC_OLD_NS.'schacUserPresenceID',
     SCHAC_NEW_NS.'schacUserPrivateAttribute' => SCHAC_OLD_NS.'schacUserPrivateAttribute',
     SCHAC_NEW_NS.'schacUserStatus' => SCHAC_OLD_NS.'schacUserStatus',
-);
+];
diff --git a/attributemap/facebook2name.php b/attributemap/facebook2name.php
index 5867ea7edfc87e56c1338bcb99b06f4bcc98f035..e567a69f20572cdbeaa1328cab5316cab1cea20d 100644
--- a/attributemap/facebook2name.php
+++ b/attributemap/facebook2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
 
     // Generated Facebook Attributes
     'facebook_user'        => 'eduPersonPrincipalName', // username OR uid @ facebook.com
@@ -15,4 +15,4 @@ $attributemap = array(
     'facebook.profile_url' => 'labeledURI',
     'facebook.locale'      => 'preferredLanguage',
     'facebook.about_me'    => 'description',
-);
+];
diff --git a/attributemap/feide-oid.php b/attributemap/feide-oid.php
index dc94cd7a4ea344c4cac679d3219c5d8454af861d..45a1a28a4050205489689511b4b975648bd82ecf 100644
--- a/attributemap/feide-oid.php
+++ b/attributemap/feide-oid.php
@@ -1,6 +1,6 @@
 <?php
 
-$attributemap = array(
+$attributemap = [
     'mobile'      => 'urn:mace:dir:attribute-def:mobile',
     'displayName' => 'urn:oid:2.16.840.1.113730.3.1.241',
-);
+];
diff --git a/attributemap/linkedin2name.php b/attributemap/linkedin2name.php
index 97231dd4b37f63d09c697e8f41e9da769f5542ed..9b654682d8652a0a41ab630b4ea2bb1ef8d36e68 100644
--- a/attributemap/linkedin2name.php
+++ b/attributemap/linkedin2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
 
     // See http://developer.linkedin.com/docs/DOC-1061 for LinkedIn Profile fields.
     // NB: JSON response requires the conversion of field names from hyphened to camelCase.
@@ -15,4 +15,4 @@ $attributemap = array(
     'linkedin.id'         => 'uid', // alpha + mixed case user id
     'linkedin.headline'   => 'title',
     'linkedin.summary'    => 'description',
-);
+];
diff --git a/attributemap/myspace2name.php b/attributemap/myspace2name.php
deleted file mode 100644
index 6111f61d051d84713edc412f2fba8e2183091b00..0000000000000000000000000000000000000000
--- a/attributemap/myspace2name.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-$attributemap = array(
-
-    // See http://developerwiki.myspace.com/index.php?title=People_API for attributes
-
-    // Generated MySpace Attributes
-    'myspace_user'            => 'eduPersonPrincipalName', // username OR uid @ myspace.com
-    'myspace_targetedID'      => 'eduPersonTargetedID', // http://myspace.com!uid
-    'myspace_username'        => 'uid', // myspace username (maybe numeric uid)
-
-    // Attributes Returned by MySpace
-    'myspace.name.givenName'  => 'givenName',
-    'myspace.name.familyName' => 'sn',
-    'myspace.displayName'     => 'displayName',
-    'myspace.profileUrl'      => 'labeledURI',
-);
diff --git a/attributemap/name2claim.php b/attributemap/name2claim.php
index 482bb6d8bd3606e8fa5d2f2675c999bce4c98878..7b03b104539ad251a30519989c0b920ba77b1763 100644
--- a/attributemap/name2claim.php
+++ b/attributemap/name2claim.php
@@ -1,5 +1,5 @@
 <?php // Maps AD LDAP to Claims from http://msdn.microsoft.com/en-us/library/hh159803.aspx
-$attributemap = array(
+$attributemap = [
     'c'               => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country',
     'givenName'       => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
     'mail'            => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
@@ -10,4 +10,4 @@ $attributemap = array(
     'st'              => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince',
     'streetaddress'   => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress',
     'telephonenumber' => 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/otherphone',
-);
+];
diff --git a/attributemap/name2oid.php b/attributemap/name2oid.php
index 1a5e10ca27e6746149668f4cfd91687d5ea759db..c99f0e0b371e493a5dd6f865fccc8aef93feef85 100644
--- a/attributemap/name2oid.php
+++ b/attributemap/name2oid.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'aRecord'                       => 'urn:oid:0.9.2342.19200300.100.1.26',
     'aliasedEntryName'              => 'urn:oid:2.5.4.1',
     'aliasedObjectName'             => 'urn:oid:2.5.4.1',
@@ -189,4 +189,4 @@ $attributemap = array(
     'userid'                        => 'urn:oid:0.9.2342.19200300.100.1.1',
     'x121Address'                   => 'urn:oid:2.5.4.24',
     'x500UniqueIdentifier'          => 'urn:oid:2.5.4.45',
-);
+];
diff --git a/attributemap/name2urn.php b/attributemap/name2urn.php
index 477f6c665cc71ff35acd21ca42ded680dac0cd73..03190f3090a673497a4c2d5f09665c0175657b93 100644
--- a/attributemap/name2urn.php
+++ b/attributemap/name2urn.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'aRecord'                       => 'urn:mace:dir:attribute-def:aRecord',
     'aliasedEntryName'              => 'urn:mace:dir:attribute-def:aliasedEntryName',
     'aliasedObjectName'             => 'urn:mace:dir:attribute-def:aliasedObjectName',
@@ -112,6 +112,7 @@ $attributemap = array(
     'owner'                         => 'urn:mace:dir:attribute-def:owner',
     'pager'                         => 'urn:mace:dir:attribute-def:pager',
     'pagerTelephoneNumber'          => 'urn:mace:dir:attribute-def:pagerTelephoneNumber',
+    'pairwise-id'                   => 'urn:oasis:names:tc:SAML:attribute:pairwise-id',
     'personalSignature'             => 'urn:mace:dir:attribute-def:personalSignature',
     'personalTitle'                 => 'urn:mace:dir:attribute-def:personalTitle',
     'photo'                         => 'urn:mace:dir:attribute-def:photo',
@@ -163,6 +164,7 @@ $attributemap = array(
     'stateOrProvinceName'           => 'urn:mace:dir:attribute-def:stateOrProvinceName',
     'street'                        => 'urn:mace:dir:attribute-def:street',
     'streetAddress'                 => 'urn:mace:dir:attribute-def:streetAddress',
+    'subject-id'                    => 'urn:oasis:names:tc:SAML:attribute:subject-id',
     'subtreeMaximumQuality'         => 'urn:mace:dir:attribute-def:subtreeMaximumQuality',
     'subtreeMinimumQuality'         => 'urn:mace:dir:attribute-def:subtreeMinimumQuality',
     'supportedAlgorithms'           => 'urn:mace:dir:attribute-def:supportedAlgorithms',
@@ -184,4 +186,4 @@ $attributemap = array(
     'userid'                        => 'urn:mace:dir:attribute-def:userid',
     'x121Address'                   => 'urn:mace:dir:attribute-def:x121Address',
     'x500UniqueIdentifier'          => 'urn:mace:dir:attribute-def:x500UniqueIdentifier',
-);
+];
diff --git a/attributemap/newSchacNS.php b/attributemap/newSchacNS.php
index 8b3d2a75685f392c9c73c56431b2e31c947d6c78..16e67394eecf567af9ffb263c21e02e5964efad7 100644
--- a/attributemap/newSchacNS.php
+++ b/attributemap/newSchacNS.php
@@ -11,7 +11,7 @@ if (!defined('SCHAC_NEW_NS')) {
     define('SCHAC_NEW_NS', 'urn:schac:attribute-def:');
 }
 
-$attributemap = array(
+$attributemap = [
     SCHAC_OLD_NS.'schacCountryOfCitizenship' => SCHAC_NEW_NS.'schacCountryOfCitizenship',
     SCHAC_OLD_NS.'schacCountryOfResidence' => SCHAC_NEW_NS.'schacCountryOfResidence',
     SCHAC_OLD_NS.'schacDateOfBirth' => SCHAC_NEW_NS.'schacDateOfBirth',
@@ -32,4 +32,4 @@ $attributemap = array(
     SCHAC_OLD_NS.'schacUserPresenceID' => SCHAC_NEW_NS.'schacUserPresenceID',
     SCHAC_OLD_NS.'schacUserPrivateAttribute' => SCHAC_NEW_NS.'schacUserPrivateAttribute',
     SCHAC_OLD_NS.'schacUserStatus' => SCHAC_NEW_NS.'schacUserStatus',
-);
+];
diff --git a/attributemap/oid-feide.php b/attributemap/oid-feide.php
index e20b7a88500056734152c19768e61b2df7ea477a..c6bc2148d289c0d3ed9e442c02872025301a397a 100644
--- a/attributemap/oid-feide.php
+++ b/attributemap/oid-feide.php
@@ -1,6 +1,6 @@
 <?php
 
-$attributemap = array(
+$attributemap = [
     'urn:oid:0.9.2342.19200300.100.1.41' => 'mobile',
     'urn:oid:1.3.6.1.4.1.5923.1.1.1.6'   => 'eduPersonPrincipalName',
     'urn:oid:0.9.2342.19200300.100.1.3'  => 'mail',
@@ -9,4 +9,4 @@ $attributemap = array(
     'urn:oid:2.5.4.4'                    => 'sn',
     'urn:oid:2.5.4.42'                   => 'givenName',
     'urn:oid:2.16.756.1.2.5.1.1.1'       => 'eduPerson',
-);
+];
diff --git a/attributemap/oid2name.php b/attributemap/oid2name.php
index e1ce887d6e61ef1e8509d58f05707da251f830b7..f36dd1cab3b173df320c424f78b05a8e5a455a49 100644
--- a/attributemap/oid2name.php
+++ b/attributemap/oid2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'urn:oid:0.9.2342.19200300.100.1.1'  => 'uid',
     'urn:oid:0.9.2342.19200300.100.1.10' => 'manager',
     'urn:oid:0.9.2342.19200300.100.1.11' => 'documentIdentifier',
@@ -167,4 +167,4 @@ $attributemap = array(
     'urn:oid:2.5.4.7'                    => 'l',
     'urn:oid:2.5.4.8'                    => 'st',
     'urn:oid:2.5.4.9'                    => 'street',
-);
+];
diff --git a/attributemap/oid2urn.php b/attributemap/oid2urn.php
index cefb99ce762a69f0bdb6f69cd1f0ee38275d782d..a2b0a78e32e63655ca946a2d85a05d86d1e29a26 100644
--- a/attributemap/oid2urn.php
+++ b/attributemap/oid2urn.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'urn:oid:0.9.2342.19200300.100.1.1'  => 'urn:mace:dir:attribute-def:uid',
     'urn:oid:0.9.2342.19200300.100.1.10' => 'urn:mace:dir:attribute-def:manager',
     'urn:oid:0.9.2342.19200300.100.1.11' => 'urn:mace:dir:attribute-def:documentIdentifier',
@@ -164,4 +164,4 @@ $attributemap = array(
     'urn:oid:2.5.4.7'                    => 'urn:mace:dir:attribute-def:l',
     'urn:oid:2.5.4.8'                    => 'urn:mace:dir:attribute-def:st',
     'urn:oid:2.5.4.9'                    => 'urn:mace:dir:attribute-def:street',
-);
+];
diff --git a/attributemap/openid2name.php b/attributemap/openid2name.php
index 624074b02cf4ffb8f13e1bf8919f767156f30736..1cef43ef2cef2b7e0ebbed04cfe47da204e42bf6 100644
--- a/attributemap/openid2name.php
+++ b/attributemap/openid2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     // Simple Registration + AX Schema
     'http://axschema.org/namePerson/friendly'     => 'displayName', // Alias/Username -> displayName
     'openid.sreg.nickname'                        => 'displayName',
@@ -30,4 +30,4 @@ $attributemap = array(
     'http://axschema.org/contact/phone/fax'       => 'facsimileTelephoneNumber', // Phone (fax)
 
     // Further attributes can be found at http://www.axschema.org/types/
-);
+];
diff --git a/attributemap/removeurnprefix.php b/attributemap/removeurnprefix.php
index 6a7c920d59fb9761fd2b72b75382057799b1d3b9..f9ac92f5edb3115251c14f571f5d373905a308fe 100644
--- a/attributemap/removeurnprefix.php
+++ b/attributemap/removeurnprefix.php
@@ -1,6 +1,6 @@
 <?php
 
-$attributemap = array(
+$attributemap = [
     'urn:mace:dir:attribute-def:sn'                         => 'sn',
     'urn:mace:dir:attribute-def:telephoneNumber'            => 'telephoneNumber',
     'urn:mace:dir:attribute-def:facsimileTelephoneNumber'   => 'facsimileTelephoneNumber',
@@ -17,4 +17,4 @@ $attributemap = array(
     'urn:mace:dir:attribute-def:eduPersonEntitlement'       => 'eduPersonEntitlement',
     'urn:mace:dir:attribute-def:eduPersonOrgDN'             => 'eduPersonOrgDN',
     'urn:mace:dir:attribute-def:eduPersonOrgUnitDN'         => 'eduPersonOrgUnitDN',
-);
+];
diff --git a/attributemap/test.php b/attributemap/test.php
index a89ad869f7ea0606e95bded4133360245ad97faf..8ddd84b6980ea06d58548c81cdd4710066693238 100644
--- a/attributemap/test.php
+++ b/attributemap/test.php
@@ -1,5 +1,5 @@
 <?php
 
-$attributemap = array(
+$attributemap = [
     'mobile' => 'urn:mace:dir:attribute-def:mobile'
-);
+];
diff --git a/attributemap/twitter2name.php b/attributemap/twitter2name.php
index 27c9e755a1b478625846a20c6000ea173ae7ee7d..00f65317a26ad6e11a10b1d6c11c4d025180dfb5 100644
--- a/attributemap/twitter2name.php
+++ b/attributemap/twitter2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
 
     // Generated Twitter Attributes
     'twitter_screen_n_realm' => 'eduPersonPrincipalName', // screen_name@twitter.com
@@ -11,4 +11,4 @@ $attributemap = array(
     'twitter.url'            => 'labeledURI',
     'twitter.lang'           => 'preferredLanguage',
     'twitter.description'    => 'description',
-);
+];
diff --git a/attributemap/urn2name.php b/attributemap/urn2name.php
index 66cd8589abe2a59ea7937acafef86f7dc8e3bd4f..8cf8bffd7d408414cc3ccc719fe57ccda866303d 100644
--- a/attributemap/urn2name.php
+++ b/attributemap/urn2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'urn:mace:dir:attribute-def:aRecord'                          => 'aRecord',
     'urn:mace:dir:attribute-def:aliasedEntryName'                 => 'aliasedEntryName',
     'urn:mace:dir:attribute-def:aliasedObjectName'                => 'aliasedObjectName',
@@ -184,4 +184,6 @@ $attributemap = array(
     'urn:mace:terena.org:attribute-def:schacUserPresenceID'       => 'schacUserPresenceID',
     'urn:mace:terena.org:attribute-def:schacUserPrivateAttribute' => 'schacUserPrivateAttribute',
     'urn:mace:terena.org:attribute-def:schacUserStatus'           => 'schacUserStatus',
-);
+    'urn:oasis:names:tc:SAML:attribute:pairwise-id'               => 'pairwise-id',
+    'urn:oasis:names:tc:SAML:attribute:subject-id'                => 'subject-id',
+];
diff --git a/attributemap/urn2oid.php b/attributemap/urn2oid.php
index fda382b93ab6de4c9e55c3b37b6cd2ddd5886339..4abf467844205819687bee888882586f4e3e8cec 100644
--- a/attributemap/urn2oid.php
+++ b/attributemap/urn2oid.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
     'urn:mace:dir:attribute-def:aRecord'                          => 'urn:oid:0.9.2342.19200300.100.1.26',
     'urn:mace:dir:attribute-def:aliasedEntryName'                 => 'urn:oid:2.5.4.1',
     'urn:mace:dir:attribute-def:aliasedObjectName'                => 'urn:oid:2.5.4.1',
@@ -185,4 +185,4 @@ $attributemap = array(
     'urn:mace:terena.org:attribute-def:schacUserPresenceID'       => 'urn:oid:1.3.6.1.4.1.25178.1.2.12',
     'urn:mace:terena.org:attribute-def:schacUserPrivateAttribute' => 'urn:oid:1.3.6.1.4.1.25178.1.2.18',
     'urn:mace:terena.org:attribute-def:schacUserStatus'           => 'urn:oid:1.3.6.1.4.1.25178.1.2.19',
-);
+];
diff --git a/attributemap/windowslive2name.php b/attributemap/windowslive2name.php
index 1c5496c90dd63e3c9006c38ff13644cda5b37402..3c3ffa1f00c91b488597a062c96731e7082149b5 100644
--- a/attributemap/windowslive2name.php
+++ b/attributemap/windowslive2name.php
@@ -1,5 +1,5 @@
 <?php
-$attributemap = array(
+$attributemap = [
 
     // Generated Windows Live ID Attributes
     'windowslive_user'       => 'eduPersonPrincipalName', // uid @ windowslive.com
@@ -19,4 +19,4 @@ $attributemap = array(
     'windowslive.mail' => 'mail',
     'windowslive.preferredLanguage' => 'preferredLanguage',
 
-);
+];
diff --git a/bin/build-release.sh b/bin/build-release.sh
index 464d652af2743d8c9afe32e0aca585be46e05c2e..d123533ee0081b23aa84251938c9ee43bb477c6c 100755
--- a/bin/build-release.sh
+++ b/bin/build-release.sh
@@ -46,12 +46,19 @@ if [ -f "$TARGET/composer.json" ]; then
     php "$TARGET/composer.phar" install --no-dev --prefer-dist -o -d "$TARGET"
 fi
 
-mkdir -p "$TARGET/config" "$TARGET/metadata" "$TARGET/cert" "$TARGET/log"
+# Use npm only on newer versions that have a package.json
+if [ -f "$TARGET/package.json" ]; then
+    npm install
+    npm audit fix
+fi
+
+mkdir -p "$TARGET/config" "$TARGET/metadata" "$TARGET/cert" "$TARGET/log" "$TARGET/data"
 cp -rv "$TARGET/config-templates/"* "$TARGET/config/"
 cp -rv "$TARGET/metadata-templates/"* "$TARGET/metadata/"
 rm -rf "$TARGET/.git"
 rm "$TARGET/.coveralls.yml"
 rm "$TARGET/.travis.yml"
+rm "$TARGET/.php_cs.dist"
 rm "$TARGET/psalm.xml"
 rm "$TARGET"/{,modules}/.gitignore
 rm "$TARGET/.gitattributes"
diff --git a/bin/importPdoMetadata.php b/bin/importPdoMetadata.php
index 79e4b504a2326208616469f7e1f9cc7bac31c531..abf4fdd4842f5a6ec3c6641d82664a01e330e769 100755
--- a/bin/importPdoMetadata.php
+++ b/bin/importPdoMetadata.php
@@ -3,18 +3,18 @@
 $baseDir = dirname(dirname(__FILE__));
 
 require_once $baseDir.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.'_autoload.php';
-require_once SimpleSAML\Utils\Config::getConfigDir().DIRECTORY_SEPARATOR.'config.php';
+require_once \SimpleSAML\Utils\Config::getConfigDir().DIRECTORY_SEPARATOR.'config.php';
 
 # Iterate through configured metadata sources and ensure
 # that a PDO source exists.
 foreach ($config['metadata.sources'] as $s) {
     # If pdo is configured, create the new handler and add in the metadata sets.
     if ($s['type'] === "pdo") {
-        $mdshp = new SimpleSAML_Metadata_MetaDataStorageHandlerPdo($s);
+        $mdshp = new \SimpleSAML\Metadata\MetaDataStorageHandlerPdo($s);
         $mdshp->initDatabase();
 
         foreach (glob("metadata/*.php") as $filename) {
-            $metadata = array();
+            $metadata = [];
             require_once $filename;
             $set = basename($filename, ".php");
             echo "importing set '$set'...".PHP_EOL;
diff --git a/bin/initMDSPdo.php b/bin/initMDSPdo.php
index b68a5b22f6ccc2bfe311a8f9dc0fd67528eeb850..403b4d2de00ce3ac8fdd9267b31cecf77b8abea1 100755
--- a/bin/initMDSPdo.php
+++ b/bin/initMDSPdo.php
@@ -6,7 +6,7 @@ $baseDir = dirname(dirname(__FILE__));
 
 // Add library autoloader and configuration
 require_once $baseDir.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.'_autoload.php';
-require_once SimpleSAML\Utils\Config::getConfigDir().DIRECTORY_SEPARATOR.'config.php';
+require_once \SimpleSAML\Utils\Config::getConfigDir().DIRECTORY_SEPARATOR.'config.php';
 
 echo "Initializing Metadata Database...".PHP_EOL;
 
@@ -15,7 +15,7 @@ echo "Initializing Metadata Database...".PHP_EOL;
 foreach ($config['metadata.sources'] as $source) {
     # If pdo is configured, create the new handler and initialize the DB.
     if ($source['type'] === "pdo") {
-        $metadataStorageHandler = new SimpleSAML_Metadata_MetaDataStorageHandlerPdo($source);
+        $metadataStorageHandler = new \SimpleSAML\Metadata\MetaDataStorageHandlerPdo($source);
         $result = $metadataStorageHandler->initDatabase();
 
         if ($result === false) {
diff --git a/bin/memcacheSync.php b/bin/memcacheSync.php
index 64605a952aa94ff89d4e9a57e4ba36df16149cd9..0dfdc31f4741b3b56961c9ea27e7e569ac3952a8 100755
--- a/bin/memcacheSync.php
+++ b/bin/memcacheSync.php
@@ -3,19 +3,19 @@
 
 
 // Check that the memcache library is enabled
-if(!class_exists('Memcache') && !class_exists('Memcached')) {
-	echo("Error: the memcached (or memcache) PHP extension appears to be unavailable.\n");
-	echo("\n");
-	echo("This is most likely because PHP doesn't load it for the command line\n");
-	echo("version. You probably need to enable it somehow.\n");
-	echo("\n");
-	if(is_executable('/usr/sbin/phpenmod')) {
-		echo("It is possible that running one of the following commands as root will fix it:\n");
-		echo(" phpenmod -s cli memcached\n");
-		echo(" phpenmod -s cli memcache\n");
-	}
-
-	exit(1);
+if (!class_exists('Memcache') && !class_exists('Memcached')) {
+    echo "Error: the memcached (or memcache) PHP extension appears to be unavailable.\n";
+    echo "\n";
+    echo "This is most likely because PHP doesn't load it for the command line\n";
+    echo "version. You probably need to enable it somehow.\n";
+    echo "\n";
+    if (is_executable('/usr/sbin/phpenmod')) {
+        echo "It is possible that running one of the following commands as root will fix it:\n";
+        echo " phpenmod -s cli memcached\n";
+        echo " phpenmod -s cli memcache\n";
+    }
+
+    exit(1);
 }
 
 // This is the base directory of the SimpleSAMLphp installation
@@ -26,42 +26,41 @@ require_once($baseDir.'/lib/_autoload.php');
 
 // Initialize the configuration
 $configdir = SimpleSAML\Utils\Config::getConfigDir();
-SimpleSAML_Configuration::setConfigDir($configdir);
+\SimpleSAML\Configuration::setConfigDir($configdir);
 
 // Things we should warn the user about
 $warnServerDown = 0;
 $warnBigSlab = 0;
 
 // We use the stats interface to determine which servers exists
-$stats = SimpleSAML_Memcache::getRawStats();
+$stats = \SimpleSAML\Memcache::getRawStats();
 
-$keys = array();
+$keys = [];
 foreach ($stats as $group) {
     foreach ($group as $server => $state) {
-
         if ($state === false) {
-            echo("WARNING: Server ".$server." is down.\n");
+            echo "WARNING: Server ".$server." is down.\n";
             $warnServerDown++;
             continue;
         }
 
         $items = $state['curr_items'];
-        echo("Server ".$server." has ".$items." items.\n");
+        echo "Server ".$server." has ".$items." items.\n";
         $serverKeys = getServerKeys($server);
         $keys = array_merge($keys, $serverKeys);
     }
 }
 
-echo("Total number of keys: ".count($keys)."\n");
+echo "Total number of keys: ".count($keys)."\n";
 $keys = array_unique($keys);
-echo("Total number of unique keys: ".count($keys)."\n");
+echo "Total number of unique keys: ".count($keys)."\n";
 
-echo("Starting synchronization.\n");
+echo "Starting synchronization.\n" ;
 
 $skipped = 0;
 $sync = 0;
 foreach ($keys as $key) {
-    $res = SimpleSAML_Memcache::get($key);
+    $res = \SimpleSAML\Memcache::get($key);
     if ($res === null) {
         $skipped += 1;
     } else {
@@ -70,20 +69,20 @@ foreach ($keys as $key) {
 }
 
 
-echo("Synchronization done.\n");
-echo($sync." keys in sync.\n");
+echo "Synchronization done.\n";
+echo $sync." keys in sync.\n";
 if ($skipped > 0) {
-    echo($skipped." keys skipped.\n");
-    echo("Keys are skipped because they are either expired, or are of a type unknown\n");
-    echo("to SimpleSAMLphp.\n");
+    echo $skipped." keys skipped.\n";
+    echo "Keys are skipped because they are either expired, or are of a type unknown\n";
+    echo "to SimpleSAMLphp.\n";
 }
 
 if ($warnServerDown > 0) {
-    echo("WARNING: ".$warnServerDown." server(s) down. Not all servers are synchronized.\n");
+    echo "WARNING: ".$warnServerDown." server(s) down. Not all servers are synchronized.\n";
 }
 
 if ($warnBigSlab > 0) {
-    echo("WARNING: ".$warnBigSlab." slab(s) may have contained more keys than we were told about.\n");
+    echo "WARNING: ".$warnBigSlab." slab(s) may have contained more keys than we were told about.\n";
 }
 
 /**
@@ -99,17 +98,17 @@ function getServerKeys($server)
     $host = $server[0];
     $port = (int) $server[1];
 
-    echo("Connecting to: ".$host.":".$port."\n");
+    echo "Connecting to: ".$host.":".$port."\n";
     $socket = fsockopen($host, $port);
-    echo("Connected. Finding keys.\n");
+    echo "Connected. Finding keys.\n";
 
     if (fwrite($socket, "stats slabs\r\n") === false) {
-        echo("Error requesting slab dump from server.\n");
+        echo "Error requesting slab dump from server.\n";
         exit(1);
     }
 
     // Read list of slabs
-    $slabs = array();
+    $slabs = [];
     while (($line = fgets($socket)) !== false) {
         $line = rtrim($line);
         if ($line === 'END') {
@@ -125,11 +124,10 @@ function getServerKeys($server)
     }
 
     // Dump keys in slabs
-    $keys = array();
+    $keys = [];
     foreach ($slabs as $slab) {
-
         if (fwrite($socket, "stats cachedump ".$slab." 1000000\r\n") === false) {
-            echo("Error requesting cache dump from server.\n");
+            echo "Error requesting cache dump from server.\n";
             exit(1);
         }
 
@@ -149,17 +147,17 @@ function getServerKeys($server)
             if (preg_match('/^ITEM (.*) \[\d+ b; \d+ s\]/', $line, $matches)) {
                 $keys[] = $matches[1];
             } else {
-                echo("Unknown result from cache dump: ".$line."\n");
+                echo "Unknown result from cache dump: ".$line."\n";
             }
         }
         if ($resultSize > 1900000 || count($keys) >= 1000000) {
-            echo("WARNING: Slab ".$slab." on server ".$host.":".$port.
-                " may have contained more keys than we were told about.\n");
+            echo "WARNING: Slab ".$slab." on server ".$host.":".$port.
+                " may have contained more keys than we were told about.\n";
             $GLOBALS['warnBigSlab'] += 1;
         }
     }
 
-    echo("Found ".count($keys)." key(s).\n");
+    echo "Found ".count($keys)." key(s).\n";
     fclose($socket);
 
     return $keys;
diff --git a/composer.json b/composer.json
index 3a06bf0dad4889394b7f5b6b2282f5cf149b2159..372e453a6431f7953c8a5e6b7d1c2c5902aba9e0 100644
--- a/composer.json
+++ b/composer.json
@@ -4,7 +4,7 @@
     "type": "project",
     "keywords": [ "saml2", "shibboleth","oauth","ws-federation","sp","idp" ],
     "homepage": "http://simplesamlphp.org",
-    "license": "LGPL-2.1",
+    "license": "LGPL-2.1-or-later",
     "authors": [
         {
             "name": "Andreas Ă…kre Solberg",
@@ -26,7 +26,7 @@
         "files": ["lib/_autoload_modules.php"]
     },
     "require": {
-        "php": ">=5.4",
+        "php": ">=5.5",
         "ext-SPL": "*",
         "ext-zlib": "*",
         "ext-pcre": "*",
@@ -36,15 +36,14 @@
         "ext-hash": "*",
         "ext-json": "*",
         "ext-mbstring": "*",
-        "simplesamlphp/saml2": "~3.1",
-        "robrichards/xmlseclibs": "~3.0",
+        "simplesamlphp/saml2": "^3.2",
+        "robrichards/xmlseclibs": "^3.0",
         "whitehat101/apr1-md5": "~1.0",
-        "twig/twig": "~1.0",
-        "gettext/gettext": "^3.5",
-        "jaimeperez/twig-configurable-i18n": "^1.2"
+        "twig/twig": "~1.0 || ~2.0",
+        "gettext/gettext": "^4.6",
+        "jaimeperez/twig-configurable-i18n": "^2.0"
     },
     "require-dev": {
-        "ext-pdo_sqlite": "*",
         "phpunit/phpunit": "~4.8.35",
         "mikey179/vfsStream": "~1.6",
         "friendsofphp/php-cs-fixer": "^2.2"
diff --git a/composer.lock b/composer.lock
index cb059121c63298c6a7723032466f8ecc4f588f92..4054e22f02d7fd76fa0b105dce86da4c02a64a0a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1,34 +1,36 @@
 {
     "_readme": [
         "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "a7ac3f6a5e037f467876e690ee591e59",
+    "content-hash": "b9c34fc504ecc863bc6fe8fecd0f838e",
     "packages": [
         {
             "name": "gettext/gettext",
-            "version": "v3.6.1",
+            "version": "v4.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/oscarotero/Gettext.git",
-                "reference": "cd3be64443551e3a693117c4bccbe53e36282456"
+                "reference": "854ff5f5aaf92d2af7080ba8fc15718b27b5c89a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/cd3be64443551e3a693117c4bccbe53e36282456",
-                "reference": "cd3be64443551e3a693117c4bccbe53e36282456",
+                "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/854ff5f5aaf92d2af7080ba8fc15718b27b5c89a",
+                "reference": "854ff5f5aaf92d2af7080ba8fc15718b27b5c89a",
                 "shasum": ""
             },
             "require": {
-                "gettext/languages": "2.*",
-                "php": ">=5.3.0"
+                "gettext/languages": "^2.3",
+                "php": ">=5.4.0"
             },
             "require-dev": {
                 "illuminate/view": "*",
+                "phpunit/phpunit": "^4.8|^5.7|^6.5",
+                "squizlabs/php_codesniffer": "^3.0",
                 "symfony/yaml": "~2",
                 "twig/extensions": "*",
-                "twig/twig": "*"
+                "twig/twig": "^1.31|^2.0"
             },
             "suggest": {
                 "illuminate/view": "Is necessary if you want to use the Blade extractor",
@@ -64,20 +66,20 @@
                 "po",
                 "translation"
             ],
-            "time": "2016-08-01T18:09:57+00:00"
+            "time": "2018-08-27T15:40:19+00:00"
         },
         {
             "name": "gettext/languages",
-            "version": "2.3.0",
+            "version": "2.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git",
-                "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7"
+                "reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7",
-                "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7",
+                "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/1b74377bd0c4cd87e8d72b948f5d8867e23505a5",
+                "reference": "1b74377bd0c4cd87e8d72b948f5d8867e23505a5",
                 "shasum": ""
             },
             "require": {
@@ -125,20 +127,20 @@
                 "translations",
                 "unicode"
             ],
-            "time": "2017-03-23T17:02:28+00:00"
+            "time": "2018-06-21T15:58:36+00:00"
         },
         {
             "name": "jaimeperez/twig-configurable-i18n",
-            "version": "v1.2",
+            "version": "v2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/jaimeperez/twig-configurable-i18n.git",
-                "reference": "75d4926fd102c9e62219ad7f94a6136d2f2ccd93"
+                "reference": "4ccf150ba9f28d2e31d0622ecc9b81cdc6a2638b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/jaimeperez/twig-configurable-i18n/zipball/75d4926fd102c9e62219ad7f94a6136d2f2ccd93",
-                "reference": "75d4926fd102c9e62219ad7f94a6136d2f2ccd93",
+                "url": "https://api.github.com/repos/jaimeperez/twig-configurable-i18n/zipball/4ccf150ba9f28d2e31d0622ecc9b81cdc6a2638b",
+                "reference": "4ccf150ba9f28d2e31d0622ecc9b81cdc6a2638b",
                 "shasum": ""
             },
             "require": {
@@ -169,7 +171,7 @@
                 "translation",
                 "twig"
             ],
-            "time": "2016-10-03T12:34:15+00:00"
+            "time": "2018-10-10T09:12:46+00:00"
         },
         {
             "name": "psr/log",
@@ -220,24 +222,22 @@
         },
         {
             "name": "robrichards/xmlseclibs",
-            "version": "3.0.1",
+            "version": "3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/robrichards/xmlseclibs.git",
-                "reference": "d937712f70f93a584eb0299ccd87dc6374003781"
+                "reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/d937712f70f93a584eb0299ccd87dc6374003781",
-                "reference": "d937712f70f93a584eb0299ccd87dc6374003781",
+                "url": "https://api.github.com/repos/robrichards/xmlseclibs/zipball/1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
+                "reference": "1f4de0c0d121922aafd8c62c2a9f5e528830cf38",
                 "shasum": ""
             },
             "require": {
+                "ext-openssl": "*",
                 "php": ">= 5.4"
             },
-            "suggest": {
-                "ext-openssl": "OpenSSL extension"
-            },
             "type": "library",
             "autoload": {
                 "psr-4": {
@@ -256,20 +256,20 @@
                 "xml",
                 "xmldsig"
             ],
-            "time": "2017-08-31T09:27:07+00:00"
+            "time": "2018-09-27T13:24:13+00:00"
         },
         {
             "name": "simplesamlphp/saml2",
-            "version": "v3.1.0",
+            "version": "v3.2.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplesamlphp/saml2.git",
-                "reference": "1b93d1fa49abaf99ffa78aef5358224e3a6b29b2"
+                "reference": "b3a040ec186f4a3749228b8c13642c5295fc451b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/1b93d1fa49abaf99ffa78aef5358224e3a6b29b2",
-                "reference": "1b93d1fa49abaf99ffa78aef5358224e3a6b29b2",
+                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/b3a040ec186f4a3749228b8c13642c5295fc451b",
+                "reference": "b3a040ec186f4a3749228b8c13642c5295fc451b",
                 "shasum": ""
             },
             "require": {
@@ -283,7 +283,7 @@
             "require-dev": {
                 "mockery/mockery": "~0.9",
                 "phpmd/phpmd": "~1.5",
-                "phpunit/phpunit": "~3.7",
+                "phpunit/phpunit": "~4",
                 "sebastian/phpcpd": "~1.4",
                 "sensiolabs/security-checker": "~1.1",
                 "squizlabs/php_codesniffer": "~1.4"
@@ -291,7 +291,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "v3.0.x-dev"
+                    "dev-master": "v3.1.x-dev"
                 }
             },
             "autoload": {
@@ -304,7 +304,7 @@
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "LGPL-2.1"
+                "LGPL-2.1-or-later"
             ],
             "authors": [
                 {
@@ -313,28 +313,145 @@
                 }
             ],
             "description": "SAML2 PHP library from SimpleSAMLphp",
-            "time": "2017-12-06T15:57:23+00:00"
+            "time": "2018-09-27T14:09:06+00:00"
+        },
+        {
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
+                "reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-ctype": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                },
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8",
+                "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.9-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
         },
         {
             "name": "twig/extensions",
-            "version": "v1.5.1",
+            "version": "v1.5.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig-extensions.git",
-                "reference": "d188c76168b853481cc75879ea045bf93d718e9c"
+                "reference": "2c1a86526d0044065220d1b51ac08348bea5ca82"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/d188c76168b853481cc75879ea045bf93d718e9c",
-                "reference": "d188c76168b853481cc75879ea045bf93d718e9c",
+                "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/2c1a86526d0044065220d1b51ac08348bea5ca82",
+                "reference": "2c1a86526d0044065220d1b51ac08348bea5ca82",
                 "shasum": ""
             },
             "require": {
-                "twig/twig": "~1.27|~2.0"
+                "twig/twig": "^1.27|^2.0"
             },
             "require-dev": {
-                "symfony/phpunit-bridge": "~3.3@dev",
-                "symfony/translation": "~2.3|~3.0"
+                "symfony/phpunit-bridge": "^3.4",
+                "symfony/translation": "^2.7|^3.4"
             },
             "suggest": {
                 "symfony/translation": "Allow the time_diff output to be translated"
@@ -364,39 +481,40 @@
                 }
             ],
             "description": "Common additional features for Twig that do not directly belong in core",
-            "homepage": "http://twig.sensiolabs.org/doc/extensions/index.html",
             "keywords": [
                 "i18n",
                 "text"
             ],
-            "time": "2017-06-08T18:19:53+00:00"
+            "time": "2018-05-22T13:26:07+00:00"
         },
         {
             "name": "twig/twig",
-            "version": "v1.34.4",
+            "version": "v2.5.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/twigphp/Twig.git",
-                "reference": "f878bab48edb66ad9c6ed626bf817f60c6c096ee"
+                "reference": "6a5f676b77a90823c2d4eaf76137b771adf31323"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/twigphp/Twig/zipball/f878bab48edb66ad9c6ed626bf817f60c6c096ee",
-                "reference": "f878bab48edb66ad9c6ed626bf817f60c6c096ee",
+                "url": "https://api.github.com/repos/twigphp/Twig/zipball/6a5f676b77a90823c2d4eaf76137b771adf31323",
+                "reference": "6a5f676b77a90823c2d4eaf76137b771adf31323",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": "^7.0",
+                "symfony/polyfill-ctype": "^1.8",
+                "symfony/polyfill-mbstring": "~1.0"
             },
             "require-dev": {
                 "psr/container": "^1.0",
-                "symfony/debug": "~2.7",
-                "symfony/phpunit-bridge": "~3.3@dev"
+                "symfony/debug": "^2.7",
+                "symfony/phpunit-bridge": "^3.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.34-dev"
+                    "dev-master": "2.5-dev"
                 }
             },
             "autoload": {
@@ -425,16 +543,16 @@
                 },
                 {
                     "name": "Twig Team",
-                    "homepage": "http://twig.sensiolabs.org/contributors",
+                    "homepage": "https://twig.symfony.com/contributors",
                     "role": "Contributors"
                 }
             ],
             "description": "Twig, the flexible, fast, and secure template language for PHP",
-            "homepage": "http://twig.sensiolabs.org",
+            "homepage": "https://twig.symfony.com",
             "keywords": [
                 "templating"
             ],
-            "time": "2017-07-04T13:19:31+00:00"
+            "time": "2018-07-13T07:18:09+00:00"
         },
         {
             "name": "whitehat101/apr1-md5",
@@ -544,37 +662,81 @@
             ],
             "time": "2016-08-30T16:08:34+00:00"
         },
+        {
+            "name": "composer/xdebug-handler",
+            "version": "1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/xdebug-handler.git",
+                "reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/b8e9745fb9b06ea6664d8872c4505fb16df4611c",
+                "reference": "b8e9745fb9b06ea6664d8872c4505fb16df4611c",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0",
+                "psr/log": "^1.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Composer\\XdebugHandler\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "John Stevenson",
+                    "email": "john-stevenson@blueyonder.co.uk"
+                }
+            ],
+            "description": "Restarts a process without xdebug.",
+            "keywords": [
+                "Xdebug",
+                "performance"
+            ],
+            "time": "2018-08-31T19:07:57+00:00"
+        },
         {
             "name": "doctrine/annotations",
-            "version": "v1.2.7",
+            "version": "v1.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/annotations.git",
-                "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535"
+                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
-                "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97",
+                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97",
                 "shasum": ""
             },
             "require": {
                 "doctrine/lexer": "1.*",
-                "php": ">=5.3.2"
+                "php": "^5.6 || ^7.0"
             },
             "require-dev": {
                 "doctrine/cache": "1.*",
-                "phpunit/phpunit": "4.*"
+                "phpunit/phpunit": "^5.7"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.3.x-dev"
+                    "dev-master": "1.4.x-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "Doctrine\\Common\\Annotations\\": "lib/"
+                "psr-4": {
+                    "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -610,7 +772,7 @@
                 "docblock",
                 "parser"
             ],
-            "time": "2015-08-31T12:32:49+00:00"
+            "time": "2017-02-24T16:22:25+00:00"
         },
         {
             "name": "doctrine/instantiator",
@@ -722,50 +884,56 @@
         },
         {
             "name": "friendsofphp/php-cs-fixer",
-            "version": "v2.2.8",
+            "version": "v2.13.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
-                "reference": "aca23e791784eade7b377d578d6dfc6fcf1398d2"
+                "reference": "7136aa4e0c5f912e8af82383775460d906168a10"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/aca23e791784eade7b377d578d6dfc6fcf1398d2",
-                "reference": "aca23e791784eade7b377d578d6dfc6fcf1398d2",
+                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/7136aa4e0c5f912e8af82383775460d906168a10",
+                "reference": "7136aa4e0c5f912e8af82383775460d906168a10",
                 "shasum": ""
             },
             "require": {
                 "composer/semver": "^1.4",
+                "composer/xdebug-handler": "^1.2",
                 "doctrine/annotations": "^1.2",
                 "ext-json": "*",
                 "ext-tokenizer": "*",
-                "gecko-packages/gecko-php-unit": "^2.0",
-                "php": "^5.3.6 || >=7.0 <7.3",
-                "sebastian/diff": "^1.4",
-                "symfony/console": "^2.4 || ^3.0",
-                "symfony/event-dispatcher": "^2.1 || ^3.0",
-                "symfony/filesystem": "^2.4 || ^3.0",
-                "symfony/finder": "^2.2 || ^3.0",
-                "symfony/options-resolver": "^2.6 || ^3.0",
-                "symfony/polyfill-php54": "^1.0",
-                "symfony/polyfill-php55": "^1.3",
+                "php": "^5.6 || >=7.0 <7.3",
+                "php-cs-fixer/diff": "^1.3",
+                "symfony/console": "^3.2 || ^4.0",
+                "symfony/event-dispatcher": "^3.0 || ^4.0",
+                "symfony/filesystem": "^3.0 || ^4.0",
+                "symfony/finder": "^3.0 || ^4.0",
+                "symfony/options-resolver": "^3.0 || ^4.0",
                 "symfony/polyfill-php70": "^1.0",
                 "symfony/polyfill-php72": "^1.4",
-                "symfony/process": "^2.3 || ^3.0",
-                "symfony/stopwatch": "^2.5 || ^3.0"
+                "symfony/process": "^3.0 || ^4.0",
+                "symfony/stopwatch": "^3.0 || ^4.0"
             },
             "conflict": {
-                "hhvm": "<3.18"
+                "hhvm": "*"
             },
             "require-dev": {
-                "johnkary/phpunit-speedtrap": "^1.0.1",
+                "johnkary/phpunit-speedtrap": "^1.1 || ^2.0 || ^3.0",
                 "justinrainbow/json-schema": "^5.0",
-                "phpunit/phpunit": "^4.8.35 || ^5.4.3",
-                "satooshi/php-coveralls": "^1.0",
-                "symfony/phpunit-bridge": "^3.2.2"
+                "keradus/cli-executor": "^1.1",
+                "mikey179/vfsstream": "^1.6",
+                "php-coveralls/php-coveralls": "^2.1",
+                "php-cs-fixer/accessible-object": "^1.0",
+                "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.0.1",
+                "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.0.1",
+                "phpunit/phpunit": "^5.7.27 || ^6.5.8 || ^7.1",
+                "phpunitgoodpractices/traits": "^1.5.1",
+                "symfony/phpunit-bridge": "^4.0"
             },
             "suggest": {
                 "ext-mbstring": "For handling non-UTF8 characters in cache signature.",
+                "php-cs-fixer/phpunit-constraint-isidenticalstring": "For IsIdenticalString constraint.",
+                "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "For XmlMatchesXsd constraint.",
                 "symfony/polyfill-mbstring": "When enabling `ext-mbstring` is not possible."
             },
             "bin": [
@@ -774,7 +942,7 @@
             "type": "application",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2-dev"
+                    "dev-master": "2.13-dev"
                 }
             },
             "autoload": {
@@ -783,9 +951,14 @@
                 },
                 "classmap": [
                     "tests/Test/AbstractFixerTestCase.php",
+                    "tests/Test/AbstractIntegrationCaseFactory.php",
                     "tests/Test/AbstractIntegrationTestCase.php",
+                    "tests/Test/Assert/AssertTokensTrait.php",
                     "tests/Test/IntegrationCase.php",
-                    "tests/Test/IntegrationCaseFactory.php"
+                    "tests/Test/IntegrationCaseFactory.php",
+                    "tests/Test/IntegrationCaseFactoryInterface.php",
+                    "tests/Test/InternalIntegrationCaseFactory.php",
+                    "tests/TestCase.php"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -803,93 +976,7 @@
                 }
             ],
             "description": "A tool to automatically fix PHP code style",
-            "time": "2017-09-29T15:07:49+00:00"
-        },
-        {
-            "name": "gecko-packages/gecko-php-unit",
-            "version": "v2.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/GeckoPackages/GeckoPHPUnit.git",
-                "reference": "ab525fac9a9ffea219687f261b02008b18ebf2d1"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/GeckoPackages/GeckoPHPUnit/zipball/ab525fac9a9ffea219687f261b02008b18ebf2d1",
-                "reference": "ab525fac9a9ffea219687f261b02008b18ebf2d1",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.3.6 || ^7.0"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^4.8.35 || ^5.4.3"
-            },
-            "suggest": {
-                "ext-dom": "When testing with xml.",
-                "ext-libxml": "When testing with xml.",
-                "phpunit/phpunit": "This is an extension for it so make sure you have it some way."
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "GeckoPackages\\PHPUnit\\": "src/PHPUnit"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "description": "Additional PHPUnit asserts and constraints.",
-            "homepage": "https://github.com/GeckoPackages",
-            "keywords": [
-                "extension",
-                "filesystem",
-                "phpunit"
-            ],
-            "time": "2017-08-23T07:39:54+00:00"
-        },
-        {
-            "name": "ircmaxell/password-compat",
-            "version": "v1.0.4",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/ircmaxell/password_compat.git",
-                "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c",
-                "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c",
-                "shasum": ""
-            },
-            "require-dev": {
-                "phpunit/phpunit": "4.*"
-            },
-            "type": "library",
-            "autoload": {
-                "files": [
-                    "lib/password.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Anthony Ferrara",
-                    "email": "ircmaxell@php.net",
-                    "homepage": "http://blog.ircmaxell.com"
-                }
-            ],
-            "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash",
-            "homepage": "https://github.com/ircmaxell/password_compat",
-            "keywords": [
-                "hashing",
-                "password"
-            ],
-            "time": "2014-11-20T16:49:30+00:00"
+            "time": "2018-08-23T13:15:44+00:00"
         },
         {
             "name": "mikey179/vfsStream",
@@ -939,33 +1026,29 @@
         },
         {
             "name": "paragonie/random_compat",
-            "version": "v2.0.11",
+            "version": "v9.99.99",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8"
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8",
-                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
+                "reference": "84b4dfb120c6f9b4ff7b3685f9b8f1aa365a0c95",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.2.0"
+                "php": "^7"
             },
             "require-dev": {
-                "phpunit/phpunit": "4.*|5.*"
+                "phpunit/phpunit": "4.*|5.*",
+                "vimeo/psalm": "^1"
             },
             "suggest": {
                 "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
             },
             "type": "library",
-            "autoload": {
-                "files": [
-                    "lib/random.php"
-                ]
-            },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
@@ -980,23 +1063,75 @@
             "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
             "keywords": [
                 "csprng",
+                "polyfill",
                 "pseudorandom",
                 "random"
             ],
-            "time": "2017-09-27T21:40:39+00:00"
+            "time": "2018-07-02T15:55:56+00:00"
+        },
+        {
+            "name": "php-cs-fixer/diff",
+            "version": "v1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHP-CS-Fixer/diff.git",
+                "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/78bb099e9c16361126c86ce82ec4405ebab8e756",
+                "reference": "78bb099e9c16361126c86ce82ec4405ebab8e756",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^5.7.23 || ^6.4.3",
+                "symfony/process": "^3.3"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "src/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Kore Nordmann",
+                    "email": "mail@kore-nordmann.de"
+                },
+                {
+                    "name": "Sebastian Bergmann",
+                    "email": "sebastian@phpunit.de"
+                },
+                {
+                    "name": "SpacePossum"
+                }
+            ],
+            "description": "sebastian/diff v2 backport support for PHP5.6",
+            "homepage": "https://github.com/PHP-CS-Fixer",
+            "keywords": [
+                "diff"
+            ],
+            "time": "2018-02-15T16:58:55+00:00"
         },
         {
             "name": "phpdocumentor/reflection-common",
-            "version": "1.0",
+            "version": "1.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionCommon.git",
-                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
+                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
-                "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
+                "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6",
                 "shasum": ""
             },
             "require": {
@@ -1037,33 +1172,39 @@
                 "reflection",
                 "static analysis"
             ],
-            "time": "2015-12-27T11:43:31+00:00"
+            "time": "2017-09-11T18:02:19+00:00"
         },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "3.2.0",
+            "version": "4.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "46f7e8bb075036c92695b15a1ddb6971c751e585"
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/46f7e8bb075036c92695b15a1ddb6971c751e585",
-                "reference": "46f7e8bb075036c92695b15a1ddb6971c751e585",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08",
+                "reference": "94fd0001232e47129dd3504189fa1c7225010d08",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.5",
-                "phpdocumentor/reflection-common": "^1.0@dev",
+                "php": "^7.0",
+                "phpdocumentor/reflection-common": "^1.0.0",
                 "phpdocumentor/type-resolver": "^0.4.0",
                 "webmozart/assert": "^1.0"
             },
             "require-dev": {
-                "mockery/mockery": "^0.9.4",
-                "phpunit/phpunit": "^4.4"
+                "doctrine/instantiator": "~1.0.5",
+                "mockery/mockery": "^1.0",
+                "phpunit/phpunit": "^6.4"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "4.x-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
                     "phpDocumentor\\Reflection\\": [
@@ -1082,7 +1223,7 @@
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2017-07-15T11:38:20+00:00"
+            "time": "2017-11-30T07:14:17+00:00"
         },
         {
             "name": "phpdocumentor/type-resolver",
@@ -1133,33 +1274,33 @@
         },
         {
             "name": "phpspec/prophecy",
-            "version": "v1.7.0",
+            "version": "1.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "93d39f1f7f9326d746203c7c056f300f7f126073"
+                "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073",
-                "reference": "93d39f1f7f9326d746203c7c056f300f7f126073",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
+                "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
                 "php": "^5.3|^7.0",
-                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
-                "sebastian/comparator": "^1.1|^2.0",
+                "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
+                "sebastian/comparator": "^1.1|^2.0|^3.0",
                 "sebastian/recursion-context": "^1.0|^2.0|^3.0"
             },
             "require-dev": {
                 "phpspec/phpspec": "^2.5|^3.2",
-                "phpunit/phpunit": "^4.8 || ^5.6.5"
+                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.6.x-dev"
+                    "dev-master": "1.8.x-dev"
                 }
             },
             "autoload": {
@@ -1192,7 +1333,7 @@
                 "spy",
                 "stub"
             ],
-            "time": "2017-03-02T20:05:34+00:00"
+            "time": "2018-08-05T17:53:17+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
@@ -1258,16 +1399,16 @@
         },
         {
             "name": "phpunit/php-file-iterator",
-            "version": "1.4.2",
+            "version": "1.4.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
-                "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
+                "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
                 "shasum": ""
             },
             "require": {
@@ -1301,7 +1442,7 @@
                 "filesystem",
                 "iterator"
             ],
-            "time": "2016-10-03T07:40:28+00:00"
+            "time": "2017-11-27T13:52:08+00:00"
         },
         {
             "name": "phpunit/php-text-template",
@@ -1395,16 +1536,16 @@
         },
         {
             "name": "phpunit/php-token-stream",
-            "version": "1.4.11",
+            "version": "1.4.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-token-stream.git",
-                "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7"
+                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7",
-                "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16",
+                "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16",
                 "shasum": ""
             },
             "require": {
@@ -1440,7 +1581,7 @@
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2017-02-27T10:12:30+00:00"
+            "time": "2017-12-04T08:55:13+00:00"
         },
         {
             "name": "phpunit/phpunit",
@@ -1944,44 +2085,45 @@
         },
         {
             "name": "symfony/console",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "116bc56e45a8e5572e51eb43ab58c769a352366c"
+                "reference": "3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/116bc56e45a8e5572e51eb43ab58c769a352366c",
-                "reference": "116bc56e45a8e5572e51eb43ab58c769a352366c",
+                "url": "https://api.github.com/repos/symfony/console/zipball/3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b",
+                "reference": "3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b",
                 "shasum": ""
             },
             "require": {
                 "php": "^5.5.9|>=7.0.8",
-                "symfony/debug": "~2.8|~3.0",
+                "symfony/debug": "~2.8|~3.0|~4.0",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "conflict": {
-                "symfony/dependency-injection": "<3.3"
+                "symfony/dependency-injection": "<3.4",
+                "symfony/process": "<3.3"
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/config": "~3.3",
-                "symfony/dependency-injection": "~3.3",
-                "symfony/event-dispatcher": "~2.8|~3.0",
-                "symfony/filesystem": "~2.8|~3.0",
-                "symfony/process": "~2.8|~3.0"
+                "symfony/config": "~3.3|~4.0",
+                "symfony/dependency-injection": "~3.4|~4.0",
+                "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
+                "symfony/lock": "~3.4|~4.0",
+                "symfony/process": "~3.3|~4.0"
             },
             "suggest": {
-                "psr/log": "For using the console logger",
+                "psr/log-implementation": "For using the console logger",
                 "symfony/event-dispatcher": "",
-                "symfony/filesystem": "",
+                "symfony/lock": "",
                 "symfony/process": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2008,20 +2150,20 @@
             ],
             "description": "Symfony Console Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-10-02T16:33:53+00:00"
         },
         {
             "name": "symfony/debug",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/debug.git",
-                "reference": "eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd"
+                "reference": "0a612e9dfbd2ccce03eb174365f31ecdca930ff6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd",
-                "reference": "eb95d9ce8f18dcc1b3dfff00cb624c402be78ffd",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/0a612e9dfbd2ccce03eb174365f31ecdca930ff6",
+                "reference": "0a612e9dfbd2ccce03eb174365f31ecdca930ff6",
                 "shasum": ""
             },
             "require": {
@@ -2032,12 +2174,12 @@
                 "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
             },
             "require-dev": {
-                "symfony/http-kernel": "~2.8|~3.0"
+                "symfony/http-kernel": "~2.8|~3.0|~4.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2064,20 +2206,20 @@
             ],
             "description": "Symfony Debug Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-10-02T16:33:53+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "d7ba037e4b8221956ab1e221c73c9e27e05dd423"
+                "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d7ba037e4b8221956ab1e221c73c9e27e05dd423",
-                "reference": "d7ba037e4b8221956ab1e221c73c9e27e05dd423",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb",
+                "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb",
                 "shasum": ""
             },
             "require": {
@@ -2088,10 +2230,10 @@
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/config": "~2.8|~3.0",
-                "symfony/dependency-injection": "~3.3",
-                "symfony/expression-language": "~2.8|~3.0",
-                "symfony/stopwatch": "~2.8|~3.0"
+                "symfony/config": "~2.8|~3.0|~4.0",
+                "symfony/dependency-injection": "~3.3|~4.0",
+                "symfony/expression-language": "~2.8|~3.0|~4.0",
+                "symfony/stopwatch": "~2.8|~3.0|~4.0"
             },
             "suggest": {
                 "symfony/dependency-injection": "",
@@ -2100,7 +2242,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2127,29 +2269,30 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-07-26T09:06:28+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1"
+                "reference": "d69930fc337d767607267d57c20a7403d0a822a4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/90bc45abf02ae6b7deb43895c1052cb0038506f1",
-                "reference": "90bc45abf02ae6b7deb43895c1052cb0038506f1",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/d69930fc337d767607267d57c20a7403d0a822a4",
+                "reference": "d69930fc337d767607267d57c20a7403d0a822a4",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5.9|>=7.0.8"
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/polyfill-ctype": "~1.8"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2176,20 +2319,20 @@
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-03T13:33:10+00:00"
+            "time": "2018-10-02T12:28:39+00:00"
         },
         {
             "name": "symfony/finder",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "773e19a491d97926f236942484cb541560ce862d"
+                "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/773e19a491d97926f236942484cb541560ce862d",
-                "reference": "773e19a491d97926f236942484cb541560ce862d",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/54ba444dddc5bd5708a34bd095ea67c6eb54644d",
+                "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d",
                 "shasum": ""
             },
             "require": {
@@ -2198,7 +2341,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2225,20 +2368,20 @@
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-10-03T08:46:40+00:00"
         },
         {
             "name": "symfony/options-resolver",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/options-resolver.git",
-                "reference": "ee4e22978fe885b54ee5da8c7964f0a5301abfb6"
+                "reference": "1cf7d8e704a9cc4164c92e430f2dfa3e6983661d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/options-resolver/zipball/ee4e22978fe885b54ee5da8c7964f0a5301abfb6",
-                "reference": "ee4e22978fe885b54ee5da8c7964f0a5301abfb6",
+                "url": "https://api.github.com/repos/symfony/options-resolver/zipball/1cf7d8e704a9cc4164c92e430f2dfa3e6983661d",
+                "reference": "1cf7d8e704a9cc4164c92e430f2dfa3e6983661d",
                 "shasum": ""
             },
             "require": {
@@ -2247,7 +2390,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2279,203 +2422,30 @@
                 "configuration",
                 "options"
             ],
-            "time": "2017-07-29T21:54:42+00:00"
-        },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.6.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
-                "reference": "2ec8b39c38cb16674bbf3fea2b6ce5bf117e1296",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2017-10-11T12:05:26+00:00"
-        },
-        {
-            "name": "symfony/polyfill-php54",
-            "version": "v1.6.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php54.git",
-                "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/d7810a14b2c6c1aff415e1bb755f611b3d5327bc",
-                "reference": "d7810a14b2c6c1aff415e1bb755f611b3d5327bc",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php54\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ],
-                "classmap": [
-                    "Resources/stubs"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2017-10-11T12:05:26+00:00"
-        },
-        {
-            "name": "symfony/polyfill-php55",
-            "version": "v1.6.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php55.git",
-                "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/b64e7f0c37ecf144ecc16668936eef94e628fbfd",
-                "reference": "b64e7f0c37ecf144ecc16668936eef94e628fbfd",
-                "shasum": ""
-            },
-            "require": {
-                "ircmaxell/password-compat": "~1.0",
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.6-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php55\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2017-10-11T12:05:26+00:00"
+            "time": "2018-09-17T17:29:18+00:00"
         },
         {
             "name": "symfony/polyfill-php70",
-            "version": "v1.6.0",
+            "version": "v1.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php70.git",
-                "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff"
+                "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff",
-                "reference": "0442b9c0596610bd24ae7b5f0a6cdbbc16d9fcff",
+                "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934",
+                "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934",
                 "shasum": ""
             },
             "require": {
-                "paragonie/random_compat": "~1.0|~2.0",
+                "paragonie/random_compat": "~1.0|~2.0|~9.99",
                 "php": ">=5.3.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.6-dev"
+                    "dev-master": "1.9-dev"
                 }
             },
             "autoload": {
@@ -2511,20 +2481,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2017-10-11T12:05:26+00:00"
+            "time": "2018-08-06T14:22:27+00:00"
         },
         {
             "name": "symfony/polyfill-php72",
-            "version": "v1.6.0",
+            "version": "v1.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php72.git",
-                "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254"
+                "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/6de4f4884b97abbbed9f0a84a95ff2ff77254254",
-                "reference": "6de4f4884b97abbbed9f0a84a95ff2ff77254254",
+                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/95c50420b0baed23852452a7f0c7b527303ed5ae",
+                "reference": "95c50420b0baed23852452a7f0c7b527303ed5ae",
                 "shasum": ""
             },
             "require": {
@@ -2533,7 +2503,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.6-dev"
+                    "dev-master": "1.9-dev"
                 }
             },
             "autoload": {
@@ -2566,20 +2536,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2017-10-11T12:05:26+00:00"
+            "time": "2018-08-06T14:22:27+00:00"
         },
         {
             "name": "symfony/process",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "fdf89e57a723a29baf536e288d6e232c059697b1"
+                "reference": "1dc2977afa7d70f90f3fefbcd84152813558910e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/fdf89e57a723a29baf536e288d6e232c059697b1",
-                "reference": "fdf89e57a723a29baf536e288d6e232c059697b1",
+                "url": "https://api.github.com/repos/symfony/process/zipball/1dc2977afa7d70f90f3fefbcd84152813558910e",
+                "reference": "1dc2977afa7d70f90f3fefbcd84152813558910e",
                 "shasum": ""
             },
             "require": {
@@ -2588,7 +2558,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2615,20 +2585,20 @@
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-10-02T12:28:39+00:00"
         },
         {
             "name": "symfony/stopwatch",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/stopwatch.git",
-                "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184"
+                "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/170edf8b3247d7b6779eb6fa7428f342702ca184",
-                "reference": "170edf8b3247d7b6779eb6fa7428f342702ca184",
+                "url": "https://api.github.com/repos/symfony/stopwatch/zipball/05e52a39de52ba690aebaed462b2bc8a9649f0a4",
+                "reference": "05e52a39de52ba690aebaed462b2bc8a9649f0a4",
                 "shasum": ""
             },
             "require": {
@@ -2637,7 +2607,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2664,27 +2634,31 @@
             ],
             "description": "Symfony Stopwatch Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-02T06:42:24+00:00"
+            "time": "2018-10-02T12:28:39+00:00"
         },
         {
             "name": "symfony/yaml",
-            "version": "v3.3.10",
+            "version": "v3.4.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46"
+                "reference": "640b6c27fed4066d64b64d5903a86043f4a4de7f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
-                "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/640b6c27fed4066d64b64d5903a86043f4a4de7f",
+                "reference": "640b6c27fed4066d64b64d5903a86043f4a4de7f",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5.9|>=7.0.8"
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/polyfill-ctype": "~1.8"
+            },
+            "conflict": {
+                "symfony/console": "<3.4"
             },
             "require-dev": {
-                "symfony/console": "~2.8|~3.0"
+                "symfony/console": "~3.4|~4.0"
             },
             "suggest": {
                 "symfony/console": "For validating YAML files using the lint command"
@@ -2692,7 +2666,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.3-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
@@ -2719,20 +2693,20 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "https://symfony.com",
-            "time": "2017-10-05T14:43:42+00:00"
+            "time": "2018-10-02T16:33:53+00:00"
         },
         {
             "name": "webmozart/assert",
-            "version": "1.2.0",
+            "version": "1.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
-                "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a",
+                "reference": "0df1908962e7a3071564e857d86874dad1ef204a",
                 "shasum": ""
             },
             "require": {
@@ -2769,7 +2743,7 @@
                 "check",
                 "validate"
             ],
-            "time": "2016-11-23T20:04:58+00:00"
+            "time": "2018-01-29T19:49:41+00:00"
         }
     ],
     "aliases": [],
@@ -2789,7 +2763,5 @@
         "ext-json": "*",
         "ext-mbstring": "*"
     },
-    "platform-dev": {
-        "ext-pdo_sqlite": "*"
-    }
+    "platform-dev": []
 }
diff --git a/config-templates/acl.php b/config-templates/acl.php
index 7dcca16535c3781a73af7fb67aad132d224257db..cb760d0aa7c024715049a69c6e7ee56ad0d06a43 100644
--- a/config-templates/acl.php
+++ b/config-templates/acl.php
@@ -4,58 +4,56 @@
  * This file defines "named" access control lists, which can
  * be reused in several places.
  */
-$config = array(
-
-	'adminlist' => array(
-		//array('allow', 'equals', 'mail', 'admin1@example.org'),
-		//array('allow', 'has', 'groups', 'admin'),
-		// The default action is to deny access.
-	),
-
-	'example-simple' => array(
-		array('allow', 'equals', 'mail', 'admin1@example.org'),
-		array('allow', 'equals', 'mail', 'admin2@example.org'),
-		// The default action is to deny access.
-	),
-
-	'example-deny-some' => array(
-		array('deny', 'equals', 'mail', 'eviluser@example.org'),
-		array('allow'), // Allow everybody else.
-	),
-
-	'example-maildomain' => array(
-		array('allow', 'equals-preg', 'mail', '/@example\.org$/'),
-		// The default action is to deny access.
-	),
-
-	'example-allow-employees' => array(
-		array('allow', 'has', 'eduPersonAffiliation', 'employee'),
-		// The default action is to deny access.
-	),
-
-	'example-allow-employees-not-students' => array(
-		array('deny', 'has', 'eduPersonAffiliation', 'student'),
-		array('allow', 'has', 'eduPersonAffiliation', 'employee'),
-		// The default action is to deny access.
-	),
-
-	'example-deny-student-except-one' => array(
-		array('deny', 'and',
-			array('has', 'eduPersonAffiliation', 'student'),
-			array('not', 'equals', 'mail', 'user@example.org'),
-		),
-		array('allow'),
-	),
-
-	'example-allow-or' => array(
-		array('allow', 'or',
-			array('equals', 'eduPersonAffiliation', 'student', 'member'),
-			array('equals', 'mail', 'someuser@example2.org'),
-		),
-	),
-
-	'example-allow-all' => array(
-		array('allow'),
-	),
-
-);
\ No newline at end of file
+$config = [
+    'adminlist' => [
+        //['allow', 'equals', 'mail', 'admin1@example.org'],
+        //['allow', 'has', 'groups', 'admin'],
+        // The default action is to deny access.
+    ],
+
+    'example-simple' => [
+        ['allow', 'equals', 'mail', 'admin1@example.org'],
+        ['allow', 'equals', 'mail', 'admin2@example.org'],
+        // The default action is to deny access.
+    ],
+
+    'example-deny-some' => [
+        ['deny', 'equals', 'mail', 'eviluser@example.org'],
+        ['allow'], // Allow everybody else.
+    ],
+
+    'example-maildomain' => [
+        ['allow', 'equals-preg', 'mail', '/@example\.org$/'],
+        // The default action is to deny access.
+    ],
+
+    'example-allow-employees' => [
+        ['allow', 'has', 'eduPersonAffiliation', 'employee'],
+        // The default action is to deny access.
+    ],
+
+    'example-allow-employees-not-students' => [
+        ['deny', 'has', 'eduPersonAffiliation', 'student'],
+        ['allow', 'has', 'eduPersonAffiliation', 'employee'],
+        // The default action is to deny access.
+    ],
+
+    'example-deny-student-except-one' => [
+        ['deny', 'and',
+            ['has', 'eduPersonAffiliation', 'student'],
+            ['not', 'equals', 'mail', 'user@example.org'],
+        ],
+        ['allow'],
+    ],
+
+    'example-allow-or' => [
+        ['allow', 'or',
+            ['equals', 'eduPersonAffiliation', 'student', 'member'],
+            ['equals', 'mail', 'someuser@example2.org'],
+        ],
+    ],
+
+    'example-allow-all' => [
+        ['allow'],
+    ],
+];
diff --git a/config-templates/authmemcookie.php b/config-templates/authmemcookie.php
index 6fa872061d9e7580efadba42b56a67d36b11755e..fac02813814cd56c09cd69ce3b526408d35da4e9 100644
--- a/config-templates/authmemcookie.php
+++ b/config-templates/authmemcookie.php
@@ -4,72 +4,70 @@
  * This is the configuration file for the Auth MemCookie example.
  */
 
-$config = array(
+$config = [
+    /*
+     * The authentication source that should be used.
+     *
+     * This must be one of the authentication sources configured in config/authsources.php.
+     */
+    'authsource' => 'default-sp',
 
-	/*
-	 * The authentication source that should be used.
-	 *
-	 * This must be one of the authentication sources configured in config/authsources.php.
-	 */
-	'authsource' => 'default-sp',
+    /*
+     * This is the name of the cookie we should save the session id in. The value of this option must match the
+     * Auth_memCookie_CookieName option in the Auth MemCookie configuration. The default value is 'AuthMemCookie'.
+     *
+     * Default:
+     *  'cookiename' => 'AuthMemCookie',
+     */
+    'cookiename' => 'AuthMemCookie',
 
-	/*
-	 * This is the name of the cookie we should save the session id in. The value of this option must match the
-	 * Auth_memCookie_CookieName option in the Auth MemCookie configuration. The default value is 'AuthMemCookie'.
-	 *
-	 * Default:
-	 *  'cookiename' => 'AuthMemCookie',
-	 */
-	'cookiename' => 'AuthMemCookie',
+    /*
+     * This option specifies the name of the attribute which contains the username of the user. It must be set to
+     * a valid attribute name.
+     *
+     * Examples:
+     *  'username' => 'uid', // LDAP attribute for user id.
+     *  'username' => 'mail', // LDAP attribute for email address.
+     *
+     * Default:
+     *  No default value.
+     */
+    'username' => null,
 
-	/*
-	 * This option specifies the name of the attribute which contains the username of the user. It must be set to
-	 * a valid attribute name.
-	 *
-	 * Examples:
-	 *  'username' => 'uid', // LDAP attribute for user id.
-	 *  'username' => 'mail', // LDAP attribute for email address.
-	 *
-	 * Default:
-	 *  No default value.
-	 */
-	'username' => null,
+    /*
+     * This option specifies the name of the attribute which contains the groups of the user. Set this option to
+     * NULL if you don't want to include any groups.
+     *
+     * Example:
+     *  'groups' => 'edupersonaffiliation',
+     *
+     * Default:
+     *  'groups' => null,
+     */
+    'groups' => null,
 
-	/*
-	 * This option specifies the name of the attribute which contains the groups of the user. Set this option to
-	 * NULL if you don't want to include any groups.
-	 *
-	 * Example:
-	 *  'groups' => 'edupersonaffiliation',
-	 *
-	 * Default:
-	 *  'groups' => null,
-	 */
-	'groups' => null,
+    /*
+     * This option contains the hostnames or IP addresses of the memcache servers where we should store the
+     * authentication information. Separator is a comma. This option should match the address part of the
+     * Auth_memCookie_Memcached_AddrPort option in the Auth MemCookie configuration.
+     *
+     * Examples:
+     *  'memcache.host' => '192.168.93.52',
+     *  'memcache.host' => 'memcache.example.org',
+     *  'memcache.host' => 'memcache1.example.org,memcache2.example.org'
+     *
+     * Default:
+     *  'memcache.host' => '127.0.0.1',
+     */
+    'memcache.host' => '127.0.0.1',
 
-	/*
-	 * This option contains the hostnames or IP addresses of the memcache servers where we should store the
-	 * authentication information. Separator is a comma. This option should match the address part of the
-	 * Auth_memCookie_Memcached_AddrPort option in the Auth MemCookie configuration.
-	 *
-	 * Examples:
-	 *  'memcache.host' => '192.168.93.52',
-	 *  'memcache.host' => 'memcache.example.org',
-	 *  'memcache.host' => 'memcache1.example.org,memcache2.example.org'
-	 *
-	 * Default:
-	 *  'memcache.host' => '127.0.0.1',
-	 */
-	'memcache.host' => '127.0.0.1',
-
-	/*
-	 * This option contains the port number of the memcache server where we should store the
-	 * authentication information. This option should match the port part of the
-	 * Auth_memCookie_Memcached_AddrPort option in the Auth MemCookie configuration.
-	 *
-	 * Default:
-	 *  'memcache.port' => 11211,
-	 */
-	'memcache.port' => 11211,
-
-);
+    /*
+     * This option contains the port number of the memcache server where we should store the
+     * authentication information. This option should match the port part of the
+     * Auth_memCookie_Memcached_AddrPort option in the Auth MemCookie configuration.
+     *
+     * Default:
+     *  'memcache.port' => 11211,
+     */
+    'memcache.port' => 11211,
+];
diff --git a/config-templates/authsources.php b/config-templates/authsources.php
index 6afe417811d36c5248af6fa115dc3001d2bf1456..ac1d1c5545fa14b685d2c6f58b078eaf44e95aeb 100644
--- a/config-templates/authsources.php
+++ b/config-templates/authsources.php
@@ -1,19 +1,19 @@
 <?php
 
-$config = array(
+$config = [
 
     // This is a authentication source which handles admin authentication.
-    'admin' => array(
+    'admin' => [
         // The default is to use core:AdminPassword, but it can be replaced with
         // any authentication source.
 
         'core:AdminPassword',
-    ),
+    ],
 
 
     // An authentication source which can authenticate against both SAML 2.0
     // and Shibboleth 1.3 IdPs.
-    'default-sp' => array(
+    'default-sp' => [
         'saml:SP',
 
         // The entity ID of this SP.
@@ -28,26 +28,6 @@ $config = array(
         // Can be NULL/unset, in which case a builtin discovery service will be used.
         'discoURL' => null,
 
-        /*
-         * WARNING: SHA-1 is disallowed starting January the 1st, 2014.
-         *
-         * Uncomment the following option to start using SHA-256 for your signatures.
-         * Currently, SimpleSAMLphp defaults to SHA-1, which has been deprecated since
-         * 2011, and will be disallowed by NIST as of 2014. Please refer to the following
-         * document for more information:
-         *
-         * http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf
-         *
-         * If you are uncertain about identity providers supporting SHA-256 or other
-         * algorithms of the SHA-2 family, you can configure it individually in the
-         * IdP-remote metadata set for those that support it. Once you are certain that
-         * all your configured IdPs support SHA-2, you can safely remove the configuration
-         * options in the IdP-remote metadata set and uncomment the following option.
-         *
-         * Please refer to the hosted SP configuration reference for more information.
-          */
-        //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
-
         /*
          * The attributes parameter must contain an array of desired attributes by the SP.
          * The attributes can be expressed as an array of names or as an associative array
@@ -55,79 +35,81 @@ $config = array(
          * The metadata will then be created as follows:
          * <md:RequestedAttribute FriendlyName="friendlyName" Name="name" />
          */
-        /*'name' => array(
-             'en' => 'A service',
-             'no' => 'En tjeneste',
-          ),
+        /*
+        'name' => [
+            'en' => 'A service',
+            'no' => 'En tjeneste',
+        ],
 
-          'attributes' => array(
+        'attributes' => [
             'attrname' => 'urn:oid:x.x.x.x',
-        ),*/
-        /*'attributes.required' => array (
+        ],
+        'attributes.required' => [
             'urn:oid:x.x.x.x',
-        ),*/
-    ),
+        ],
+        */
+    ],
 
 
     /*
-    'example-sql' => array(
+    'example-sql' => [
         'sqlauth:SQL',
         'dsn' => 'pgsql:host=sql.example.org;port=5432;dbname=simplesaml',
         'username' => 'simplesaml',
         'password' => 'secretpassword',
-        'query' => 'SELECT uid, givenName, email, eduPersonPrincipalName FROM users WHERE uid = :username AND password = SHA2(CONCAT((SELECT salt FROM users WHERE uid = :username), :password),256);',
-    ),
+        'query' => 'SELECT uid, givenName, email, eduPersonPrincipalName FROM users WHERE uid = :username AND password = SHA2(CONCAT((SELECT salt FROM users WHERE uid = :username), :password), 256);',
+    ],
     */
 
     /*
-    'example-static' => array(
+    'example-static' => [
         'exampleauth:Static',
-        'uid' => array('testuser'),
-        'eduPersonAffiliation' => array('member', 'employee'),
-        'cn' => array('Test User'),
-    ),
+        'uid' => ['testuser'],
+        'eduPersonAffiliation' => ['member', 'employee'],
+        'cn' => ['Test User'],
+    ],
     */
 
     /*
-    'example-userpass' => array(
+    'example-userpass' => [
         'exampleauth:UserPass',
 
         // Give the user an option to save their username for future login attempts
         // And when enabled, what should the default be, to save the username or not
-        //'remember.username.enabled' => FALSE,
-        //'remember.username.checked' => FALSE,
-
-        'student:studentpass' => array(
-            'uid' => array('test'),
-            'eduPersonAffiliation' => array('member', 'student'),
-        ),
-        'employee:employeepass' => array(
-            'uid' => array('employee'),
-            'eduPersonAffiliation' => array('member', 'employee'),
-        ),
-    ),
+        //'remember.username.enabled' => false,
+        //'remember.username.checked' => false,
+
+        'student:studentpass' => [
+            'uid' => ['test'],
+            'eduPersonAffiliation' => ['member', 'student'],
+        ],
+        'employee:employeepass' => [
+            'uid' => ['employee'],
+            'eduPersonAffiliation' => ['member', 'employee'],
+        ],
+    ],
     */
 
     /*
-    'crypto-hash' => array(
+    'crypto-hash' => [
         'authcrypt:Hash',
         // hashed version of 'verysecret', made with bin/pwgen.php
-        'professor:{SSHA256}P6FDTEEIY2EnER9a6P2GwHhI5JDrwBgjQ913oVQjBngmCtrNBUMowA==' => array(
-            'uid' => array('prof_a'),
-            'eduPersonAffiliation' => array('member', 'employee', 'board'),
-        ),
-    ),
+        'professor:{SSHA256}P6FDTEEIY2EnER9a6P2GwHhI5JDrwBgjQ913oVQjBngmCtrNBUMowA==' => [
+            'uid' => ['prof_a'],
+            'eduPersonAffiliation' => ['member', 'employee', 'board'],
+        ],
+    ],
     */
 
     /*
-    'htpasswd' => array(
+    'htpasswd' => [
         'authcrypt:Htpasswd',
         'htpasswd_file' => '/var/www/foo.edu/legacy_app/.htpasswd',
-        'static_attributes' => array(
-            'eduPersonAffiliation' => array('member', 'employee'),
-            'Organization' => array('University of Foo'),
-        ),
-    ),
+        'static_attributes' => [
+            'eduPersonAffiliation' => ['member', 'employee'],
+            'Organization' => ['University of Foo'],
+        ],
+    ],
     */
 
     /*
@@ -135,68 +117,21 @@ $config = array(
     // external authentication engine. Take a look at the comment in the beginning
     // of modules/exampleauth/lib/Auth/Source/External.php for a description of
     // how to adjust it to your own site.
-    'example-external' => array(
+    'example-external' => [
         'exampleauth:External',
-    ),
+    ],
     */
 
     /*
-    'yubikey' => array(
+    'yubikey' => [
         'authYubiKey:YubiKey',
          'id' => '000',
         // 'key' => '012345678',
-    ),
-    */
-
-    /*
-    'openid' => array(
-        'openid:OpenIDConsumer',
-        'attributes.required' => array('nickname'),
-        'attributes.optional' => array('fullname', 'email',),
-        // 'sreg.validate' => FALSE,
-        'attributes.ax_required' => array('http://axschema.org/namePerson/friendly'),
-        'attributes.ax_optional' => array('http://axschema.org/namePerson','http://axschema.org/contact/email'),
-        // Prefer HTTP redirect over POST
-        // 'prefer_http_redirect' => FALSE,
-    ),
-    */
-
-    /*
-    // Example of an authsource that authenticates against Google.
-    // See: http://code.google.com/apis/accounts/docs/OpenID.html
-    'google' => array(
-        'openid:OpenIDConsumer',
-        // Googles OpenID endpoint.
-        'target' => 'https://www.google.com/accounts/o8/id',
-        // Custom realm
-        // 'realm' => 'http://*.example.org',
-        // Attributes that google can supply.
-        'attributes.ax_required' => array(
-            //'http://axschema.org/namePerson/first',
-            //'http://axschema.org/namePerson/last',
-            //'http://axschema.org/contact/email',
-            //'http://axschema.org/contact/country/home',
-            //'http://axschema.org/pref/language',
-        ),
-        // custom extension arguments
-        'extension.args' => array(
-            //'http://specs.openid.net/extensions/ui/1.0' => array(
-            //	'mode' => 'popup',
-            //	'icon' => 'true',
-            //),
-        ),
-    ),
-    */
-
-    /*
-    'papi' => array(
-        'authpapi:PAPI',
-    ),
+    ],
     */
 
-
     /*
-    'facebook' => array(
+    'facebook' => [
         'authfacebook:Facebook',
         // Register your Facebook application on http://www.facebook.com/developers
         // App ID or API key (requests with App ID should be faster; https://github.com/facebook/php-sdk/issues/214)
@@ -210,7 +145,7 @@ $config = array(
         // When empty, only the app-specific user id and name will be returned
         // See https://developers.facebook.com/docs/graph-api/reference/v2.6/user for the full list
         // 'user_fields' => 'email,birthday,third_party_id,name,first_name,last_name',
-    ),
+    ],
     */
 
     /*
@@ -219,70 +154,59 @@ $config = array(
     //  https://www.linkedin.com/secure/developer
     // Attributes definition:
     //  https://developer.linkedin.com/docs/fields
-    'linkedin' => array(
+    'linkedin' => [
         'authlinkedin:LinkedIn',
         'key' => 'xxxxxxxxxxxxxxxx',
         'secret' => 'xxxxxxxxxxxxxxxx',
         'attributes' => 'id,first-name,last-name,headline,summary,specialties,picture-url,email-address',
-    ),
+    ],
     */
 
     /*
     // Twitter OAuth Authentication API.
     // Register your application to get an API key here:
     //  http://twitter.com/oauth_clients
-    'twitter' => array(
+    'twitter' => [
         'authtwitter:Twitter',
         'key' => 'xxxxxxxxxxxxxxxx',
         'secret' => 'xxxxxxxxxxxxxxxx',
 
         // Forces the user to enter their credentials to ensure the correct users account is authorized.
         // Details: https://dev.twitter.com/docs/api/1/get/oauth/authenticate
-        'force_login' => FALSE,
-    ),
-    */
-
-    /*
-    // MySpace OAuth Authentication API.
-    // Register your application to get an API key here:
-    //  http://developer.myspace.com/
-    'myspace' => array(
-        'authmyspace:MySpace',
-        'key' => 'xxxxxxxxxxxxxxxx',
-        'secret' => 'xxxxxxxxxxxxxxxx',
-    ),
+        'force_login' => false,
+    ],
     */
 
     /*
     // Microsoft Account (Windows Live ID) Authentication API.
     // Register your application to get an API key here:
     //  https://apps.dev.microsoft.com/
-    'windowslive' => array(
+    'windowslive' => [
         'authwindowslive:LiveID',
         'key' => 'xxxxxxxxxxxxxxxx',
         'secret' => 'xxxxxxxxxxxxxxxx',
-    ),
+    ],
     */
 
     /*
     // Example of a LDAP authentication source.
-    'example-ldap' => array(
+    'example-ldap' => [
         'ldap:LDAP',
 
         // Give the user an option to save their username for future login attempts
         // And when enabled, what should the default be, to save the username or not
-        //'remember.username.enabled' => FALSE,
-        //'remember.username.checked' => FALSE,
+        //'remember.username.enabled' => false,
+        //'remember.username.checked' => false,
 
         // The hostname of the LDAP server.
         'hostname' => 'ldap.example.org',
 
         // Whether SSL/TLS should be used when contacting the LDAP server.
-        'enable_tls' => TRUE,
+        'enable_tls' => true,
 
         // Whether debug output from the LDAP library should be enabled.
         // Default is FALSE.
-        'debug' => FALSE,
+        'debug' => false,
 
         // The timeout for accessing the LDAP server, in seconds.
         // The default is 0, which means no timeout.
@@ -293,12 +217,12 @@ $config = array(
         'port' => 389,
 
         // Set whether to follow referrals. AD Controllers may require FALSE to function.
-        'referrals' => TRUE,
+        'referrals' => true,
 
         // Which attributes should be retrieved from the LDAP server.
         // This can be an array of attribute names, or NULL, in which case
         // all attributes are fetched.
-        'attributes' => NULL,
+        'attributes' => null,
 
         // The pattern which should be used to create the users DN given the username.
         // %username% in this pattern will be replaced with the users username.
@@ -308,7 +232,7 @@ $config = array(
 
         // As an alternative to specifying a pattern for the users DN, it is possible to
         // search for the username in a set of attributes. This is enabled by this option.
-        'search.enable' => FALSE,
+        'search.enable' => false,
 
         // The DN which will be used as a base for the search.
         // This can be a single string, in which case only that DN is searched, or an
@@ -319,40 +243,45 @@ $config = array(
         //
         // This is an array with one or more attribute names. Any of the attributes in
         // the array may match the value the username.
-        'search.attributes' => array('uid', 'mail'),
+        'search.attributes' => ['uid', 'mail'],
 
         // Additional LDAP filters appended to the search attributes
         'search.filter' => '(objectclass=inetorgperson)',
 
         // The username & password the SimpleSAMLphp should bind to before searching. If
         // this is left as NULL, no bind will be performed before searching.
-        'search.username' => NULL,
-        'search.password' => NULL,
+        'search.username' => null,
+        'search.password' => null,
 
         // If the directory uses privilege separation,
         // the authenticated user may not be able to retrieve
         // all required attribures, a privileged entity is required
         // to get them. This is enabled with this option.
-        'priv.read' => FALSE,
+        'priv.read' => false,
 
         // The DN & password the SimpleSAMLphp should bind to before
         // retrieving attributes. These options are required if
         // 'priv.read' is set to TRUE.
-        'priv.username' => NULL,
-        'priv.password' => NULL,
+        'priv.username' => null,
+        'priv.password' => null,
 
-    ),
+    ],
     */
 
     /*
     // Example of an LDAPMulti authentication source.
-    'example-ldapmulti' => array(
+    'example-ldapmulti' => [
         'ldap:LDAPMulti',
 
         // Give the user an option to save their username for future login attempts
         // And when enabled, what should the default be, to save the username or not
-        //'remember.username.enabled' => FALSE,
-        //'remember.username.checked' => FALSE,
+        //'remember.username.enabled' => false,
+        //'remember.username.checked' => false,
+
+        // Give the user an option to save their organization choice for future login
+        // attempts. And when enabled, what should the default be, checked or not.
+        //'remember.organization.enabled' => false,
+        //'remember.organization.checked' => false,
 
         // The way the organization as part of the username should be handled.
         // Three possible values:
@@ -371,7 +300,7 @@ $config = array(
         // username will be used as the user enters it.
         //
         // The default is FALSE.
-        'include_organization_in_username' => FALSE,
+        'include_organization_in_username' => false,
 
         // A list of available LDAP servers.
         //
@@ -381,7 +310,7 @@ $config = array(
         //
         // The value of each element is an array in the same format as an LDAP
         // authentication source.
-        'employees' => array(
+        'employees' => [
             // A short name/description for this group. Will be shown in a dropdown list
             // when the user logs on.
             //
@@ -392,16 +321,14 @@ $config = array(
             // the LDAP authentication source.
             'hostname' => 'ldap.employees.example.org',
             'dnpattern' => 'uid=%username%,ou=employees,dc=example,dc=org',
-        ),
+        ],
 
-        'students' => array(
+        'students' => [
             'description' => 'Students',
 
             'hostname' => 'ldap.students.example.org',
             'dnpattern' => 'uid=%username%,ou=students,dc=example,dc=org',
-        ),
-
-    ),
+        ],
+    ],
     */
-
-);
+];
diff --git a/config-templates/config.php b/config-templates/config.php
index 5833e48ebd76f8a49e618010a30e44fe4aac5cdc..ac9b800f230c7a435735e9c37a183370dbe9bef4 100644
--- a/config-templates/config.php
+++ b/config-templates/config.php
@@ -4,7 +4,7 @@
  *
  */
 
-$config = array(
+$config = [
 
     /*******************************
      | BASIC CONFIGURATION OPTIONS |
@@ -33,7 +33,7 @@ $config = array(
      * The 'application' configuration array groups a set configuration options
      * relative to an application protected by SimpleSAMLphp.
      */
-    //'application' => array(
+    //'application' => [
         /*
          * The 'baseURL' configuration option allows you to specify a protocol,
          * host and optionally a port that serves as the canonical base for all
@@ -48,8 +48,8 @@ $config = array(
          * need to compute the right URLs yourself and pass them dynamically
          * to SimpleSAMLphp's API.
          */
-        //'baseURL' => 'https://example.com'
-    //),
+        //'baseURL' => 'https://example.com',
+    //],
 
     /*
      * The following settings are *filesystem paths* which define where
@@ -103,7 +103,7 @@ $config = array(
      * 'secretsalt' can be any valid string of any length.
      *
      * A possible way to generate a random salt is by running the following command from a unix shell:
-     * tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom | dd bs=32 count=1 2>/dev/null;echo
+     * LC_CTYPE=C tr -c -d '0123456789abcdefghijklmnopqrstuvwxyz' </dev/urandom | dd bs=32 count=1 2>/dev/null;echo
      */
     'secretsalt' => 'defaultsecretsalt',
 
@@ -148,9 +148,9 @@ $config = array(
      * WHAT YOU ARE DOING!
      *
      * Example:
-     *   'trusted.url.domains' => array('sp.example.com', 'app.example.com'),
+     *   'trusted.url.domains' => ['sp.example.com', 'app.example.com'],
      */
-    'trusted.url.domains' => array(),
+    'trusted.url.domains' => [],
 
     /*
      * Enable regular expression matching of trusted.url.domains.
@@ -214,11 +214,11 @@ $config = array(
      * If you want to disable debugging completely, unset this option or set it to an
      * empty array.
      */
-    'debug' => array(
+    'debug' => [
         'saml' => false,
         'backtraces' => true,
         'validatexml' => false,
-    ),
+    ],
 
     /*
      * When 'showerrors' is enabled, all error messages and stack traces will be output
@@ -231,11 +231,11 @@ $config = array(
     'errorreporting' => true,
 
     /*
-     * Custom error show function called from SimpleSAML_Error_Error::show.
+     * Custom error show function called from SimpleSAML\Error\Error::show.
      * See docs/simplesamlphp-errorhandling.txt for function code example.
      *
      * Example:
-     *   'errors.show_function' => array('sspmod_example_Error_Show', 'show'),
+     *   'errors.show_function' => ['SimpleSAML\Module\example\Error', 'show'],
      */
 
 
@@ -316,21 +316,21 @@ $config = array(
      * This is an array of outputs. Each output has at least a 'class' option, which
      * selects the output.
      */
-    'statistics.out' => array(// Log statistics to the normal log.
+    'statistics.out' => [// Log statistics to the normal log.
         /*
-        array(
+        [
             'class' => 'core:Log',
             'level' => 'notice',
-        ),
+        ],
         */
         // Log statistics to files in a directory. One file per day.
         /*
-        array(
+        [
             'class' => 'core:File',
             'directory' => '/var/log/stats',
-        ),
+        ],
         */
-    ),
+    ],
 
 
 
@@ -351,7 +351,7 @@ $config = array(
      * Example:
      *   'proxy.auth' = 'myuser:password'
      */
-    'proxy.auth' => false,
+    //'proxy.auth' => 'myuser:password',
 
 
 
@@ -377,13 +377,18 @@ $config = array(
      */
     'database.username' => 'simplesamlphp',
     'database.password' => 'secret',
-    'database.options' => array(),
+    'database.options' => [],
 
     /*
      * (Optional) Table prefix
      */
     'database.prefix' => '',
 
+    /*
+     * (Optional) Driver options
+     */
+    'database.driver_options' => [],
+
     /*
      * True or false if you would like a persistent database connection
      */
@@ -397,18 +402,18 @@ $config = array(
      *
      * Configuration options in the slave array are exactly the same as the
      * options for the master (shown above) with the exception of the table
-     * prefix.
+     * prefix and driver options.
      */
-    'database.slaves' => array(
+    'database.slaves' => [
         /*
-        array(
+        [
             'dsn' => 'mysql:host=myslave;dbname=saml',
             'username' => 'simplesamlphp',
             'password' => 'secret',
             'persistent' => false,
-        ),
+        ],
         */
-    ),
+    ],
 
 
 
@@ -453,11 +458,11 @@ $config = array(
      *
      * Example:
      *
-     * 'module.enable' => array(
-     *      'exampleauth' => TRUE, // Setting to TRUE enables.
-     *      'saml' => FALSE, // Setting to FALSE disables.
-     *      'core' => NULL, // Unset or NULL uses default.
-     * ),
+     * 'module.enable' => [
+     *      'exampleauth' => true, // Setting to TRUE enables.
+     *      'saml' => false, // Setting to FALSE disables.
+     *      'core' => null, // Unset or NULL uses default.
+     * ],
      *
      */
 
@@ -563,7 +568,7 @@ $config = array(
      * See docs/simplesamlphp-advancedfeatures.txt for function code example.
      *
      * Example:
-     *   'session.check_function' => array('sspmod_example_Util', 'checkSession'),
+     *   'session.check_function' => ['\SimpleSAML\Module\example\Util', 'checkSession'],
      */
 
 
@@ -601,33 +606,33 @@ $config = array(
      * Note that sessions will be lost if one server is lost from both the
      * a-group and the b-group.
      *
-     * 'memcache_store.servers' => array(
-     *     array(
-     *         array('hostname' => 'mc_a1'),
-     *         array('hostname' => 'mc_a2'),
-     *     ),
-     *     array(
-     *         array('hostname' => 'mc_b1'),
-     *         array('hostname' => 'mc_b2'),
-     *     ),
-     * ),
+     * 'memcache_store.servers' => [
+     *     [
+     *         ['hostname' => 'mc_a1'],
+     *         ['hostname' => 'mc_a2'],
+     *     ],
+     *     [
+     *         ['hostname' => 'mc_b1'],
+     *         ['hostname' => 'mc_b2'],
+     *     ],
+     * ],
      *
      * Example of simple configuration with only one memcache server,
      * running on the same computer as the web server:
      * Note that all sessions will be lost if the memcache server crashes.
      *
-     * 'memcache_store.servers' => array(
-     *     array(
-     *         array('hostname' => 'localhost'),
-     *     ),
-     * ),
+     * 'memcache_store.servers' => [
+     *     [
+     *         ['hostname' => 'localhost'],
+     *     ],
+     * ],
      *
      */
-    'memcache_store.servers' => array(
-        array(
-            array('hostname' => 'localhost'),
-        ),
-    ),
+    'memcache_store.servers' => [
+        [
+            ['hostname' => 'localhost'],
+        ],
+    ],
 
     /*
      * This value allows you to set a prefix for memcache-keys. The default
@@ -665,7 +670,7 @@ $config = array(
     /*
      * Language-related options.
      */
-    'language' => array(
+    'language' => [
         /*
          * An array in the form 'language' => <list of alternative languages>.
          *
@@ -676,32 +681,32 @@ $config = array(
          *
          * For example, for the "no" language code (Norwegian), we would have:
          *
-         * 'priorities' => array(
-         *      'no' => array('nb', 'nn', 'en', 'se'),
+         * 'priorities' => [
+         *      'no' => ['nb', 'nn', 'en', 'se'],
          *      ...
-         * ),
+         * ],
          *
          * establishing that if a translation for the "no" language code is
          * not available, we look for translations in "nb" (Norwegian BokmĂĄl),
          * and so on, in that order.
          */
-        'priorities' => array(
-            'no' => array('nb', 'nn', 'en', 'se'),
-            'nb' => array('no', 'nn', 'en', 'se'),
-            'nn' => array('no', 'nb', 'en', 'se'),
-            'se' => array('nb', 'no', 'nn', 'en'),
-        ),
-    ),
+        'priorities' => [
+            'no' => ['nb', 'nn', 'en', 'se'],
+            'nb' => ['no', 'nn', 'en', 'se'],
+            'nn' => ['no', 'nb', 'en', 'se'],
+            'se' => ['nb', 'no', 'nn', 'en'],
+        ],
+    ],
 
     /*
      * Languages available, RTL languages, and what language is the default.
      */
-    'language.available' => array(
-        'en', 'no', 'nn', 'se', 'da', 'de', 'sv', 'fi', 'es', 'fr', 'it', 'nl', 'lb', 'cs',
-        'sl', 'lt', 'hr', 'hu', 'pl', 'pt', 'pt-br', 'tr', 'ja', 'zh', 'zh-tw', 'ru', 'et',
-        'he', 'id', 'sr', 'lv', 'ro', 'eu', 'el', 'af'
-    ),
-    'language.rtl' => array('ar', 'dv', 'fa', 'ur', 'he'),
+    'language.available' => [
+        'en', 'no', 'nn', 'se', 'da', 'de', 'sv', 'fi', 'es', 'ca', 'fr', 'it', 'nl', 'lb',
+        'cs', 'sl', 'lt', 'hr', 'hu', 'pl', 'pt', 'pt-br', 'tr', 'ja', 'zh', 'zh-tw', 'ru',
+        'et', 'he', 'id', 'sr', 'lv', 'ro', 'eu', 'el', 'af'
+    ],
+    'language.rtl' => ['ar', 'dv', 'fa', 'ur', 'he'],
     'language.default' => 'en',
 
     /*
@@ -740,7 +745,7 @@ $config = array(
      * the default language for the user.
      *
      * Example:
-     *   'language.get_language_function' => array('sspmod_example_Template', 'getLanguage'),
+     *   'language.get_language_function' => ['\SimpleSAML\Module\example\Template', 'getLanguage'],
      */
 
     /*
@@ -849,11 +854,12 @@ $config = array(
      * Authentication processing filters that will be executed for all IdPs
      * Both Shibboleth and SAML 2.0
      */
-    'authproc.idp' => array(
+    'authproc.idp' => [
         /* Enable the authproc filter below to add URN prefixes to all attributes
-         10 => array(
-             'class' => 'core:AttributeMap', 'addurnprefix'
-         ), */
+        10 => array[
+            'class' => 'core:AttributeMap', 'addurnprefix'
+        ],
+        */
         /* Enable the authproc filter below to automatically generated eduPersonTargetedID.
         20 => 'core:TargetedID',
         */
@@ -861,11 +867,11 @@ $config = array(
         // Adopts language from attribute to use in UI
         30 => 'core:LanguageAdaptor',
 
-        45 => array(
+        45 => [
             'class'         => 'core:StatisticsWithAttribute',
             'attributename' => 'realm',
             'type'          => 'saml20-idp-SSO',
-        ),
+        ],
 
         /* When called without parameters, it will fallback to filter attributes ‹the old way›
          * by checking the 'attributes' parameter in metadata on IdP hosted and SP remote.
@@ -874,58 +880,61 @@ $config = array(
 
         /*
          * Search attribute "distinguishedName" for pattern and replaces if found
-
-        60 => array(
+         */
+        /*
+        60 => [
             'class' => 'core:AttributeAlter',
             'pattern' => '/OU=studerende/',
             'replacement' => 'Student',
             'subject' => 'distinguishedName',
             '%replace',
-        ),
-         */
+        ],
+        */
 
         /*
          * Consent module is enabled (with no permanent storage, using cookies).
-
-        90 => array(
+         */
+        /*
+        90 => [
             'class' => 'consent:Consent',
             'store' => 'consent:Cookie',
             'focus' => 'yes',
-            'checked' => TRUE
-        ),
-         */
+            'checked' => true
+        ],
+        */
         // If language is set in Consent module it will be added as an attribute.
         99 => 'core:LanguageAdaptor',
-    ),
+    ],
 
     /*
      * Authentication processing filters that will be executed for all SPs
      * Both Shibboleth and SAML 2.0
      */
-    'authproc.sp' => array(
+    'authproc.sp' => [
         /*
-        10 => array(
+        10 => [
             'class' => 'core:AttributeMap', 'removeurnprefix'
-        ),
+        ],
         */
 
         /*
          * Generate the 'group' attribute populated from other variables, including eduPersonAffiliation.
-         60 => array(
+        60 => [
             'class' => 'core:GenerateGroups', 'eduPersonAffiliation'
-        ),
+        ],
         */
         /*
          * All users will be members of 'users' and 'members'
-        61 => array(
-            'class' => 'core:AttributeAdd', 'groups' => array('users', 'members')
-        ),
+         */
+        /*
+        61 => [
+            'class' => 'core:AttributeAdd', 'groups' => ['users', 'members']
+        ],
         */
 
         // Adopts language from attribute to use in UI
         90 => 'core:LanguageAdaptor',
-
-    ),
+    ],
 
 
 
@@ -982,40 +991,40 @@ $config = array(
      * This example defines two flatfile sources. One is the default metadata directory, the other
      * is a metadata directory with auto-generated metadata files.
      *
-     * 'metadata.sources' => array(
-     *     array('type' => 'flatfile'),
-     *     array('type' => 'flatfile', 'directory' => 'metadata-generated'),
-     * ),
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile'],
+     *     ['type' => 'flatfile', 'directory' => 'metadata-generated'],
+     * ],
      *
      * This example defines a flatfile source and an XML source.
-     * 'metadata.sources' => array(
-     *     array('type' => 'flatfile'),
-     *     array('type' => 'xml', 'file' => 'idp.example.org-idpMeta.xml'),
-     * ),
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile'],
+     *     ['type' => 'xml', 'file' => 'idp.example.org-idpMeta.xml'],
+     * ],
      *
      * This example defines an mdq source.
-     * 'metadata.sources' => array(
-     *      array(
+     * 'metadata.sources' => [
+     *      [
      *          'type' => 'mdq',
      *          'server' => 'http://mdq.server.com:8080',
      *          'cachedir' => '/var/simplesamlphp/mdq-cache',
      *          'cachelength' => 86400
-     *      )
-     * ),
+     *      ]
+     * ],
      *
      * This example defines an pdo source.
-     * 'metadata.sources' => array(
-     *     array('type' => 'pdo')
-     * ),
+     * 'metadata.sources' => [
+     *     ['type' => 'pdo']
+     * ],
      *
      * Default:
-     * 'metadata.sources' => array(
-     *     array('type' => 'flatfile')
-     * ),
+     * 'metadata.sources' => [
+     *     ['type' => 'flatfile']
+     * ],
      */
-    'metadata.sources' => array(
-        array('type' => 'flatfile'),
-    ),
+    'metadata.sources' => [
+        ['type' => 'flatfile'],
+    ],
 
     /*
      * Should signing of generated metadata be enabled by default.
@@ -1054,8 +1063,6 @@ $config = array(
      * - 'redis': Key-value datastore, based on redis.
      *
      * The default datastore is 'phpsession'.
-     *
-     * (This option replaces the old 'session.handler'-option.)
      */
     'store.type'                    => 'phpsession',
 
@@ -1088,4 +1095,4 @@ $config = array(
      * The prefix we should use on our Redis datastore.
      */
     'store.redis.prefix' => 'SimpleSAMLphp',
-);
+];
diff --git a/dictionaries/admin.translation.json b/dictionaries/admin.translation.json
index 28742f46bead11bf762aba2dcce6829192db3cbb..7f5f18abbdbc4d57dfdc8f92a55beafdc632eb34 100644
--- a/dictionaries/admin.translation.json
+++ b/dictionaries/admin.translation.json
@@ -885,8 +885,7 @@
 		"sr": "Shib 1.3 Davalac Identiteta (udaljeni)",
 		"ro": "Furnizor de identitate Shib 1.3 (distant)",
 		"ru": "\u041f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 Shib 1.3 (\u0443\u0434\u0430\u043b\u0435\u043d\u043d\u043e\u0435 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435)",
-		"eu": "Shib 1.3 Identitate hornitzailea (Urrunekoa)",
-		"eu": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03c2 \u03a4\u03b1\u03c5\u03c4\u03cc\u03c4\u03b7\u03c4\u03b1\u03c2 Shib 1.3 (\u0391\u03c0\u03bf\u03bc\u03b1\u03ba\u03c1\u03c5\u03c3\u03bc\u03ad\u03bd\u03bf\u03c2)"
+		"eu": "Shib 1.3 Identitate hornitzailea (Urrunekoa)"
 	},
 	"metaover_group_metadata.wsfed-sp-hosted": {
 		"no": "WS-Federation tjenesteleverand\u00f8r (intern)",
diff --git a/dictionaries/attributes.definition.json b/dictionaries/attributes.definition.json
index c04dcfc27d2ef427ea6351e32b451bc48a2f9c79..ee886676522c86d4f75a924c9bc590838ac7c648 100644
--- a/dictionaries/attributes.definition.json
+++ b/dictionaries/attributes.definition.json
@@ -47,12 +47,18 @@
 	"attribute_edupersontargetedid": {
 		"en": "Persistent pseudonymous ID"
 	},
+	"attribute_pairwise_id": {
+		"en": "Service-specific pseudonymous ID at home organization"
+	},
 	"attribute_edupersonprincipalname": {
 		"en": "Person's principal name at home organization"
 	},
 	"attribute_edupersonuniqueid": {
 		"en": "Person's non-reassignable, persistent pseudonymous ID at home organization"
 	},
+	"attribute_subject_id": {
+		"en": "Pseudonymous ID at home organization"
+	},
 	"attribute_edupersonorcid": {
 		"en": "ORCID researcher identifiers"
 	},
diff --git a/dictionaries/attributes.translation.json b/dictionaries/attributes.translation.json
index 3e6b7cbec5c9bb26c9a407ea3e6bb604b783b6e5..4b859cf4f704553397cf06e7340b85817b8b6a5b 100644
--- a/dictionaries/attributes.translation.json
+++ b/dictionaries/attributes.translation.json
@@ -566,6 +566,9 @@
 		"af": "Aanhoudende anonieme ID",
 		"el": "\u0391\u03b4\u03b9\u03b1\u03c6\u03b1\u03bd\u03ad\u03c2 \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 \u03bc\u03b1\u03ba\u03c1\u03ac\u03c2 \u03b4\u03b9\u03ac\u03c1\u03ba\u03b5\u03b9\u03b1\u03c2"
 	},
+	"attribute_pairwise_id": {
+		"de": "Service-spezifische pseudonyme ID bei der Heimorganisation"
+	},
 	"attribute_edupersonprincipalname": {
 		"no": "Personlig ID hos organisasjonen",
 		"nn": "Brukarnamn hos din organisasjon",
@@ -608,6 +611,9 @@
 		"zh-tw": "\u500b\u4eba\u7121\u6cd5\u91cd\u65b0\u8a2d\u7f6e\uff0c\u65bc\u6240\u5c6c\u7d44\u7e54\u7684\u6c38\u4e45\u533f\u540d ID",
 		"el": "\u039c\u03cc\u03bd\u03b9\u03bc\u03bf, \u03b1\u03b4\u03b9\u03b1\u03c6\u03b1\u03bd\u03ad\u03c2 \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7 \u03c3\u03c4\u03bf\u03bd \u03bf\u03b9\u03ba\u03b5\u03af\u03bf \u03bf\u03c1\u03b3\u03b1\u03bd\u03b9\u03c3\u03bc\u03cc"
 	},
+	"attribute_subject_id": {
+		"de": "Pseudonyme ID bei der Heimorganisation"
+	},
 	"attribute_edupersonorcid": {
 		"zh-tw": "ORCID \u7814\u7a76\u8005\u8b58\u5225\u78bc",
 		"el": "\u0391\u03bd\u03b1\u03b3\u03bd\u03c9\u03c1\u03b9\u03c3\u03c4\u03b9\u03ba\u03ac \u03b5\u03c1\u03b5\u03c5\u03bd\u03b7\u03c4\u03ae ORCID"
diff --git a/dictionaries/disco.translation.json b/dictionaries/disco.translation.json
index 8fea4c86f66085692a8be988c259f610109c63a4..6bdc2997250d8e38c39c433ae1796a8df68fe636 100644
--- a/dictionaries/disco.translation.json
+++ b/dictionaries/disco.translation.json
@@ -38,7 +38,7 @@
 		"no": "Vennligst velg hvilken identitetsleverand\u00f8r du vil bruke for \u00e5 logge inn:",
 		"nn": "Vel innloggingsteneste (IdP) der du \u00f8nskjer \u00e5 logga inn.",
 		"sv": "V\u00e4lj vilken identitetsleverant\u00f6r du vill logga in med:",
-		"es": "Por favor, seleccione el proveedor de identidad donde desea autenticarse",
+		"es": "Por favor, seleccione el proveedor de identidad que desea usar para autenticarse",
 		"fr": "S\u00e9lectionnez le fournisseur d'identit\u00e9 aupr\u00e8s duquel vous souhaitez vous authentifier :",
 		"de": "Bitte w\u00e4hlen Sie den Identity Provider, bei dem Sie sich authentifizieren m\u00f6chten:",
 		"nl": "Selecteer de Identity Provider waar je wil authenticeren:",
@@ -142,7 +142,7 @@
 	"icon_prefered_idp": {
 		"no": "[Foretrukket valg]",
 		"sv": "Prioriterat val",
-		"es": "[Opci\u00f3n preference]",
+		"es": "[Opci\u00f3n preferida]",
 		"de": "[Bevorzugte Auswahl]",
 		"nl": "[Voorkeurskeuze]",
 		"sl": "Prioritetna izbira",
@@ -177,7 +177,7 @@
 	"previous_auth": {
 		"no": "Du har tidligere valg \u00e5 autentisere deg hos",
 		"sv": "Du har  tidigare valt att logga in med",
-		"es": "Previamente solicit\u00f3 autenticarse en",
+		"es": "Previamente eligi\u00f3 autenticarse con",
 		"nl": "Je hebt eerder gekozen voor authenticatie bij",
 		"sl": "Predhodnje ste se prijavljali \u017ee pri",
 		"da": "Du har tidligere valgt at logge ind hos",
@@ -211,7 +211,7 @@
 	"login_at": {
 		"no": "Logg inn hos",
 		"sv": "Logga in med",
-		"es": "Identificarse en",
+		"es": "Iniciar sesi\u00f3n en",
 		"nl": "Inloggen bij",
 		"sl": "Prijavi se pri",
 		"da": "Login hos",
diff --git a/dictionaries/general.translation.json b/dictionaries/general.translation.json
index 8d36241bceeb72b1f361b8b5dd16728c77d57dad..b9c9cfb87724421b2bf56f35fa4e95dfb70f14e3 100644
--- a/dictionaries/general.translation.json
+++ b/dictionaries/general.translation.json
@@ -75,7 +75,7 @@
     "no": "Godta ogs\u00e5 for fremtiden",
     "nn": "Godta ogs\u00e5 for framtida",
     "sv": "Spara samtycke",
-    "es": "Recordar el consentimiento",
+    "es": "Recordar",
     "fr": "Se souvenir du consentement",
     "de": "Zustimmung merken",
     "nl": "Bewaar toestemming",
@@ -111,7 +111,7 @@
     "no": "Ja, fortsett",
     "nn": "Ja, fortsett",
     "sv": "Ja",
-    "es": "S\u00ed",
+    "es": "S\u00ed, continuar",
     "fr": "Oui",
     "de": "Ja, ich stimme zu",
     "nl": "Ja, ik ga akkoord",
@@ -147,7 +147,7 @@
     "no": "Nei, avbryt",
     "nn": "Nei, avbryt",
     "sv": "Nej",
-    "es": "No",
+    "es": "No, cancelar",
     "fr": "Non",
     "de": "Nein, ich stimme nicht zu",
     "nl": "Nee, ik weiger",
diff --git a/dictionaries/login.definition.json b/dictionaries/login.definition.json
index be3b12d4ed6dbd72db6a4b010b083652fc03074a..61e5dddf6c0179147997b37d6cac1c8cfea3acd7 100644
--- a/dictionaries/login.definition.json
+++ b/dictionaries/login.definition.json
@@ -1,68 +1,71 @@
 {
-	"error_header": {
-		"en": "Error"
-	},
-	"user_pass_header": {
-		"en": "Enter your username and password"
-	},
-	"user_pass_text": {
-		"en": "A service has requested you to authenticate yourself. Please enter your username and password in the form below."
-	},
-	"login_button": {
-		"en": "Login"
-	},
-	"processing": {
-		"en": "Processing..."
-	},
-	"username": {
-		"en": "Username"
-	},
-	"organization": {
-		"en": "Organization"
-	},
-	"password": {
-		"en": "Password"
-	},
-	"help_header": {
-		"en": "Help! I don't remember my password."
-	},
-	"help_text": {
-		"en": "Without your username and password you cannot authenticate yourself for access to the service. There may be someone that can help you. Consult the help desk at your organization!"
-	},
-	"error_nopassword": {
-		"en": "You sent something to the login page, but for some reason the password was not sent. Try again please."
-	},
-	"error_wrongpassword": {
-		"en": "Incorrect username or password."
-	},
-	"select_home_org": {
-		"en": "Choose your home organization"
-	},
-	"next": {
-		"en": "Next"
-	},
-	"change_home_org_title": {
-		"en": "Change your home organization"
-	},
-	"change_home_org_text": {
-		"en": "You have chosen <b>%HOMEORG%<\/b> as your home organization. If this is wrong you may choose another one."
-	},
-	"change_home_org_button": {
-		"en": "Choose home organization"
-	},
-	"help_desk_link": {
-		"en": "Help desk homepage"
-	},
-	"help_desk_email": {
-		"en": "Send e-mail to help desk"
-	},
-	"contact_info": {
-		"en": "Contact information:"
-	},
-	"remember_username": {
-		"en": "Remember my username"
-	},
+    "error_header": {
+        "en": "Error"
+    },
+    "user_pass_header": {
+        "en": "Enter your username and password"
+    },
+    "user_pass_text": {
+        "en": "A service has requested you to authenticate yourself. Please enter your username and password in the form below."
+    },
+    "login_button": {
+        "en": "Login"
+    },
+    "processing": {
+        "en": "Processing..."
+    },
+    "username": {
+        "en": "Username"
+    },
+    "organization": {
+        "en": "Organization"
+    },
+    "password": {
+        "en": "Password"
+    },
+    "help_header": {
+        "en": "Help! I don't remember my password."
+    },
+    "help_text": {
+        "en": "Without your username and password you cannot authenticate yourself for access to the service. There may be someone that can help you. Consult the help desk at your organization!"
+    },
+    "error_nopassword": {
+        "en": "You sent something to the login page, but for some reason the password was not sent. Try again please."
+    },
+    "error_wrongpassword": {
+        "en": "Incorrect username or password."
+    },
+    "select_home_org": {
+        "en": "Choose your home organization"
+    },
+    "next": {
+        "en": "Next"
+    },
+    "change_home_org_title": {
+        "en": "Change your home organization"
+    },
+    "change_home_org_text": {
+        "en": "You have chosen <b>%HOMEORG%<\/b> as your home organization. If this is wrong you may choose another one."
+    },
+    "change_home_org_button": {
+        "en": "Choose home organization"
+    },
+    "help_desk_link": {
+        "en": "Help desk homepage"
+    },
+    "help_desk_email": {
+        "en": "Send e-mail to help desk"
+    },
+    "contact_info": {
+        "en": "Contact information:"
+    },
+    "remember_username": {
+        "en": "Remember my username"
+    },
     "remember_me": {
         "en": "Remember me"
+    },
+    "remember_organization": {
+        "en": "Remember my organization"
     }
 }
diff --git a/dictionaries/login.translation.json b/dictionaries/login.translation.json
index ac03e326cc5ba2f484c0afd01e3bd552fcf57ebc..0ba81bb79287829f7dd041018fa6a8705bbad9fa 100644
--- a/dictionaries/login.translation.json
+++ b/dictionaries/login.translation.json
@@ -3,7 +3,7 @@
 		"no": "Feil",
 		"nn": "Feil",
 		"sv": "Fel",
-		"es": "Los datos que ha suministrado no son v\u00e1lidos",
+		"es": "Error",
 		"fr": "Erreur",
 		"de": "Fehler",
 		"nl": "Fout",
@@ -40,7 +40,7 @@
 		"no": "Skriv inn brukernavn og passord",
 		"nn": "Skriv inn brukarnamn og passord",
 		"sv": "Ange ditt anv\u00e4ndarnamn och l\u00f6senord",
-		"es": "Indique su nombre de usuario y clave de acceso",
+		"es": "Introduzca su nombre de usuario y contrase\u00f1a",
 		"fr": "Entrez votre identifiant et votre mot de passe",
 		"de": "Bitten geben Sie ihren Nutzernamen und Passwort ein",
 		"nl": "Geef je gebruikersnaam en wachtwoord",
@@ -77,7 +77,7 @@
 		"no": "En tjeneste har bedt om bekreftelse p\u00e5 din identitet. Skriv inn ditt brukernavn og passord for \u00e5 autentisere deg.",
 		"nn": "Ei webteneste har spurt etter autentisering av deg. Skriv inn brukarnamnet ditt og passordet ditt for \u00e5 autentisera deg.",
 		"sv": "En webbtj\u00e4nst har beg\u00e4rt att du ska logga in. Detta betyder att du beh\u00f6ver ange ditt anv\u00e4ndarnamn och ditt l\u00f6senord i formul\u00e4ret nedan.",
-		"es": "Un servicio solicita que se autentique. Esto significa que debe indicar su nombre de usuario y su clave de acceso en el siguiente formulario.",
+		"es": "Un servicio solicita que se autentique. Por favor, introduzca su nombre de usuario y contrase\u00f1a en el siguiente formulario.",
 		"fr": "Un service a demand\u00e9 \u00e0 ce que vous vous authentifiez.  Cela signifie que vous devez entrer votre identifiant et votre mot de passe dans le formulaire ci-dessous.",
 		"de": "Um diesen Dienst zu nutzen, m\u00fcssen Sie sich authentifizieren. Bitte geben sie daher unten Nutzernamen und Passwort ein.",
 		"nl": "Voor deze dienst is authenticatie vereist. Geef je gebruikersnaam en wachtwoord in onderstaand formulier.",
@@ -113,7 +113,7 @@
 		"no": "Logg inn",
 		"nn": "Logg inn",
 		"sv": "Logga in",
-		"es": "Login",
+		"es": "Iniciar sesi\u00f3n",
 		"fr": "S'identifier",
 		"de": "Anmelden",
 		"nl": "Inloggen",
@@ -148,6 +148,7 @@
 		"el": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2"
 	},
 	"processing": {
+		"es": "Procesando...",
 		"zh-tw": "\u8655\u7406\u4e2d..."
 	},
 	"username": {
@@ -230,7 +231,7 @@
 		"no": "Passord",
 		"nn": "Passord",
 		"sv": "L\u00f6senord",
-		"es": "Clave de acceso",
+		"es": "Contrase\u00f1a",
 		"fr": "Mot de passe",
 		"de": "Passwort",
 		"nl": "Wachtwoord",
@@ -268,7 +269,7 @@
 		"no": "Hjelp! Jeg har glemt passordet mitt.",
 		"nn": "Hjelp! Eg har gl\u00f8ymd passordet mitt",
 		"sv": "Hj\u00e4lp! Jag kommer inte ih\u00e5g mitt l\u00f6senord.",
-		"es": "&iexcl;Socorro! Se me ha olvidado mi clave de acceso.",
+		"es": "\u00a1Ayuda! Se me ha olvidado la contrase\u00f1a.",
 		"fr": "\u00c0 l'aide!  Je ne me souviens plus de mon mot de passe.",
 		"de": "Hilfe, ich habe mein Passwort vergessen.",
 		"nl": "Help! Ik weet mijn wachtwoord niet meer.",
@@ -304,7 +305,7 @@
 		"no": "Synd! - Uten riktig brukernavn og passord kan du ikke autentisere deg. Det kan v\u00e6re noen som kan hjelpe deg. Fors\u00f8k \u00e5 kontakt brukerst\u00f8tte ved din vertsorganisasjon.",
 		"nn": "Synd! - Utan riktig brukarnamn og passord kan du ikkje autentisera deg.  Ta kontakt med brukarst\u00f8tte hos din organisasjon.",
 		"sv": "Tyv\u00e4rr kan du inte logga in i tj\u00e4nsten om du inte har ditt anv\u00e4ndarnamn och ditt l\u00f6senord. Ta kontakt med din organisations support eller helpdesk f\u00f6r att f\u00e5 hj\u00e4lp.",
-		"es": "&iexcl;Muy mal! - Sin su nombre de usuario y su clave de acceso usted no se puede identificar y acceder al servicio. A lo mejor hay alguien que puede ayudarle. &iexcl;P&oacute;ngase en contacto con el centro de ayuda de su universidad!",
+		"es": "Sin su nombre de usuario y contrase\u00f1a no se puede identificar y acceder al servicio. Quiz\u00e1s haya alguien que pueda ayudarle. \u00a1Contacte con el centro de atenci\u00f3n al usuario de su organizaci\u00f3n!",
 		"fr": "Pas de chance! Sans votre identifiant et votre mot de passe vous ne pouvez pas vous authentifier et acc\u00e9der au service. Il y a peut-\u00eatre quelqu'un pour vous aider.  Contactez le help desk de votre universit\u00e9!",
 		"de": "Tut uns leid - Ohne Nutzername und Passwort k\u00f6nnen Sie sich nicht authentifizieren und somit den Dienst nicht nutzen. M\u00f6glicherweise kann ihnen jemand helfen, kontaktieren Sie dazu den Helpdesk ihrer Einrichtung.",
 		"nl": "Zonder je gebruikersnaam en wachtwoord kun je je niet authenticeren en dus niet gebruikmaken van deze dienst.",
@@ -340,7 +341,7 @@
 		"no": "Du kontaktet loginsiden, men passordet ble ikke sendt med. Fors\u00f8k igjen.",
 		"nn": "Passordet blei ikkje sendt. Pr\u00f8v p\u00e5 nytt.",
 		"sv": "Du skicka in en inloggningsf\u00f6rfr\u00e5gan men det verkar som om ditt l\u00f6senord inte fanns med i f\u00f6rfr\u00e5gan. F\u00f6rs\u00f6k igen!",
-		"es": "Usted envi\u00f3 algo a la p\u00e1gina de acceso pero, por alg\u00fan motivo, la clave no fue enviada. Int\u00e9ntelo de nuevo, por favor.",
+		"es": "Usted envi\u00f3 algo a la p\u00e1gina de acceso pero, por alguna raz\u00f3n, no se envi\u00f3 la contrase\u00f1a. Int\u00e9ntelo de nuevo, por favor.",
 		"fr": "Vous avez envoy\u00e9 quelque chose sur la page d'identification mais pour une raison inconnue votre mot de passe n'a pas \u00e9t\u00e9 transmis. Veuillez r\u00e9essayer.",
 		"de": "Sie haben etwas an die Anmeldeseite geschickt, aber aus irgendeinem Grund ist das Passwort nicht \u00fcbermittelt worden. Bitte versuchen Sie es erneut.",
 		"nl": "Je hebt wel iets ingetikt, maar blijkbaar is je wachtwoord niet verstuurd. Probeer het opnieuw AUB.",
@@ -376,7 +377,7 @@
 		"no": "Feil brukernavn eller passord.",
 		"nn": "Feil brukarnamn eller passord.",
 		"sv": "Fel anv\u00e4ndarnamn eller l\u00f6senord.",
-		"es": "Nombre de usuario o contrase\u00f1a err\u00f3neos",
+		"es": "Nombre de usuario o contrase\u00f1a incorrectos",
 		"fr": "Mauvais identifiant ou mot de passe.",
 		"de": "Falscher Nutzername oder Passwort.",
 		"nl": "Gebruikersnaam of wachtwoord niet bekend.",
@@ -449,7 +450,7 @@
 		"no": "Velg vertsorganisasjon",
 		"nn": "Vel vertsorganisasjon",
 		"sv": "V\u00e4lj vilken organisation du kommer ifr\u00e5n",
-		"es": "Seleccione su organizaci\u00f3n origen",
+		"es": "Seleccione su organizaci\u00f3n de origen",
 		"fr": "Choisissez votre fournisseur.",
 		"de": "W\u00e4hlen sie die Einrichtung, von der Sie ihre Zugangsdaten beziehen",
 		"nl": "Kies je organisatie",
@@ -484,7 +485,7 @@
 		"no": "Endre din vertsorganisasjon",
 		"nn": "Endra vertsorganisasjon",
 		"sv": "\u00c4ndra vilken organisation du kommer ifr\u00e5n",
-		"es": "Cambiar su organizaci\u00f3n origen",
+		"es": "Cambiar la organizaci\u00f3n de origen",
 		"fr": "Changez votre fournisseur",
 		"de": "Eine andere Einrichtung, von der Sie Zugangsdaten erhalten, ausw\u00e4hlen",
 		"nl": "Verander je organisatie",
@@ -519,7 +520,7 @@
 		"no": "Du har valgt <b>%HOMEORG%<\/b> som din vertsorganisasjon. Dersom dette er feil kan du velge en annen.",
 		"nn": "Du har vald <b>%HOMEORG%<\/b> som din vertsorganisasjon.  Dersom dette er feil, kan du velja ein annan organisasjon fr\u00e5 menyen.",
 		"sv": "Du har valt <b>%HOMEORG%<\/b> som organisation du kommer ifr\u00e5n. Om detta \u00e4r fel s\u00e5 kan du v\u00e4lja en annan.",
-		"es": "Ha seleccionado <b>%HOMEORG%<\/b> como organizaci\u00f3n origen. Si esta informaci\u00f3n es incorrecta puede seleccionar otra.",
+		"es": "Ha seleccionado <b>%HOMEORG%<\/b> como organizaci\u00f3n de origen. Si esta informaci\u00f3n es incorrecta, puede seleccionar otra.",
 		"fr": "Vous avez choisi <b>%HOMEORG%<\/b> comme votre fournisseur. Si ce n'est pas correct, vous pouvez le changer.",
 		"de": "Sie haben <b>%HOMEORG%<\/b> als ihre Einrichtung gew\u00e4hlt, k\u00f6nnen diese Auswahl aber noch \u00e4ndern.",
 		"nl": "Je hebt <b>%HOMEORG%<\/b> gekozen als je organisatie. Als dit niet correct is kun je een andere keuze maken.",
@@ -554,7 +555,7 @@
 		"no": "Velg vertsorganisasjon",
 		"nn": "Vel vertsorganisasjon",
 		"sv": "\u00c4ndra organisation",
-		"es": "Seleccionar la organizaci\u00f3n origen",
+		"es": "Seleccione su organizaci\u00f3n de origen",
 		"fr": "Choisissez votre fournisseur.",
 		"de": "Einrichtung ausw\u00e4hlen",
 		"nl": "Kies je organisatie",
@@ -589,7 +590,7 @@
 		"no": "Hjemmesiden til brukerst\u00f8tte",
 		"nn": "Heimeside for brukarst\u00f8tte",
 		"sv": "Hemsida f\u00f6r helpdesk",
-		"es": "P\u00e1gina de soporte t\u00e9cnico",
+		"es": "P\u00e1gina del centro de atenci\u00f3n al usuario",
 		"fr": "Page web de l'assistance technique",
 		"de": "Seite des Helpdesk",
 		"nl": "Helpdesk homepage",
@@ -624,7 +625,7 @@
 		"no": "Send e-post til brukerst\u00f8tte",
 		"nn": "Send epost til brukarst\u00f8tte",
 		"sv": "Skicka e-post till helpdesk",
-		"es": "Enviar correo electr\u00f3nico al soporte t\u00e9cnico",
+		"es": "Enviar correo electr\u00f3nico al centro de atenci\u00f3n al usuario",
 		"fr": "Assistance technique par courriel",
 		"de": "Email an den Helpdesk senden",
 		"nl": "Stuur een e-mail naar de helpdesk",
diff --git a/dictionaries/logout.translation.json b/dictionaries/logout.translation.json
index dd7e2ead5e218163061b0da4104bf418b41e31dd..8cfb40d2a8e01a10861a5bf92f1c8a477a23e437 100644
--- a/dictionaries/logout.translation.json
+++ b/dictionaries/logout.translation.json
@@ -3,7 +3,7 @@
 		"no": "Utlogget",
 		"nn": "Utlogga",
 		"sv": "Utloggad",
-		"es": "Desconectado",
+		"es": "SesiĂłn cerrada",
 		"fr": "D\u00e9connect\u00e9",
 		"de": "Abgemeldet",
 		"nl": "Uitgelogd",
@@ -38,7 +38,7 @@
 		"no": "Du er n\u00e5 utlogget.",
 		"nn": "Du har blitt logga ut.  Takk for at du brukte denne tenesta.",
 		"sv": "Du har blivit uloggad. Tack f\u00f6r att du anv\u00e4nde denna tj\u00e4nst.",
-		"es": "Ha sido desconectado. Gracias por usar este servicio.",
+		"es": "Se ha cerrado la sesiĂłn.",
 		"fr": "Vous avez \u00e9t\u00e9 d\u00e9connect\u00e9. Merci d'avoir utilis\u00e9 ce service.",
 		"de": "Sie wurden abgemeldet. Danke, dass Sie diesen Dienst verwendet haben.",
 		"nl": "U bent uitgelogd. Dank u voor het gebruiken van deze dienst.",
@@ -178,7 +178,7 @@
 		"no": "Logger ut...",
 		"nn": "Loggar ut...",
 		"sv": "Loggar ut...",
-		"es": "Desconectando...",
+		"es": "Cerrando la sesi\u00f3n...",
 		"fr": "D\u00e9connexion...",
 		"de": "Abmeldung l\u00e4uft...",
 		"nl": "Uitloggen...",
@@ -213,7 +213,7 @@
 		"no": "Utlogging feilet",
 		"nn": "Utlogging feila",
 		"sv": "Utloggning misslyckades",
-		"es": "Proceso de desconexi\u00f3n fallido",
+		"es": "El cierre de sesi\u00f3n ha fallado",
 		"fr": "\u00c9chec de la d\u00e9connexion",
 		"de": "Abmeldung fehlgeschlagen",
 		"nl": "Uitloggen mislukt",
@@ -283,7 +283,7 @@
 		"no": "Du har n&aring; logget ut fra alle tjenestene listet ovenfor.",
 		"nn": "Du er ferdig utlogga fr\u00e5 alle tenestene",
 		"sv": "Du har loggat ut fr\u00e5n alla nedanst\u00e5ende tj\u00e4nster.",
-		"es": "Ha sido correctamente desconectado de todo los servicios listados a continuaci\u00f3n",
+		"es": "Ha cerrado las sesiones de todos los servicios listados m\u00e1s arriba",
 		"fr": "Vous avez \u00e9t\u00e9 d\u00e9connect\u00e9 avec succ\u00e8s des services list\u00e9s ci dessus",
 		"de": "Sie haben sich erfolgreich von allen obenstehenden Diensten abgemeldet.",
 		"nl": "Je bent succesvol uitgelogd van de bovenvermelde services.",
@@ -318,7 +318,7 @@
 		"no": "Du er n\u00e5 logget ut fra %SP%.",
 		"nn": "Du er ferdig utlogga fr\u00e5 %SP%.",
 		"sv": "Du har nu loggat ut fr\u00e5n %SP%.",
-		"es": "Ha sido desconectado correctamente de %SP%.",
+		"es": "Ha cerrado correctamente la sesiĂłn en %SP%.",
 		"fr": "Vous avez \u00e9t\u00e9 d\u00e9connect\u00e9 de %SP%.",
 		"de": "Sie wurden nun erfolgreich von %SP% abgemeldet",
 		"nl": "Je bent nu succesvol uitgelogd van %SP%.",
@@ -388,7 +388,7 @@
 		"no": "Vil du logge ut fra alle tjenestene ovenfor?",
 		"nn": "Vil du logga ut fr\u00e5 alle tenestene?",
 		"sv": "Vill du logga ut fr\u00e5n alla ovanst\u00e5ende tj\u00e4nster?",
-		"es": "\u00bfDesea desconectarse de todos los servicios que se muestran m\u00e1s arriba?",
+		"es": "\u00bfDesea cerrar las sesiones de todos los servicios que se muestran m\u00e1s arriba?",
 		"fr": "Voulez vous r\u00e9ellement terminer les connexions \u00e0 tout ces services?",
 		"de": "Wollen Sie sich von allen obenstehenden Diensten abmelden?",
 		"nl": "Wil je uitloggen van alle bovenvermelde diensten?",
@@ -423,7 +423,7 @@
 		"no": "Ja, alle tjenestene over",
 		"nn": "Ja, logg ut fr\u00e5 alle",
 		"sv": "Ja, alla tj\u00e4nster",
-		"es": "Si, todos los servicios",
+		"es": "S\u00ed, de todos los servicios",
 		"fr": "Oui, de tous les services",
 		"de": "Ja, alle Dienste",
 		"nl": "Ja, alle diensten",
@@ -458,7 +458,7 @@
 		"no": "Nei, bare %SP%",
 		"nn": "Nei, logg berre ut fr\u00e5 %SP%",
 		"sv": "Nej, endast %SP%",
-		"es": "No, s\u00f3lo %SPS",
+		"es": "No, s\u00f3lo de %SP%",
 		"fr": "Non, seulement de %SP%",
 		"de": "Nein, nur %SP%",
 		"nl": "Nee, alleen %SP%",
@@ -493,7 +493,7 @@
 		"no": "En eller flere av tjenestene du er logget inn p\u00e5 <i>st\u00f8tter ikke logout<\/i>. Lukk nettleseren, dersom du \u00f8nsker \u00e5 logge ut fra disse tjenestene.",
 		"nn": "Ei eller fleire av tenestene du er innlogga p\u00e5 <i>st\u00f8tter ikkje utlogging<\/i>.  Lukk weblesaren din for \u00e5 sikra at alle sesjonar blir lukka",
 		"sv": "En eller flera av tj\u00e4nsterna du \u00e4r inloggad i <i>kan inte hantera utloggning<\/i>. F\u00f6r att s\u00e4kerst\u00e4lla att du inte l\u00e4ngre \u00e4r inloggad i n\u00e5gon tj\u00e4nst ska du <i>st\u00e4nga din webbl\u00e4sare<\/i>.",
-		"es": "Uno o m\u00e1s de los servicios en los que est\u00e1 autenticado <i>no permite desconexi\u00f3n<\/i>. Para asegurarse de que todas sus sesiones se cierran, se le recomienda que <i>cierre todas las ventanas de su navegador<\/i>.",
+		"es": "Uno o m\u00e1s de los servicios en los que est\u00e1 autenticado <i>no permite desconexi\u00f3n<\/i>. Para asegurarse de que todas sus sesiones se cierran, se le recomienda que <i>cierre su navegador<\/i>.",
 		"fr": "Un ou plusieurs des services auxquels vous \u00eates connect\u00e9 <i>ne g\u00e8rent pas la d\u00e9connexion<\/i>. Pour terminer les sessions sur ces services, vous devrez <i>fermer votre navigateur<\/i>.",
 		"de": "Einer oder mehrere Dienste an denen Sie angemeldet sind, <i>unterst\u00fctzen keine Abmeldung<\/i>. Um sicherzustellen, dass Sie abgemeldet sind, <i>schlie\u00dfen Sie bitte Ihren Webbrowser<\/i>.",
 		"nl": "Een of meer diensten waarop je bent inlogd hebben <i>geen ondersteuning voor uitloggen<\/i>. Om er zeker van te zijn dat al je sessies zijn be\u00ebindigd, kun je het beste <i>je webbrowser afsluiten<\/i>.",
@@ -571,7 +571,7 @@
 		"fr": "D\u00e9connexion des services suivants :",
 		"lt": "Vyksta atjungimas nuo \u0161i\u0173 paslaug\u0173:",
 		"it": "Disconnessione in corso dai seguenti servizi:",
-		"es": "Desconectarse de los siguientes servicios:",
+		"es": "Cerrando las sesiones de los siguientes servicios:",
 		"hu": "Kil\u00e9p\u00e9s az al\u00e1bbi szolg\u00e1ltat\u00e1sokb\u00f3l:",
 		"ja": "\u4ee5\u4e0b\u306e\u30b5\u30fc\u30d3\u30b9\u304b\u3089\u30ed\u30b0\u30a2\u30a6\u30c8\u3057\u307e\u3057\u305f:",
 		"nl": "Uitloggen van de volgende diensten:",
@@ -605,7 +605,7 @@
 		"fr": "Impossible de se d\u00e9connecter d'un ou plusieurs services. Pour \u00eatre certain de clore vos sessions, il vous est recommand\u00e9 de <i>fermer votre navigateur<\/i>.",
 		"lt": "Nepavyksta atsijungti nuo vienos ar daugiau paslaug\u0173. Siekiant u\u017etikrinti s\u0117kming\u0105 darbo pabaig\u0105, rekomenduojame <i>u\u017edaryti nar\u0161ykl\u0119<\/i>.",
 		"it": "Impossibile disconnettersi da uno o pi\u00f9 servizi. Per assicurarsi di chiudere tutte le sessioni si consiglia di <i>chiudere il browser<\/i>",
-		"es": "Imposible desconectarse de uno o m\u00e1s servicios. Para asegurar que todas sus sesiones han sido cerradas, se recomienda que <i>cierre su navegador web<\/i>.",
+		"es": "No fue posible desconectarse de uno o m\u00e1s servicios. Para garantizar que todas sus sesiones han sido cerradas, se recomienda que <i>cierre su navegador web<\/i>.",
 		"hu": "Legal\u00e1bb egy szolg\u00e1ltat\u00e1sb\u00f3l nem siker\u00fclt kil\u00e9pni. Ahhoz, hogy biztosan lez\u00e1rja a megkezdett munkamenetet, k\u00e9rj\u00fck, <i>z\u00e1rja be b\u00f6ng\u00e9sz\u0151j\u00e9t<\/i>.",
 		"ja": "\u4e00\u3064\u4ee5\u4e0a\u306e\u30b5\u30fc\u30d3\u30b9\u304b\u305f\u30ed\u30b0\u30a2\u30a6\u30c8\u51fa\u6765\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u78ba\u5b9f\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u7d42\u4e86\u3055\u305b\u308b\u306b\u306f\u3001<i>WEB\u30d6\u30e9\u30a6\u30b6\u3092\u9589\u3058\u308b<\/i>\u4e8b\u3092\u63a8\u5968\u3057\u307e\u3059\u3002",
 		"nl": "Het was niet mogelijk bij een of meerdere diensten uit te loggen. Om alle sessies te sluiten, raden wij u aan uw <i>webbrowser te af te sluiten<\/i>.",
diff --git a/dictionaries/status.definition.json b/dictionaries/status.definition.json
index 57030aaab4db1ee8fb8ce483d492548e2b83ed39..a82c97fcbe51e94ed24241089cac7efe86b9a226 100644
--- a/dictionaries/status.definition.json
+++ b/dictionaries/status.definition.json
@@ -37,5 +37,11 @@
 	},
 	"logout": {
 		"en": "Logout"
+	},
+	"authData_header": {
+		"en": "AuthData"
+	},
+	"authData_summary": {
+		"en": "Click to view AuthData"
 	}
 }
diff --git a/docs/index.md b/docs/index.md
index 8bb3cea2220587b33c7e990cb242a027614953f2..32674dbeded788fb9693d4d5b5a9f36b81609db9 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -2,6 +2,7 @@ SimpleSAMLphp Documentation
 ===========================
 
  * [Installing SimpleSAMLphp](simplesamlphp-install)
+    * [Upgrade notes for version 1.16](simplesamlphp-upgrade-notes-1.16)
     * [Upgrade notes for version 1.15](simplesamlphp-upgrade-notes-1.15)
     * [Upgrade notes for version 1.14](simplesamlphp-upgrade-notes-1.14)
     * [Upgrade notes for version 1.13](simplesamlphp-upgrade-notes-1.13)
@@ -18,7 +19,6 @@ SimpleSAMLphp Documentation
  * [Using SimpleSAMLphp as a SAML Service Provider](simplesamlphp-sp)
   * [Hosted SP Configuration Reference](./saml:sp)
   * [IdP remote reference](simplesamlphp-reference-idp-remote)
-  * [Upgrading - migration to use the SAML authentication source](simplesamlphp-sp-migration)
   * [Configuring HTTP-Artifact](./simplesamlphp-artifact-sp)
   * [Using scoping](./simplesamlphp-scoping)
   * [Holder-of-Key profile](simplesamlphp-hok-sp)
diff --git a/docs/simplesamlphp-advancedfeatures.md b/docs/simplesamlphp-advancedfeatures.md
index 71abf8f56072b624191d758697b6f1bbe314f520..a1ee444dd36a5da77d1f6e681b21999a94ec7cad 100644
--- a/docs/simplesamlphp-advancedfeatures.md
+++ b/docs/simplesamlphp-advancedfeatures.md
@@ -41,9 +41,9 @@ In `metadata/saml20-idp-hosted.php`:
 
 In `config/authsources.php`:
 
-    'default-sp' => array(
+    'default-sp' => [
         'saml:SP',
-    ),
+    ],
 
 
 
@@ -93,11 +93,12 @@ SimpleSAMLphp supports signing of the metadata it generates. Metadata signing is
 - `metadata.sign.privatekey`: Name of the file with the private key which should be used to sign the metadata. This file must exist in in the `cert` directory.
 - `metadata.sign.privatekey_pass`: Passphrase which should be used to open the private key. This parameter is optional, and should be left out if the private key is unencrypted.
 - `metadata.sign.certificate`: Name of the file with the certificate which matches the private key. This file must exist in in the `cert` directory.
-- `metadata.sign.algorithm`: The algorithm to use when signing metadata for this entity. Defaults to RSA-SHA1. Possible values:
+- `metadata.sign.algorithm`: The algorithm to use when signing metadata for this entity. Defaults to RSA-SHA256. Possible values:
 
     * `http://www.w3.org/2000/09/xmldsig#rsa-sha1`
        *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
+      The default.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384`
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`
 
@@ -126,7 +127,7 @@ Example code for the function with GeoIP country check:
         }
 
         if ($init) {
-            $session->setData($data_type, $data_key, $remote_addr, SimpleSAML_Session::DATA_TIMEOUT_SESSION_END);
+            $session->setData($data_type, $data_key, $remote_addr, \SimpleSAML\Session::DATA_TIMEOUT_SESSION_END);
             return;
         }
 
@@ -146,7 +147,7 @@ Example code for the function with GeoIP country check:
 
         if ($country_a === $country_b) {
             if ($stored_remote_addr !== $remote_addr) {
-                $session->setData($data_type, $data_key, $remote_addr, SimpleSAML_Session::DATA_TIMEOUT_SESSION_END);
+                $session->setData($data_type, $data_key, $remote_addr, \SimpleSAML\Session::DATA_TIMEOUT_SESSION_END);
             }
 
             return TRUE;
diff --git a/docs/simplesamlphp-artifact-idp.md b/docs/simplesamlphp-artifact-idp.md
index 4db281c494f8559efe058dfda9560b4cf6fb2aab..fcbf0079d1f36c43bf1bca98cbd1d547cabe747b 100644
--- a/docs/simplesamlphp-artifact-idp.md
+++ b/docs/simplesamlphp-artifact-idp.md
@@ -26,7 +26,7 @@ The default configuration on Debian is for the memcache server to be accessible
 
 
 Once the memcache server is configured, you can configure simplesamlphp to use it to store sessions.
-You can do this by setting the `session.handler` option in `config.php` to `memcache`.
+You can do this by setting the `store.type` option in `config.php` to `memcache`.
 If you are running memcache on a different server than the IdP, you must also change the `memcache_store.servers` option in `config.php`.
 
 
@@ -35,11 +35,11 @@ Enabling artifact on the IdP
 
 To enable the IdP to send artifacts, you must add the `saml20.sendartifact` option to the `saml20-idp-hosted` metadata file:
 
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         [....]
         'auth' => 'example-userpass',
         'saml20.sendartifact' => TRUE,
-    );
+    ];
 
 
 Add new metadata to SPs
@@ -49,13 +49,13 @@ After enabling the Artifact binding, your IdP metadata will change to add a Arti
 You therefore need to update the metadata for your IdP at your SPs.
 `saml20-idp-remote` metadata for SimpleSAMLphp SPs should contain something like:
 
-    'ArtifactResolutionService' => array(
-        array(
+    'ArtifactResolutionService' => [
+        [
             'index' => 0,
             'Location' => 'https://idp.example.org/simplesaml/saml2/idp/ArtifactResolutionService.php',
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP',
-        ),
-    ),
+        ],
+    ],
 
 
 SP metadata on the IdP
@@ -66,16 +66,16 @@ This means that you must use the complex endpoint format in `saml20-sp-remote` m
 In general, that should look something like:
 
     'AssertionConsumerService' => array (
-        array(
+        [
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
             'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
             'index' => 0,
-        ),
-        array(
+        ],
+        [
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
             'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
             'index' => 2,
-        ),
+        ],
     ),
 
 (The specific values of the various fields will vary depending on the SP.)
@@ -89,9 +89,9 @@ You may therefore have to add the webserver certificate to the metadata that you
 To do this, you need to set the `https.certificate` option in the `saml20-idp-hosted` metadata file.
 That option should refer to a file containing the webserver certificate.
 
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         [....]
         'auth' => 'example-userpass',
         'saml20.sendartifact' => TRUE,
         'https.certificate' => '/etc/apache2/webserver.crt',
-    );
+    ];
diff --git a/docs/simplesamlphp-artifact-sp.md b/docs/simplesamlphp-artifact-sp.md
index 6b18119ce8ab464b71959fee98c0a88d26f4a2cf..7571454e611061fcfde9e06300d3282b47b10357 100644
--- a/docs/simplesamlphp-artifact-sp.md
+++ b/docs/simplesamlphp-artifact-sp.md
@@ -19,11 +19,11 @@ When this is done, you can add the metadata of your SP to the IdP, and test the
 Example configuration
 ---------------------
 
-    'artifact-sp' => array(
+    'artifact-sp' => [
         'saml:SP',
         'ProtocolBinding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
         'privatekey' => 'sp.example.org.pem',
         'certificate' => 'sp.example.org.crt',
-    ),
+    ],
 
 See the [SP configuration reference](./saml:sp) for a description of the options.
diff --git a/docs/simplesamlphp-authproc.md b/docs/simplesamlphp-authproc.md
index 3b5408396591d39cd06adecee368ee4d610d9848..d66762e4bb0487265cb13bed7b220c564d001348 100644
--- a/docs/simplesamlphp-authproc.md
+++ b/docs/simplesamlphp-authproc.md
@@ -44,24 +44,24 @@ How to configure Auth Proc Filters
 
 The configuration of *Auth Proc Filters* is a list of filters with priority as *index*. Here is an example of *Auth Proc Filters* configured in `config.php`:
 
-	'authproc.idp' => array(
-		10 => array(
+	'authproc.idp' => [
+		10 => [
 			'class' => 'core:AttributeMap', 
 			'addurnprefix'
-		),
+		],
 		20 => 'core:TargetedID',
 		50 => 'core:AttributeLimit',
-		90 => array(
+		90 => [
 			'class' 	=> 'consent:Consent', 
 			'store' 	=> 'consent:Cookie', 
 			'focus' 	=> 'yes', 
 			'checked' 	=> TRUE
-		),
-	),
+		],
+	],
 
 This configuration will execute *Auth Proc Filters* one by one, with the priority value in increasing order. When *Auth Proc Filters* is configured in multiple places, in example both globally, in the hosted IdP and remote SP metadata, then the list is interleaved sorted by priority.
 
-The most important parameter of each item on the list is the *class* of the *Auth Proc Filter*. The syntax of the class is `modulename:classname`. As an example the class definition `core:AttributeLimit` will be expanded to look for the class `sspmod_core_Auth_Process_AttributeLimit`. The location of this class file *must* then be: `modules/core/lib/Auth/Process/AttributeLimit.php`.
+The most important parameter of each item on the list is the *class* of the *Auth Proc Filter*. The syntax of the class is `modulename:classname`. As an example the class definition `core:AttributeLimit` will be expanded to look for the class `\SimpleSAML\Module\core\Auth\Process\AttributeLimit`. The location of this class file *must* then be: `modules/core/lib/Auth/Process/AttributeLimit.php`.
 
 You will see that a bunch of useful filters is included in the `core` module. In addition the `consent` module that is included in the SimpleSAMLphp distribution implements a filter. Beyond that, you are encouraged to create your own filters and share with the community. If you have created a cool *Auth Proc Filter* that does something useful, let us know, and we may share it on the [SimpleSAMLphp web site][].
 
@@ -73,18 +73,18 @@ When you know the class definition of a filter, and the priority, the simple way
 
 This is analogous to:
 
-	20 => array(
+	20 => [
 		'class' => 'core:TargetedID'
-	),
+	],
 
 Some *Auth Proc Filters* have optional or required *parameters*. To send parameters to *Auth Proc Filters*, you need to choose the second of the two alernatives above. Here is an example of provided parameters to the consent module:
 
-	90 => array(
+	90 => [
 		'class' 	=> 'consent:Consent', 
 		'store' 	=> 'consent:Cookie', 
 		'focus' 	=> 'yes', 
 		'checked' 	=> TRUE
-	),
+	],
 
 
 ### Filters in `config.php`
@@ -105,15 +105,15 @@ The filters in `authproc.sp` will be executed at the SP side regardless of which
 
 Filters can be added both in `hosted` and `remote` metadata. Here is an example of a filter added in a metadata file:
 
-	'__DYNAMIC:1__' => array(
+	'__DYNAMIC:1__' => [
 		'host'				=>	'__DEFAULT_',
 		'privatekey'		=>	'example.org.pem',
 		'certificate'		=>	'example.org.crt',
 		'auth'				=>	'feide',
-		'authproc' => array(
+		'authproc' => [
 			40 => 'preprodwarning:Warning',
-		),
-	)
+		],
+	]
 
 The example above is in `saml20-idp-hosted`.
 
@@ -132,6 +132,8 @@ The following filters are included in the SimpleSAMLphp distribution:
 - [`core:AttributeLimit`](./core:authproc_attributelimit): Limit the attributes in the response.
 - [`core:AttributeMap`](./core:authproc_attributemap): Change the name of the attributes.
 - [`core:AttributeRealm`](./core:authproc_attributerealm): (deprecated) Create an attribute with the realm of the user.
+- [`core:Cardinality`](./core:authproc_cardinality): Ensure the number of attribute values is within the specified multiplicity.
+- [`core:CardinalitySingle`](./core:authproc_cardinalitysingle): Ensure the correct cardinality of single-valued attributes.
 - [`core:GenerateGroups`](./core:authproc_generategroups): Generate a `group` attribute for the user.
 - [`core:LanguageAdaptor`](./core:authproc_languageadaptor): Transfering language setting from IdP to SP.
 - [`core:PHP`](./core:authproc_php): Modify attributes with custom PHP code.
@@ -143,6 +145,7 @@ The following filters are included in the SimpleSAMLphp distribution:
 - [`expirycheck:ExpiryDate`](./expirycheck:expirycheck): Block access to accounts that have expired.
 - [`preprodwarning:Warning`](./preprodwarning:warning): Warn the user about accessing a test IdP.
 - [`saml:AttributeNameID`](./saml:nameid): Generate custom NameID with the value of an attribute.
+- [`saml:AuthnContextClassRef`](./saml:authproc_authncontextclassref): Set the authentication context in the response.
 - [`saml:ExpectedAuthnContextClassRef`](./saml:authproc_expectedauthncontextclassref): Verify the user's authentication context.
 - [`saml:FilterScopes`](./saml:filterscopes): Filter attribute values with scopes forbidden for an IdP.
 - [`saml:NameIDAttribute`](./saml:nameidattribute): Create an attribute based on the NameID we receive from the IdP.
@@ -160,16 +163,16 @@ Writing your own Auth Proc Filter
 
 Look at the included *Auth Proc Filters* as examples. Copy the classes into your own module and start playing around.
 
-Authentication processing filters are created by creating a class under `Auth/Process/` in a module. This class is expected to subclass `SimpleSAML_Auth_ProcessingFilter`. A filter must implement at least one function - the `process(&$request)`-function. This function can access the `$request`-array to add, delete and modify attributes, and can also do more advanced processing based on the SP/IdP metadata (which is also included in the `$request`-array). When this function returns, it is assumed that the filter has finished processing.
+Authentication processing filters are created by creating a class under `Auth/Process/` in a module. This class is expected to subclass `\SimpleSAML\Auth\ProcessingFilter`. A filter must implement at least one function - the `process(&$request)`-function. This function can access the `$request`-array to add, delete and modify attributes, and can also do more advanced processing based on the SP/IdP metadata (which is also included in the `$request`-array). When this function returns, it is assumed that the filter has finished processing.
 
-If a filter for some reason needs to redirect the user, for example to show a web page, it should save the current request. Upon completion it should retrieve the request, update it with the changes it is going to make, and call `SimpleSAML_Auth_ProcessingChain::resumeProcessing`. This function will continue processing the next configured filter.
+If a filter for some reason needs to redirect the user, for example to show a web page, it should save the current request. Upon completion it should retrieve the request, update it with the changes it is going to make, and call `\SimpleSAML\Auth\ProcessingChain::resumeProcessing`. This function will continue processing the next configured filter.
 
 Requirements for authentication processing filters:
 
- - Must be derived from the `SimpleSAML_Auth_ProcessingFilter`-class.
+ - Must be derived from the `\SimpleSAML\Auth\ProcessingFilter`-class.
  - If a constructor is implemented, it must first call the parent constructor, passing along all parameters, before accessing any of the parameters. In general, only the $config parameter should be accessed.
  - The `process(&$request)`-function must be implemented. If this function completes, it is assumed that processing is completed, and that the $request array has been updated.
- - If the `process`-function does not return, it must at a later time call `SimpleSAML_Auth_ProcessingChain::resumeProcessing` with the new request state. The request state must be an update of the array passed to the `process`-function.
+ - If the `process`-function does not return, it must at a later time call `\SimpleSAML\Auth\ProcessingChain::resumeProcessing` with the new request state. The request state must be an update of the array passed to the `process`-function.
  - No pages may be shown to the user from the `process`-function. Instead, the request state should be saved, and the user should be redirected to a new page. This must be done to prevent unpredictable events if the user for example reloads the page.
  - No state information should be stored in the filter object. It must instead be stored in the request state array. Any changes to variables in the filter object may be lost.
  - The filter object must be serializable. It may be serialized between being constructed and the call to the `process`-function. This means that, for example, no database connections should be created in the constructor and later used in the `process`-function.
diff --git a/docs/simplesamlphp-authsource.md b/docs/simplesamlphp-authsource.md
index 514b96f3614fb83a39688f6069770c23f04853f5..0734aaa371fa237541809792936ce6edc5274684 100644
--- a/docs/simplesamlphp-authsource.md
+++ b/docs/simplesamlphp-authsource.md
@@ -1,8 +1,8 @@
 Creating authentication sources
 ===============================
 
-All authentication sources are located in the `lib/Auth/Source/` directory in a module, and the class name is `sspmod_<module>_Auth_Source_<name>`.
-The authentication source must extend the `SimpleSAML_Auth_Source` class or one of its subclasses.
+All authentication sources are located in the `lib/Auth/Source/` directory in a module, and the class name is `\SimpleSAML\Module\<module>\Auth\Source\<name>`.
+The authentication source must extend the `\SimpleSAML\Auth\Source` class or one of its subclasses.
 
 The "entry point" of an authentication source is the `authenticate()`-function.
 Once that function is called, the authentication module can do whatever it wishes to do.
@@ -13,18 +13,18 @@ There are only two requirements:
 
 - Return control to SimpleSAMLphp after authenticating the user.
   If the module is able to authenticate the user without doing any redirects, it should just update the state-array and return.
-  If the module does a redirect, it must call `SimpleSAML_Auth_Source::completeAuth()` with the updated state array.
+  If the module does a redirect, it must call `\SimpleSAML\Auth\Source::completeAuth()` with the updated state array.
 
 Everything else is up to the module.
 If the module needs to redirect the user, for example because it needs to show the user a page asking for credentials, it needs to save the state array.
-For that we have the `SimpleSAML_Auth_State` class.
+For that we have the `\SimpleSAML\Auth\State` class.
 This is only a convenience class, and you are not required to use it (but its use is encouraged, since it handles some potential pitfalls).
 
 
 Saving state
 ------------
 
-The `SimpleSAML_Auth_State` class has two functions that you should use:
+The `\SimpleSAML\Auth\State` class has two functions that you should use:
 `saveState($state, $stage)`, and `loadState($id, $stage)`.
 The `$stage` parameter must be an unique identifier for the current position in the authentication.
 It is used to prevent a malicious user from taking a state you save in one location, and give it to a different location.
@@ -36,13 +36,13 @@ Username/password authentication
 --------------------------------
 
 Since username/password authentication is quite a common operation, a base class has been created for this.
-This is the `sspmod_core_Auth_UserPassBase` class, which is can be found as `modules/core/lib/Auth/UserPassBase.php`.
+This is the `\SimpleSAML\Module\core\Auth\UserPassBase` class, which is can be found as `modules/core/lib/Auth/UserPassBase.php`.
 
 The only function you need to implement is the `login($username, $password)`-function.
 This function receives the username and password the user entered, and is expected to return the attributes of that user.
 If the username or password is incorrect, it should throw an error saying so:
 
-    throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+    throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
 
 "[Implementing custom username/password authentication](./simplesamlphp-customauth)" describes how to implement username/password authentication using that base class.
 
@@ -51,7 +51,7 @@ Generic rules & requirements
 ----------------------------
 
 -  
-    Must be derived from the `SimpleSAML_Auth_Source`-class.
+    Must be derived from the `\SimpleSAML\Auth\Source`-class.
 
     **Rationale**:
      - Deriving all authentication sources from a single base class allows us extend all authentication sources by extending the base class.
@@ -62,7 +62,7 @@ Generic rules & requirements
 
     **Rationale**:
      - PHP doesn't automatically call any parent constructor, so it needs to be done manually.
-     - The `$info`-array is used to provide information to the `SimpleSAML_Auth_Source` base class, and therefore needs to be included.
+     - The `$info`-array is used to provide information to the `\SimpleSAML\Auth\Source` base class, and therefore needs to be included.
      - Including the `$config`-array makes it possible to add generic configuration options that are valid for all authentication sources.
 
 -  
@@ -74,7 +74,7 @@ Generic rules & requirements
        This can be used if the authentication doesn't require user input, for example if the authentication can be done based on the IP-address of the user.
 
 -  
-    If the `authenticate`-function does not return, it must at a later time call `SimpleSAML_Auth_Source::completeAuth` with the new state array.
+    If the `authenticate`-function does not return, it must at a later time call `\SimpleSAML\Auth\Source::completeAuth` with the new state array.
     The state array must be an update of the array passed to the `authenticate`-function.
 
     **Rationale**:
diff --git a/docs/simplesamlphp-automated_metadata.md b/docs/simplesamlphp-automated_metadata.md
index 54eba451099d4108c77a6968d694e109f400116a..cc40de2ceb6f5367dc6edf95b91e5462f0d40ddd 100644
--- a/docs/simplesamlphp-automated_metadata.md
+++ b/docs/simplesamlphp-automated_metadata.md
@@ -68,43 +68,43 @@ Now we are going to proceed to configure the metarefresh module. First, edit the
 
 Here's an example of a possible configuration for both the Kalmar Federation and UK Access Management Federation:
 
-	$config = array(
-		'sets' => array(
-			'kalmar' => array(
-				'cron'		=> array('hourly'),
-				'sources'	=> array(
-					array(
+	$config = [
+		'sets' => [
+			'kalmar' => [
+				'cron'		=> ['hourly'],
+				'sources'	=> [
+					[
 						'src' => 'https://kalmar.feide.no/simplesaml/module.php/aggregator/?id=kalmarcentral&mimetype=text/plain&exclude=norway',
-						'certificates' => array(
+						'certificates' => [
 							'current.crt',
 							'rollover.crt',
-						),
-						'template' => array(
-							'tags'	=> array('kalmar'),
-							'authproc' => array(
-								51 => array('class' => 'core:AttributeMap', 'oid2name'),
-							),
-						),
-					),
-				),
+						],
+						'template' => [
+							'tags'	=> ['kalmar'],
+							'authproc' => [
+								51 => ['class' => 'core:AttributeMap', 'oid2name'],
+							],
+						],
+					],
+				],
 				'expireAfter' 		=> 60*60*24*4, // Maximum 4 days cache time.
 				'outputDir' 	=> 'metadata/metarefresh-kalmar/',
 				'outputFormat' => 'flatfile',
-			),
-			'uk' => array(
-				'cron'		=> array('hourly'),
-				'sources'	=> array(
-					array(
+			],
+			'uk' => [
+				'cron'		=> ['hourly'],
+				'sources'	=> [
+					[
 						'src' => 'http://metadata.ukfederation.org.uk/ukfederation-metadata.xml',
 						'validateFingerprint' => 'D0:E8:40:25:F0:B1:2A:CC:74:22:ED:C3:87:04:BC:29:BB:7B:9A:40',
-					),
-				),
+					],
+				],
 				'expireAfter' 		=> 60*60*24*4, // Maximum 4 days cache time.
 				'outputDir' 	=> 'metadata/metarefresh-ukaccess/',
 				'outputFormat' => 'serialize',
-			),
-		)
-	);
+			],
+		]
+	];
 
 
 The configuration consists of one or more metadata sets. Each metadata set has its own configuration, representing a metadata set of sources.
@@ -180,11 +180,11 @@ web-server write access to the output directories. Following the previous exampl
 Now you can configure SimpleSAMLphp to use the metadata fetched by metarefresh. Edit the main
 config.php file, and modify the `metadata.sources` directive accordingly: 
 
-	'metadata.sources' => array(
-		array('type' => 'flatfile'),
-		array('type' => 'flatfile', 'directory' => 'metadata/metarefresh-kalmar'),
-		array('type' => 'serialize', 'directory' => 'metadata/metarefresh-ukaccess'),
-	),
+	'metadata.sources' => [
+		['type' => 'flatfile'],
+		['type' => 'flatfile', 'directory' => 'metadata/metarefresh-kalmar'],
+		['type' => 'serialize', 'directory' => 'metadata/metarefresh-ukaccess'],
+	],
 
 Remember that the `type` parameter here must match the `outputFormat` in the configuration of the module.
 
diff --git a/docs/simplesamlphp-changelog.md b/docs/simplesamlphp-changelog.md
index 159144dc4ab3d65813987a0549ca381dfc21d36d..8e1c96b0d49627c597c74c75719d41d0ec53251d 100644
--- a/docs/simplesamlphp-changelog.md
+++ b/docs/simplesamlphp-changelog.md
@@ -6,31 +6,176 @@ SimpleSAMLphp changelog
 This document lists the changes between versions of SimpleSAMLphp.
 See the upgrade notes for specific information about upgrading.
 
-## Version 1.16.0
+## Version 1.17.0
 
 Released TBD
 
+### Changes
+  * Minimum required PHP version is now 5.5.
+  * Introduce new UI based on Twig templates.
+    The new templates co-exist next to the old ones.
+  * SimpleSAMLphp can now be used with applications that use Twig 2.
+  * Update configuration templates and documentation to PHP
+    short array syntax.
+  * All clases moved to namespaces and reformatted code to PSR-2.
+  * Many code cleanups.
+
+### consent
+  * Module is now disabled by default.
+
+### core
+  * Allow `core:PHP` to manipulate all of the state.
+  * IdP initiated login: add compatibility with Shibboleth parameters.
+
+### saml
+  * Add initial support for SAML Subject Id Attributes.
+  * Allow to specify multiple supported NameIdFormats in IdP hosted and
+    SP remote metadata.
+
+## Version 1.16.2
+
+Released 2018-09-28
+
+  * Fixed an issue with PHP sessions in PHP 7.2.
+  * Fixed a bug in the OAuth module.
+  * Make schema validation work again.
+  * Properly document the `saml:AuthnContextClassRef` authentication processing filter.
+  * Fixed an issue that made it impossible to install the software with composer using the
+    "stable" minimum-stability setting.
+  * Changed the default authentication context class to "PasswordProtectedTransport" by default
+    when authentication happened on an HTTPS exchange.
+
+## Version 1.16.1
+
+Released 2018-09-07
+
+  * Fix a bug preventing the consent page from showing.
+  * Add Catalan to the list of available languages.
+
+## Version 1.16.0
+
+Released 2018-09-06
+
+### Changes
+  * Default signature algorithm is now RSA-SHA256.
+  * Renamed class `SimpleSAML_Error_BadUserInnput` to `SimpleSAML_Error_BadUserInput`
+  * PHP 7.2 compatibility, including removing deprecated use of assert with string.
+  * Avoid logging database credentials in backtraces.
+  * Fix edge case in getServerPort.
+  * Updated Spanish translation.
+  * Improvements to documentation, testsuite, code quality and coding style.
+
 ### New features
   * Added support for SAML "Enhanced Client or Proxy" (ECP) protocol,
-    IdP side with HTTP Basic Authentcation as authentication method.
+    IdP side with HTTP Basic Authentication as authentication method.
     See the [ECP IdP documentation](./simplesamlphp-ecp-idp) for details.
   * New option `sendmail_from`, the from address for email sent by SSP.
   * New option `options` for PDO database connections, e.g. for TLS setup.
-
-### authfacebook
-  * Compatibility with Facebook strict URI match.
+  * New option `search.scope` for LDAP authsources.
+  * Add support for the DiscoHints IPHint metadata property.
+  * Add support to specify metadata XML in config with the `xml` parameter,
+    next to the exising `file` and `url` options.
+  * Also support CGI/RewriteRule setups that set the `REDIRECT_SIMPLESAMLPHP_CONFIG_DIR`
+    environment variable next to regular `SIMPLESAMLPHP_CONFIG_DIR`.
+  * Support creating an AuthSource via factory, for example useful in tests.
+  * Support preloading of a virtual config file via `SimpleSAML_Configuration::setPreLoadedConfig`
+    to allow for dynamic population of authsources.php.
+  * Add basic documentation on Nginx configuration.
+  * Test authentication: optionally show AuthData array.
+  * Improve performance of PDO Metadata Storage handler entity lookup.
+
+### adfs
+  * Make signature algorithm configurable with `signature.algorithm`.
+  * Use configuration assertion lifetime when available.
+  * Use `adfs:wreply` parameter when available.
+
+### authmyspace
+  * Module removed because service is no longer available.
+
+### cas
+  * Respect all LDAP options in LDAP call.
+
+### casserver
+  * Module removed; superseded by externally hosted module.
+
+### consent
+  * Sort attribute values for consent.
+  * Fix table layout for MySQL > 5.6.
+  * Rename `noconsentattributes` to `attributes.exclude`; the former
+    is now considered deprecated.
+
+### consentAdmin
+  * Work better with TargetedIDs when operating as a proxy.
+  * Add `attributes.exclude` option to correspond to the same option
+    in the Consent module.
 
 ### core
   * StatisticsWithAttribute: add `passive-` prefix when logging passive
     requests, set new option `skipPassive` to skip logging these altogether.
-  * Replace deprecated create_function with an anonymous function.
+  * Replace deprecated `create_function` with an anonymous function.
+  * New authproc filter Cardinality to enforce attribute cardinality.
+  * SQLPermanentStorage: proper expiration of stored values.
+  * AttributeLimit: new options `regex` and `ignoreCase`.
+  * AttributeMap: prevent possible infinite loop with some PHP versions.
+
+### ldap
+  * AttributeAddUsersGroups: if `attribute.groupname` is set, use the
+    configured attribute as the group name rather than the DN.
+  * Also base64encode the `ms-ds-consistencyguid` attribute.
+
+### metarefresh
+  * Return XML parser error for better debugging of problems.
+  * Only actually parse metadata types that have been enabled.
+  * Fix missing translation.
 
 ### Oauth
   * Make module HTTP proxy-aware.
   * Remove unused demo app.
 
-### Sqlauth
-  * Changed from default-enabled to default-disabled.
+### saml
+  * AttributeConsumingService: allow to set isDefault and index options.
+  * Encrypted attributes in an assertion are now decrypted correctly.
+  * Prefer the HTTP-Redirect binding for AuthnRequests if available.
+
+### smartattributes
+  * Fix to make the `add_authority` option work.
+
+### sqlauth
+  * The module is now disabled by default.
+
+### statistics
+  * Show a decent error message when no data is available.
+
+## Version 1.15.4
+
+Released 2018-03-02
+
+  * Resolved a security issue related to signature validation in the SAML2 library. See [SSPSA 201803-01](https://simplesamlphp.org/security/201803-01).
+
+## Version 1.15.3
+
+Released 2018-02-27
+
+  * Resolved a security issue related to signature validation in the SAML2 library. See [SSPSA 201802-01](https://simplesamlphp.org/security/201802-01).
+  * Fixed edge-case scenario where an application uses one of the known LoggingHandlers' name as a defined class
+  * Fixed issue #793 in the PHP logging handler.
+
+## Version 1.15.2
+
+Released 2018-01-31
+
+  * Resolved a Denial of Service security issue when validating timestamps in the SAML2 library. See [SSPSA 201801-01](https://simplesamlphp.org/security/201801-01).
+  * Resolved a security issue with the open redirect protection mechanism. See [SSPSA 201801-02](https://simplesamlphp.org/security/201801-02).
+  * Fix _undefined method_ error when using memcacheD.
+
+### `authfacebook`
+  * Fix compatibility with Facebook strict URI match.
+
+### `consent`
+  * Fix statistics not being gathered.
+
+### `sqlauth`
+  * Prevented a security issue with the connection charset used for MySQL backends. See [SSPSA 201801-03](https://simplesamlphp.org/security/201801-03).
 
 ## Version 1.15.1
 
@@ -1437,7 +1582,7 @@ Updates to `config.php`. Please check for updates in your local modified configu
   * Verification of the Receipient attribute in the response. Will improve security if for some reason an IdP is not includeding sufficient Audience restrictions.
   * Added hook to let modules tell about themself moduleinfo hook.
   * Improved cron mails
-  * Improved santity check exception handling
+  * Improved sanity check exception handling
   * Preserver line breaks in stack trace UI
   * Improvements to WS-Federation support: dynamic realms, logout etc.
   * Better handling of presentation of JPEG photos as attributes.
diff --git a/docs/simplesamlphp-customauth.md b/docs/simplesamlphp-customauth.md
index 8238ba695b3dfbfafd23a356e6420ed3084cd43a..ac9b04e2456248c8ab91e7667136b500b1ee069c 100644
--- a/docs/simplesamlphp-customauth.md
+++ b/docs/simplesamlphp-customauth.md
@@ -1,7 +1,7 @@
 Implementing custom username/password authentication
 ====================================================
 
-This is a step-by-step guide for creating a custom username/password [authentication source](./simplesamlphp-authsource) for SimpleSAMLphp.
+This is a step-by-step guide for creating a custom username/password [authentication source](./simplesamlphp-authsource.md) for SimpleSAMLphp.
 An authentication source is responsible for authenticating the user, typically by getting a username and password, and looking it up in some sort of database.
 
 <!-- {{TOC}} -->
@@ -9,7 +9,7 @@ An authentication source is responsible for authenticating the user, typically b
 Create a custom module
 ----------------------
 
-All custom code for SimpleSAMLphp should be contained in a [module](./simplesamlphp-modules).
+All custom code for SimpleSAMLphp should be contained in a [module](./simplesamlphp-modules.md).
 This ensures that you can upgrade your SimpleSAMLphp installation without overwriting your own code.
 In this example, we will call the module `mymodule`.
 It will be located under `modules/mymodule`.
@@ -40,31 +40,31 @@ To begin with, we will create a very simple authentication source, where the use
 Create the file `modules/mymodule/lib/Auth/Source/MyAuth.php` with the following contents:
 
     <?php
-    class sspmod_mymodule_Auth_Source_MyAuth extends sspmod_core_Auth_UserPassBase {
+    class MyAuth extends \SimpleSAML\Module\core\Auth\UserPassBase {
         protected function login($username, $password) {
             if ($username !== 'theusername' || $password !== 'thepassword') {
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
-            return array(
-                'uid' => array('theusername'),
-                'displayName' => array('Some Random User'),
-                'eduPersonAffiliation' => array('member', 'employee'),
-            );
+            return [
+                'uid' => ['theusername'],
+                'displayName' => ['Some Random User'],
+                'eduPersonAffiliation' => ['member', 'employee'],
+            ];
         }
     }
 
 Some things to note:
 
-  - The classname is `sspmod_mymodule_Auth_Source_MyAuth`.
+  - The classname is `\SimpleSAML\Module\mymodule\Auth\Source\MyAuth`.
     This tells SimpleSAMLphp to look for the class in `modules/mymodule/lib/Auth/Source/MyAuth.php`.
 
-  - Our authentication source subclassese `sspmod_core_Auth_UserPassBase`.
+  - Our authentication source subclassese `\SimpleSAML\Module\core\Auth\UserPassBase`.
     This is a helper-class that implements much of the common code needed for username/password authentication.
 
   - The `login` function receives the username and password the user enters.
     It is expected to authenticate the user.
     If the username or password is correct, it must return a set of attributes for the user.
-    Otherwise, it must throw the `SimpleSAML_Error_Error('WRONGUSERPASS');` exception.
+    Otherwise, it must throw the `\SimpleSAML\Error\Error('WRONGUSERPASS');` exception.
 
   - Attributes are returned as an associative array of `name => values` pairs.
     All attributes can have multiple values, so the values are always stored in an array.
@@ -78,26 +78,26 @@ Before we can test our authentication source, we must add an entry for it in `co
 
 The entry looks like this:
 
-    'myauthinstance' => array(
+    'myauthinstance' => [
         'mymodule:MyAuth',
-    ),
+    ],
 
 You can add it to the beginning of the list, so that the file looks something like this:
 
     <?php
-    $config = array(
-        'myauthinstance' => array(
+    $config = [
+        'myauthinstance' => [
             'mymodule:MyAuth',
-        ),
+        ],
         /* Other authentication sources follow. */
-    );
+    ];
 
 `myauthinstance` is the name of this instance of the authentication source.
 (You are allowed to have multiple instances of an authentication source with different configuration.)
 The instance name is used to refer to this authentication source in other configuration files.
 
 The first element of the configuration of the authentication source must be `'mymodule:MyAuth'`.
-This tells SimpleSAMLphp to look for the `sspmod_mymodule_Auth_Source_MyAuth` class.
+This tells SimpleSAMLphp to look for the `\SimpleSAML\Module\mymodule\Auth\Source\MyAuth` class.
 
 
 Testing our authentication source
@@ -124,7 +124,7 @@ In that file you should locate the `auth`-option for your IdP, and change it to
 
     <?php
     /* ... */
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         /* ... */
         /*
          * Authentication source to use. Must be one that is configured in
@@ -132,7 +132,7 @@ In that file you should locate the `auth`-option for your IdP, and change it to
          */
         'auth' => 'myauthinstance',
         /* ... */
-    );
+    ];
 
 You can then test logging in to the IdP.
 If you have logged in previously, you may need to log out first.
@@ -168,7 +168,7 @@ We can then use the properties in the `login` function.
 The complete class file should look like this:
 
     <?php
-    class sspmod_mymodule_Auth_Source_MyAuth extends sspmod_core_Auth_UserPassBase {
+    class MyAuth extends \SimpleSAML\Module\core\Auth\UserPassBase {
 
         private $username;
         private $password;
@@ -187,24 +187,24 @@ The complete class file should look like this:
 
         protected function login($username, $password) {
             if ($username !== $this->username || $password !== $this->password) {
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
-            return array(
-                'uid' => array($this->username),
-                'displayName' => array('Some Random User'),
-                'eduPersonAffiliation' => array('member', 'employee'),
-            );
+            return [
+                'uid' => [$this->username],
+                'displayName' => ['Some Random User'],
+                'eduPersonAffiliation' => ['member', 'employee'],
+            ];
         }
 
     }
 
 We can then update our entry in `config/authsources.php` with the configuration options:
 
-    'myauthinstance' => array(
+    'myauthinstance' => [
         'mymodule:MyAuth',
         'username' => 'theconfigusername',
         'password' => 'theconfigpassword',
-    ),
+    ],
 
 Next, you should go to the "Test configured authentication sources" page again, and test logging in.
 Note that we have updated the username & password to "theconfigusername" and "theconfigpassword".
@@ -214,7 +214,7 @@ Note that we have updated the username & password to "theconfigusername" and "th
 A more complete example - custom database authentication
 --------------------------------------------------------
 
-The [sqlauth:SQL](./sqlauth:sql) authentication source can do simple authentication against SQL databases.
+The [sqlauth:SQL](../modules/sqlauth/docs/sql.md) authentication source can do simple authentication against SQL databases.
 However, in some cases it cannot be used, for example because the database layout is too complex, or because the password validation routines cannot be implemented in SQL.
 What follows is an example of an authentication source that fetches an user from a database, and validates the password using a custom function.
 
@@ -245,7 +245,7 @@ A SSHA password is created like this:
 The class follows:
 
     <?php
-    class sspmod_mymodule_Auth_Source_MyAuth extends sspmod_core_Auth_UserPassBase {
+    class MyAuth extends \SimpleSAML\Module\core\Auth\UserPassBase {
 
         /* The database DSN.
          * See the documentation for the various database drivers for information about the syntax:
@@ -314,7 +314,7 @@ The class follows:
              */
             $st = $db->prepare('SELECT username, password_hash, full_name FROM userdb WHERE username=:username');
 
-            if (!$st->execute(array('username' => $username))) {
+            if (!$st->execute(['username' => $username])) {
                 throw new Exception('Failed to query database for user.');
             }
 
@@ -323,22 +323,22 @@ The class follows:
             if (!$row) {
                 /* User not found. */
                 SimpleSAML\Logger::warning('MyAuth: Could not find user ' . var_export($username, TRUE) . '.');
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
 
             /* Check the password. */
             if (!$this->checkPassword($row['password_hash'], $password)) {
                 /* Invalid password. */
                 SimpleSAML\Logger::warning('MyAuth: Wrong password for user ' . var_export($username, TRUE) . '.');
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
 
             /* Create the attribute array of the user. */
-            $attributes = array(
-                'uid' => array($username),
-                'displayName' => array($row['full_name']),
-                'eduPersonAffiliation' => array('member', 'employee'),
-            );
+            $attributes = [
+                'uid' => [$username],
+                'displayName' => [$row['full_name']],
+                'eduPersonAffiliation' => ['member', 'employee'],
+            ];
 
             /* Return the attributes. */
             return $attributes;
@@ -348,10 +348,10 @@ The class follows:
 
 And configured in `config/authsources.php`:
 
-    'myauthinstance' => array(
+    'myauthinstance' => [
         'mymodule:MyAuth',
         'dsn' => 'mysql:host=sql.example.org;dbname=userdatabase',
         'username' => 'db_username',
         'password' => 'secret_db_password',
-    ),
+    ],
 
diff --git a/docs/simplesamlphp-database.md b/docs/simplesamlphp-database.md
index 663fdce150e357cb51cced7c87a38ee0b933b600..b9a797a00b2bcf5fc3fec803d0aaab577e1e5ad9 100644
--- a/docs/simplesamlphp-database.md
+++ b/docs/simplesamlphp-database.md
@@ -20,12 +20,12 @@ Getting Started
 ---------------
 If you are just using the already configured database, which would normally be the case, all you need to do is get the global instance of the Database class.
 
-	$db = SimpleSAML\Database::getInstance();
+	$db = \SimpleSAML\Database::getInstance();
 
 If there is a requirement to connect to an alternate database server (ex. authenticating users that exist on a different SQL server or database) you can specify an alternate configuration.
 
-	$config = new SimpleSAML_Configuration($myconfigarray, "mymodule/lib/Auth/Source/myauth.php");
-	$db = SimpleSAML\Database::getInstance($config);
+	$config = new \SimpleSAML\Configuration($myconfigarray, "mymodule/lib/Auth/Source/myauth.php");
+	$db = \SimpleSAML\Database::getInstance($config);
 
 That will create a new instance of the database, separate from the global instance, specific to the configuration defined in $myconfigarray. If you are going to specify an alternate config, your configuration array must contain the same keys that exist in the master config (database.dsn, database.username, database.password, database.prefix, etc).
 
@@ -47,20 +47,20 @@ Since the database class allows administrators to configure master and slave dat
 The write function takes 2 parameters: SQL, params.
 
 	$table = $db->applyPrefix("test");
-	$values = array(
+	$values = [
 		'id' => 20,
 		'data' => 'Some data',
-	);
+	];
 	
 	$query = $db->write("INSERT INTO $table (id, data) VALUES (:id, :data)", $values);
 
 The values specified in the $values array will be bound to the placeholders and will be executed on the master. By default, values are binded as PDO::PARAM_STR. If you need to override this, you can specify it in the values array.
 
 	$table = $db->applyPrefix("test");
-	$values = array(
-		'id' => array(20, PDO::PARAM_INT),
+	$values = [
+		'id' => [20, PDO::PARAM_INT],
 		'data' => 'Some data',
-	);
+	];
 	
 	$query = $db->write("INSERT INTO $table (id, data) VALUES (:id, :data)", $values);
 
@@ -75,17 +75,17 @@ Since the database class allows administrators to configure master and slave dat
 The read function takes 2 parameters: SQL, params.
 
 	$table = $db->applyPrefix("test");
-	$values = array(
+	$values = [
 		'id' => 20,
-	);
+	];
 	
 	$query = $db->read("SELECT * FROM $table WHERE id = :id", $values);
 
 The values specified in the $values array will be bound to the placeholders and will be executed on the selected slave. By default, values are binded as PDO::PARAM_STR. If you need to override this, you can specify it in the values array.
 
 	$table = $db->applyPrefix("test");
-	$values = array(
-		'id' => array(20, PDO::PARAM_INT),
-	);
+	$values = [
+		'id' => [20, PDO::PARAM_INT],
+	];
 	
 	$query = $db->read("SELECT * FROM $table WHERE id = :id", $values);
diff --git a/docs/simplesamlphp-ecp-idp.txt b/docs/simplesamlphp-ecp-idp.md
similarity index 98%
rename from docs/simplesamlphp-ecp-idp.txt
rename to docs/simplesamlphp-ecp-idp.md
index 28ac7f90a125dc2b14c1915cfa46755d82009453..566df182d610f989b349ee5a74aa4631d5ff3f3d 100644
--- a/docs/simplesamlphp-ecp-idp.txt
+++ b/docs/simplesamlphp-ecp-idp.md
@@ -19,11 +19,11 @@ Enabling ECP Profile on the IdP
 
 To enable the IdP to send ECP assertions you must add the `saml20.ecp` option to the `saml20-idp-hosted` metadata file:
 
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         [....]
         'auth' => 'example-userpass',
         'saml20.ecp' => true,
-    );
+    ];
 
 Note: authentication filters that require interaction with the user will not work with ECP.
 
diff --git a/docs/simplesamlphp-errorhandling.md b/docs/simplesamlphp-errorhandling.md
index 278cad2c24b7d03b5b5704d2f039c3f20445dce5..f7251550b6ccc801c6d7ed25c504217099b2b4fb 100644
--- a/docs/simplesamlphp-errorhandling.md
+++ b/docs/simplesamlphp-errorhandling.md
@@ -14,7 +14,7 @@ This document describes the way errors and exceptions are handled in authenticat
 The basic goal is to be able to throw an exception during authentication, and then have that exception transported back to the SP in a way that the SP understands.
 
 This means that internal SimpleSAMLphp exceptions must be mapped to transport specific error codes for the various transports that are supported by SimpleSAMLphp.
-E.g.: When a `SimpleSAML_Error_NoPassive` error is thrown by an authentication processing filter in a SAML 2.0 IdP, we want to map that exception to the `urn:oasis:names:tc:SAML:2.0:status:NoPassive` status code.
+E.g.: When a `\SimpleSAML\Error\NoPassive` error is thrown by an authentication processing filter in a SAML 2.0 IdP, we want to map that exception to the `urn:oasis:names:tc:SAML:2.0:status:NoPassive` status code.
 That status code should then be returned to the SP.
 
 
@@ -26,34 +26,34 @@ The simplest case is if you want to throw it during the `authenticate()`-method
 In those methods, you can just throw an exception:
 
     public function process(&$state) {
-        if ($state['something'] === FALSE) {
-            throw new SimpleSAML_Error_Exception('Something is wrong...');
+        if ($state['something'] === false) {
+            throw new \SimpleSAML\Error\Exception('Something is wrong...');
         }
     }
 
 Exceptions thrown at this stage will be caught and delivered to the appropriate error handler.
 
-If you want to throw an exception outside of those methods, i.e. after you have done a redirect, you need to use the `SimpleSAML_Auth_State::throwException()` function:
+If you want to throw an exception outside of those methods, i.e. after you have done a redirect, you need to use the `\SimpleSAML\Auth\State::throwException()` function:
 
     <?php
     $id = $_REQUEST['StateId'];
-    $state = SimpleSAML_Auth_State::loadState($id, 'somestage...');
-    SimpleSAML_Auth_State::throwException($state,
-        new SimpleSAML_Error_Exception('Something is wrong...'));
+    $state = \SimpleSAML\Auth\State::loadState($id, 'somestage...');
+    \SimpleSAML\Auth\State::throwException($state,
+        new \SimpleSAML\Error\Exception('Something is wrong...'));
     ?>
 
-The `SimpleSAML_Auth_State::throwException` function will then transfer your exception to the appropriate error handler.
+The `\SimpleSAML\Auth\State::throwException` function will then transfer your exception to the appropriate error handler.
 
 
 ### Note
 
-Note that we use the `SimpleSAML_Error_Exception` class in both cases.
+Note that we use the `\SimpleSAML\Error\Exception` class in both cases.
 This is because the delivery of the exception may require a redirect to a different web page.
 In those cases, the exception needs to be serialized.
 The normal `Exception` class in PHP isn't always serializable.
 
-If you throw an exception that isn't a subclass of the `SimpleSAML_Error_Exception` class, your exception will be converted to an instance of `SimpleSAML_Error_UnserializableException`.
-The `SimpleSAML_Auth_State::throwException` function does not accept any exceptions that does not subclass the `SimpleSAML_Error_Exception` class.
+If you throw an exception that isn't a subclass of the `\SimpleSAML\Error\Exception` class, your exception will be converted to an instance of `\SimpleSAML\Error\UnserializableException`.
+The `\SimpleSAML\Auth\State::throwException` function does not accept any exceptions that does not subclass the `\SimpleSAML\Error\Exception` class.
 
 
 Returning specific SAML 2 errors
@@ -61,24 +61,24 @@ Returning specific SAML 2 errors
 
 By default, all thrown exceptions will be converted to a generic SAML 2 error.
 In some cases, you may want to convert the exception to a specific SAML 2 status code.
-For example, the `SimpleSAML_Error_NoPassive` exception should be converted to a SAML 2 status code with the following properties:
+For example, the `\SimpleSAML\Error\NoPassive` exception should be converted to a SAML 2 status code with the following properties:
 
 * The top-level status code should be `urn:oasis:names:tc:SAML:2.0:status:Responder`.
 * The second-level status code should be `urn:oasis:names:tc:SAML:2.0:status:NoPassive`.
 * The status message should contain the cause of the exception.
 
-The `sspmod_saml_Error` class represents SAML 2 errors.
+The `\SimpleSAML\Module\saml\Error` class represents SAML 2 errors.
 It represents a SAML 2 status code with three elements: the top-level status code, the second-level status code and the status message.
 The second-level status code and the status message is optional, and can be `NULL`.
 
-The `sspmod_saml_Error` class contains a helper function named `fromException`.
+The `\SimpleSAML\Module\saml\Error` class contains a helper function named `fromException`.
 The `fromException()` function is used by `www/saml2/idp/SSOService.php` to return SAML 2 errors to the SP.
 The function contains a list which maps various exceptions to specific SAML 2 errors.
 If it is unable to convert the exception, it will return a generic SAML 2 error describing the original exception in its status message.
 
 To return a specific SAML 2 error, you should:
 
-* Create a new exception class for your error. This exception class must subclass `SimpleSAML_Error_Exception`.
+* Create a new exception class for your error. This exception class must subclass `\SimpleSAML\Error\Exception`.
 * Add that exception to the list in `fromException()`.
 * Consider adding the exception to `toException()` in the same file. (See the next section.)
 
@@ -93,11 +93,11 @@ Converting SAML 2 errors to normal exceptions
 ---------------------------------------------
 
 On the SP side, we want to convert SAML 2 errors to SimpleSAMLphp exceptions again.
-This is handled by the `toException()` method in `sspmod_saml_Error`.
+This is handled by the `toException()` method in `\SimpleSAML\Module\saml\Error`.
 The assertion consumer script of the SAML 2 authentication source (`modules/saml2/sp/acs.php`) uses this method.
 The result is that generic exceptions are thrown from that authentication source.
 
-For example, `NoPassive` errors will be converted back to instances of `SimpleSAML_Error_NoPassive`.
+For example, `NoPassive` errors will be converted back to instances of `\SimpleSAML\Error\NoPassive`.
 
 
 Other protocols
@@ -113,9 +113,9 @@ Technical details
 This section attempts to describe the internals of the error handling framework.
 
 
-### `SimpleSAML_Error_Exception`
+### `\SimpleSAML\Error\Exception`
 
-The `SimpleSAML_Error_Exception` class extends the normal PHP `Exception` class.
+The `\SimpleSAML\Error\Exception` class extends the normal PHP `Exception` class.
 It makes the exceptions serializable by overriding the `__sleep()` method.
 The `__sleep()` method returns all variables in the class which should be serialized when saving the class.
 
@@ -136,7 +136,7 @@ This may be confusing since the new stack trace leads into the `unserialize()` f
 It is therefore recommended to use the getBacktrace() method.
 
 
-### `SimpleSAML_Auth_State`
+### `\SimpleSAML\Auth\State`
 
 There are two methods in this class that deals with exceptions:
 
@@ -147,44 +147,44 @@ There are two methods in this class that deals with exceptions:
 #### `throwException`
 
 This method delivers the exception to the code that initialized the exception handling in the authentication state.
-That would be `SimpleSAML_Auth_Default` for authtentication sources, and `www/saml2/idp/SSOService.php` for processing filters.
+That would be `\SimpleSAML\Auth\DefaultAuth` for authtentication sources, and `www/saml2/idp/SSOService.php` for processing filters.
 To configure how and where the exception should be delivered, there are two fields in the state-array which can be set:
 
-* `SimpleSAML_Auth_State::EXCEPTION_HANDLER_FUNC`, in which case the exception will be delivered by a function call to the function specified in that field.
-* `SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL`, in which case the exception will be delivered by a redirect to the URL specified in that field.
+* `\SimpleSAML\Auth\State::EXCEPTION_HANDLER_FUNC`, in which case the exception will be delivered by a function call to the function specified in that field.
+* `\SimpleSAML\Auth\State::EXCEPTION_HANDLER_URL`, in which case the exception will be delivered by a redirect to the URL specified in that field.
 
 If the exception is delivered by a function call, the function will be called with two parameters: The exception and the state array.
 
-If the exception is delivered by a redirect, SimpleSAML_Auth_State will save the exception in a field in the state array, pass a parameter with the id of the state array to the URL.
-The `SimpleSAML_Auth_State::EXCEPTION_PARAM` constant contains the name of that parameter, while the `SimpleSAML_Auth_State::EXCEPTION_DATA` constant holds the name of the field where the exception is saved.
+If the exception is delivered by a redirect, \SimpleSAML\Auth\State will save the exception in a field in the state array, pass a parameter with the id of the state array to the URL.
+The `\SimpleSAML\Auth\State::EXCEPTION_PARAM` constant contains the name of that parameter, while the `\SimpleSAML\Auth\State::EXCEPTION_DATA` constant holds the name of the field where the exception is saved.
 
 
 #### `loadException`
 
-To retrieve the exception, the application should check for the state parameter in the request, and then retrieve the state array by calling `SimpleSAML_Auth_State::loadExceptionState()`.
-The exception can be located in a field named `SimpleSAML_Auth_State::EXCEPTION_DATA`.
+To retrieve the exception, the application should check for the state parameter in the request, and then retrieve the state array by calling `\SimpleSAML\Auth\State::loadExceptionState()`.
+The exception can be located in a field named `\SimpleSAML\Auth\State::EXCEPTION_DATA`.
 The following code illustrates this behaviour:
 
-    if (array_key_exists(SimpleSAML_Auth_State::EXCEPTION_PARAM, $_REQUEST)) {
-        $state = SimpleSAML_Auth_State::loadExceptionState();
-        $exception = $state[SimpleSAML_Auth_State::EXCEPTION_DATA];
+    if (array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_PARAM, $_REQUEST)) {
+        $state = \SimpleSAML\Auth\State::loadExceptionState();
+        $exception = $state[\SimpleSAML\Auth\State::EXCEPTION_DATA];
 
         /* Process exception. */
     }
 
 
-### `SimpleSAML_Auth_Default`
+### `\SimpleSAML\Auth\DefaultAuth`
 
 This class accepts an `$errorURL` parameter to the `initLogin()` function.
-This parameter is stored in the `SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL` of the state array.
+This parameter is stored in the `\SimpleSAML\Auth\State::EXCEPTION_HANDLER_URL` of the state array.
 Exceptions thrown by the authentication source will be delivered to that URL.
 
 It also wraps the call to the `authenticate()` function inside a try-catch block.
 Any exceptions thrown during that function call will be delivered to the URL specified in the `$errorURL` parameter.
-This is done for consistency, since `SimpleSAML_Auth_Default` never transfers control back to the caller by returning.
+This is done for consistency, since `\SimpleSAML\Auth\DefaultAuth` never transfers control back to the caller by returning.
 
 
-### `SimpleSAML_Auth_ProcessingChain`
+### `\SimpleSAML\Auth\ProcessingChain`
 
 This class requires the caller to add the error handler to the state array before calling the `processState()` function.
 Exceptions thrown by the processing filters will be delivered directly to the caller of `processState()` if possible.
@@ -195,9 +195,9 @@ The result will be delivered directly if it is possible, but if not, it will be
 
 The code for handling this becomes something like:
 
-    if (array_key_exists(SimpleSAML_Auth_State::EXCEPTION_PARAM, $_REQUEST)) {
-        $state = SimpleSAML_Auth_State::loadExceptionState();
-        $exception = $state[SimpleSAML_Auth_State::EXCEPTION_DATA];
+    if (array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_PARAM, $_REQUEST)) {
+        $state = \SimpleSAML\Auth\State::loadExceptionState();
+        $exception = $state[\SimpleSAML\Auth\State::EXCEPTION_DATA];
 
         /* Handle exception... */
         [...]
@@ -205,15 +205,15 @@ The code for handling this becomes something like:
 
     $procChain = [...];
 
-    $state = array(
-        'ReturnURL' => SimpleSAML_Utilities::selfURLNoQuery(),
-        SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL => SimpleSAML_Utilities::selfURLNoQuery(),
+    $state = [
+        'ReturnURL' => \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(),
+        \SimpleSAML\Auth\State::EXCEPTION_HANDLER_URL => \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(),
         [...],
-    )
+    ]
 
     try {
         $procChain->processState($state);
-    } catch (SimpleSAML_Error_Exception $e) {
+    } catch (\SimpleSAML\Error\Exception $e) {
         /* Handle exception. */
         [...];
     }
@@ -221,7 +221,7 @@ The code for handling this becomes something like:
 
 #### Note
 
-An exception which isn't a subclass of `SimpleSAML_Error_Exception` will be converted to the `SimpleSAML_Error_UnserializedException` class.
+An exception which isn't a subclass of `\SimpleSAML\Error\Exception` will be converted to the `\SimpleSAML\Error\UnserializedException` class.
 This happens regardless of whether the exception is delivered directly or through the error handler.
 This is done to be consistent in what the application receives - now it will always receive the same exception, regardless of whether it is delivered directly or through a redirect.
 
@@ -229,12 +229,12 @@ This is done to be consistent in what the application receives - now it will alw
 Custom error show function
 --------------------------
 
-Optional custom error show function, called from SimpleSAML_Error_Error::show, is defined with 'errors.show_function' in config.php.
+Optional custom error show function, called from \SimpleSAML\Error\Error::show, is defined with 'errors.show_function' in config.php.
 
-Example code for this function, which implements the same functionality as SimpleSAML_Error_Error::show, looks something like:
+Example code for this function, which implements the same functionality as \SimpleSAML\Error\Error::show, looks something like:
 
-    public static function show(SimpleSAML_Configuration $config, array $data) {
-        $t = new SimpleSAML_XHTML_Template($config, 'error.php', 'errors');
+    public static function show(\SimpleSAML\Configuration $config, array $data) {
+        $t = new \SimpleSAML\XHTML\Template($config, 'error.php', 'errors');
         $t->data = array_merge($t->data, $data);
         $t->show();
         exit;
diff --git a/docs/simplesamlphp-googleapps.md b/docs/simplesamlphp-googleapps.md
index 3eba11a6a634d221c2fcbcbe29ded49a87c9685b..5f8cfbd3c03cc938d92c869bf398c4360f4d3e1e 100644
--- a/docs/simplesamlphp-googleapps.md
+++ b/docs/simplesamlphp-googleapps.md
@@ -100,17 +100,17 @@ The next step is to create an authentication source with this module. An authent
 In this example we will use `example-userpass`, and hence that section is what matters and will be used.
 
 	<?php
-	$config = array(
-		'example-userpass' => array(
+	$config = [
+		'example-userpass' => [
 			'exampleauth:UserPass',
-			'student:studentpass' => array(
-				'uid' => array('student'),
-			),
-			'employee:employeepass' => array(
-				'uid' => array('employee'),
-			),
-		),
-	);
+			'student:studentpass' => [
+				'uid' => ['student'],
+			],
+			'employee:employeepass' => [
+				'uid' => ['employee'],
+			],
+		],
+	];
 	?>
 
 This configuration creates two users - `student` and `employee`, with the passwords `studentpass` and `employeepass`. The username and password are stored in the array index `student:studentpass` for the `student`-user. The attributes (only `uid` in this example) will be returned by the IdP when the user logs on.
@@ -127,7 +127,7 @@ If you want to setup a SAML 2.0 IdP for Google Apps, you need to configure two m
 This is the configuration of the IdP itself. Here is some example config:
 
 	// The SAML entity ID is the index of this config. Dynamic:X will automatically generate an entity ID (recommended)
-	$metadata['__DYNAMIC:1__'] => array(
+	$metadata['__DYNAMIC:1__'] => [
 		
 		// The hostname of the server (VHOST) that this SAML entity will use.
 		'host'				=>	'__DEFAULT__',
@@ -137,7 +137,7 @@ This is the configuration of the IdP itself. Here is some example config:
 		'certificate'  => 'googleappsidp.crt',
 		
 		'auth' => 'example-userpass',
-	)
+	]
 
 **Note**: You can only have one entry in the file with host equal to `__DEFAULT__`, therefore you should replace the existing entry with this one, instead of adding this entry as a new entry in the file. 
 
@@ -152,12 +152,12 @@ In the `saml20-sp-remote.php` file we will configure an entry for G Suite (Googl
        * at G Suite. E.g. if your google account is foo.com, and you have a user with email john@foo.com, then you
        * must set the simplesaml.nameidattribute to be the name of an attribute that for this user has the value of 'john'.
        */
-      $metadata['https://www.google.com/a/g.feide.no'] => array(
+      $metadata['https://www.google.com/a/g.feide.no'] => [
         'AssertionConsumerService'   => 'https://www.google.com/a/g.feide.no/acs', 
         'NameIDFormat'               => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
         'simplesaml.nameidattribute' => 'uid',
         'simplesaml.attributes'      => false
-      );
+      ];
 
 You must also map some attributes received from the authentication module into email field sent to Google Apps. In this example, the  `uid` attribute is set.  When you later configure the IdP to connect to a LDAP directory or some other authentication source, make sure that the `uid` attribute is set properly, or you can configure another attribute to use here. The `uid` attribute contains the local part of the user name.
 
diff --git a/docs/simplesamlphp-hok-idp.md b/docs/simplesamlphp-hok-idp.md
index e34a6b827d844699abbf85dbe2abf1c5c31befbe..a2315bf7481a9ca598b4d015c693941310d0a51e 100644
--- a/docs/simplesamlphp-hok-idp.md
+++ b/docs/simplesamlphp-hok-idp.md
@@ -29,11 +29,11 @@ Enabling HoK SSO Profile on the IdP
 
 To enable the IdP to send HoK assertions you must add the `saml20.hok.assertion` option to the `saml20-idp-hosted` metadata file:
 
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         [....]
         'auth' => 'example-userpass',
         'saml20.hok.assertion' => TRUE,
-    );
+    ];
 
 Add new metadata to SPs
 -----------------------
@@ -62,16 +62,16 @@ This means that you have to use the complex endpoint format in `saml20-sp-remote
 In general, this should look like the following code:
 
 	'AssertionConsumerService' => array (
-		array(
+		[
 			'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
 			'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
 			'index' => 0,
-		),
-		array(
+		],
+		[
 			'Binding' => 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser',
 			'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
 			'index' => 4,
-		),
+		],
 	),
 
 (The specific values of the various fields will vary depending on the SP.)
diff --git a/docs/simplesamlphp-hok-sp.md b/docs/simplesamlphp-hok-sp.md
index a687896c529cba118c98845dddb0123b5a6000bd..4b12a113af316f9463c06bfb7c9b2eed95b057a1 100644
--- a/docs/simplesamlphp-hok-sp.md
+++ b/docs/simplesamlphp-hok-sp.md
@@ -31,10 +31,10 @@ To enable support for the HoK SSO Profile in the SP, the `saml20.hok.assertion`
 This option can also be enabled in the `saml20-idp-remote` metadata file, but in that case the endpoint will not be added to the SP metadata.
 You must also send authentication requests specifying the Holder-of-Key profile to the IdP. This is controlled by the `ProtocolBinding` option in the SP configuration.
 
-    'hok-sp' => array(
+    'hok-sp' => [
         'saml:SP',
         'saml20.hok.assertion' => TRUE,
         'ProtocolBinding' => 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser',
-    ),
+    ],
 
 When this is done, you can add the metadata of your SP to the IdP and test the authentication.
diff --git a/docs/simplesamlphp-idp-more.md b/docs/simplesamlphp-idp-more.md
index fe61e17096b224b11da425e52995a64d558e8e26..bb5ead1ac8bde0e79d9bdaa90299862db60d6163 100644
--- a/docs/simplesamlphp-idp-more.md
+++ b/docs/simplesamlphp-idp-more.md
@@ -45,11 +45,16 @@ Here is an example of such a URL:
 
 	https://idp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=urn:mace:feide.no:someservice
 
-You can also add a RelayState parameter to the IdP-first URL:
+You can also add a `RelayState` parameter to the IdP-first URL:
 
 	https://idp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=urn:mace:feide.no:someservice&RelayState=https://sp.example.org/somepage
 
-The RelayState parameter is often uset do carry the URL the SP should redirect to after authentication.
+The `RelayState` parameter is often used to carry the URL the SP should redirect to after authentication. It is also possible to specify the Assertion
+Consumer URL with the `ConsumerURL` parameter.
+
+For compatibility with certain SPs, SimpleSAMLphp will also accept the
+`providerId`, `target` and `shire` parameters as aliases for `spentityid`,
+`RelayState` and `ConsumerURL`, respectively.
 
 
 ### IdP first with SAML 1.1
diff --git a/docs/simplesamlphp-idp.md b/docs/simplesamlphp-idp.md
index f720ee66e28bbc6705d023d860260a7e4c8aadda..1401d1d543800e8b414786c0f4d8660cecff6b1e 100644
--- a/docs/simplesamlphp-idp.md
+++ b/docs/simplesamlphp-idp.md
@@ -16,10 +16,9 @@ This guide will describe how to configure SimpleSAMLphp as an identity provider
 Enabling the Identity Provider functionality
 --------------------------------------------
 
-The first that must be done is to enable the identity provider functionality. This is done by editing `config/config.php`. The options `enable.saml20-idp` and `enable.shib13-idp` controls whether SAML 2.0 and Shibboleth 1.3 support is enabled. Enable one or both of those by assigning `true` to them:
+The first that must be done is to enable the identity provider functionality. This is done by editing `config/config.php`. The option `enable.saml20-idp` controls whether SAML 2.0 IdP support is enabled. Enable it by assigning `true` to them:
 
     'enable.saml20-idp' => true,
-    'enable.shib13-idp' => true,
 
 
 Authentication module
@@ -97,26 +96,26 @@ The next step is to create an authentication source with this module. An authent
 In this setup, this file should contain a single entry:
 
 	<?php
-	$config = array(
-		'example-userpass' => array(
+	$config = [
+		'example-userpass' => [
 			'exampleauth:UserPass',
-			'student:studentpass' => array(
-				'uid' => array('student'),
-				'eduPersonAffiliation' => array('member', 'student'),
-			),
-			'employee:employeepass' => array(
-				'uid' => array('employee'),
-				'eduPersonAffiliation' => array('member', 'employee'),
-			),
-		),
-	);
+			'student:studentpass' => [
+				'uid' => ['student'],
+				'eduPersonAffiliation' => ['member', 'student'],
+			],
+			'employee:employeepass' => [
+				'uid' => ['employee'],
+				'eduPersonAffiliation' => ['member', 'employee'],
+			],
+		],
+	];
 
 This configuration creates two users - `student` and `employee`, with the passwords `studentpass` and `employeepass`. The username and password is stored in the array index (`student:studentpass` for the `student`-user. The attributes for each user is configured in the array referenced by the index. For the student user, these are:
 
-	array(
-		'uid' => array('student'),
-		'eduPersonAffiliation' => array('member', 'student'),
-	),
+	[
+		'uid' => ['student'],
+		'eduPersonAffiliation' => ['member', 'student'],
+	],
 
 The attributes will be returned by the IdP when the user logs on.
 
@@ -141,12 +140,12 @@ SimpleSAMLphp will only work with RSA certificates. DSA certificates are not sup
 Configuring the IdP
 -------------------
 
-The IdP is configured by the metadata stored in
-`metadata/saml20-idp-hosted.php` and `metadata/shib13-idp-hosted.php`.
-This is a minimal configuration of a SAML 2.0 IdP:
+The SAML 2.0 IdP is configured by the metadata stored in
+`metadata/saml20-idp-hosted.php`.
+This is a minimal configuration:
 
     <?php
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         /*
          * The hostname for this IdP. This makes it possible to run multiple
          * IdPs from the same configuration. '__DEFAULT__' means that this one
@@ -166,7 +165,7 @@ This is a minimal configuration of a SAML 2.0 IdP:
          * user. This must match one of the entries in config/authsources.php.
          */
         'auth' => 'example-userpass',
-    );
+    ];
 
 For more information about available options in the idp-hosted metadata
 files, see the [IdP hosted reference](simplesamlphp-reference-idp-hosted).
@@ -175,29 +174,29 @@ files, see the [IdP hosted reference](simplesamlphp-reference-idp-hosted).
 Using the `uri` NameFormat on attributes
 ----------------------------------------
 
-The [interoperable SAML 2 profile](http://saml2int.org/profile/current) specifies that attributes should be delivered using the `urn:oasis:names:tc:SAML:2.0:attrname-format:uri` NameFormat.
+The [interoperable SAML 2 profile](https://kantarainitiative.github.io/SAMLprofiles/saml2int.html) specifies that attributes should be delivered using the `urn:oasis:names:tc:SAML:2.0:attrname-format:uri` NameFormat.
 We therefore recommended enabling this in new installations.
 This can be done by adding the following to the saml20-idp-hosted configuration:
 
     'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
-    'authproc' => array(
+    'authproc' => [
         // Convert LDAP names to oids.
-        100 => array('class' => 'core:AttributeMap', 'name2oid'),
-    ),
+        100 => ['class' => 'core:AttributeMap', 'name2oid'],
+    ],
 
 
 Adding SPs to the IdP
 ---------------------
 
 The identity provider you are configuring needs to know about the service providers you are going to connect to it.
-This is configured by metadata stored in `metadata/saml20-sp-remote.php` and `metadata/shib13-sp-remote.php`.
+This is configured by metadata stored in `metadata/saml20-sp-remote.php`.
 This is a minimal example of a `metadata/saml20-sp-remote.php` metadata file for a SimpleSAMLphp SP:
 
     <?php
-    $metadata['https://sp.example.org/simplesaml/module.php/saml/sp/metadata.php/default-sp'] = array(
+    $metadata['https://sp.example.org/simplesaml/module.php/saml/sp/metadata.php/default-sp'] = [
         'AssertionConsumerService' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
         'SingleLogoutService'      => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',
-    );
+    ];
 
 Note that the URI in the entityID and the URLs to the AssertionConsumerService and SingleLogoutService endpoints change between different service providers.
 If you have the metadata of the remote SP as an XML file, you can use the built-in XML to SimpleSAMLphp metadata converter, which by default is available as `/admin/metadata-converter.php` in your SimpleSAMLphp installation.
@@ -208,7 +207,7 @@ For more information about available options in the sp-remote metadata files, se
 Adding this IdP to other SPs
 ----------------------------
 
-The method for adding this IdP to a SP varies between different types of SPs. In general, most SPs need some metadata from the IdP. This should be available from `/saml2/idp/metadata.php` and `/shib13/idp/metadata.php`.
+The method for adding this IdP to a SP varies between different types of SPs. In general, most SPs need some metadata from the IdP. This should be available from `/saml2/idp/metadata.php`.
 
 
 Testing the IdP
@@ -253,7 +252,7 @@ To send the RelayState parameter from a SimpleSAMLphp IdP, specify it in the que
 
 To set it in the SP configuration, add it to `authsources.php`:
 
-    'default-sp' => array(
+    'default-sp' => [
         'saml:SP',
         'RelayState' => 'https://sp.example.org/welcome.php',
-    ),
+    ],
diff --git a/docs/simplesamlphp-install.md b/docs/simplesamlphp-install.md
index 0c4ba9c4859687b7954f1228e4e023abf71a5777..b410c54c793471412d502d9f03ae264d9ff300f6 100644
--- a/docs/simplesamlphp-install.md
+++ b/docs/simplesamlphp-install.md
@@ -24,7 +24,7 @@ Development version
 --------------------
 
 This document is about the latest stable version of SimpleSAMLphp.
-If you want to install the development version, look at the instructions for [installing SimpleSAMLphp from the repository](simplesamlphp-install-repo).
+If you want to install the development version, look at the instructions for [installing SimpleSAMLphp from the repository](simplesamlphp-install-repo.md).
 
 
 Prerequisites
@@ -151,9 +151,43 @@ This works only for the `config` directory. If you need your metadata to be in a
 
 This is just the basic configuration to get things working. For a checklist
 further completing your documentation, please see
-[Maintenance and configuration: Apache](simplesamlphp-maintenance#section_4).
+[Maintenance and configuration: Apache](simplesamlphp-maintenance.md#apache-configuration).
 
 
+Configuring Nginx
+------------------
+
+Examples below assume that SimpleSAMLphp is installed in the default location, `/var/simplesamlphp`. You may choose another location, but this requires a path update in a few files. See Appendix for details ‹Installing SimpleSAMLphp in alternative locations›.
+
+The only subdirectory of `SimpleSAMLphp` that needs to be accessible from the web is `www`. There are several ways of exposing SimpleSAMLphp depending on the way web sites are structured on your Nginx web server. The following is just one possible configuration.
+
+Find the Nginx configuration file for the virtual hosts where you want to run SimpleSAMLphp. The configuration may look like this:
+
+    server {
+        listen 443 ssl;
+        server_name idp.example.com;
+
+        ssl_certificate        /etc/pki/tls/certs/idp.example.com.crt;
+        ssl_certificate_key    /etc/pki/tls/private/idp.example.com.key;
+        ssl_protocols          TLSv1.1 TLSv1.2;
+        ssl_ciphers            HIGH:!aNULL:!MD5;
+
+        location / {
+            root     /var/simplesamlphp/www;
+            index    index.php;
+        }
+
+        location ~ \.php$ {
+            root             /var/simplesamlphp/www;
+            fastcgi_pass     127.0.0.1:9000;
+            fastcgi_index    index.php;
+            fastcgi_param    SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+            fastcgi_split_path_info ^(.+?\.php)(/.*)$;
+            fastcgi_param    PATH_INFO $fastcgi_path_info;
+            include          fastcgi_params;
+        }
+    }
+
 SimpleSAMLphp configuration: config.php
 ---------------------------------------
 
@@ -164,7 +198,7 @@ file, `config.php`, right away:
 
 		'auth.adminpassword'        => 'setnewpasswordhere',
 
-   Hashed passwords can also be used here. See the [`authcrypt`](./authcrypt:authcrypt) documentation for more information.
+   Hashed passwords can also be used here. See the [`authcrypt`](../modules/authcrypt/docs/authcrypt.md) documentation for more information.
 
 -  Set a secret salt. This should be a random string. Some parts of the SimpleSAMLphp needs this salt to generate cryptographically secure hashes. SimpleSAMLphp will give an error if the salt is not changed from the default value. The command below can help you to generated a random string on (some) unix systems:
 
@@ -254,10 +288,8 @@ At the bottom of the installation page are some green lights. simpleSAML runs so
 You have now successfully installed SimpleSAMLphp, and the next steps depends on whether you want to setup a service provider, to protect a website by authentication or if you want to setup an identity provider and connect it to a user catalog. Documentation on bridging between federation protocols is found in a separate document.
 
  * [Using SimpleSAMLphp as a SAML Service Provider](simplesamlphp-sp)
-  * [Hosted SP Configuration Reference](./saml:sp)
   * [IdP remote reference](simplesamlphp-reference-idp-remote)
   * [Connecting SimpleSAMLphp as a SP to UK Access Federation or InCommon](simplesamlphp-ukaccess)
-  * [Upgrading - migration to use the SAML authentication source](simplesamlphp-sp-migration)
  * [Identity Provider QuickStart](simplesamlphp-idp)
   * [IdP hosted reference](simplesamlphp-reference-idp-hosted)
   * [SP remote reference](simplesamlphp-reference-sp-remote)
diff --git a/docs/simplesamlphp-maintenance.md b/docs/simplesamlphp-maintenance.md
index ab38566e94330c607808a0b5218889247e3b5b2b..ff4581b034555c381e814763afddcb3d0383f299 100644
--- a/docs/simplesamlphp-maintenance.md
+++ b/docs/simplesamlphp-maintenance.md
@@ -52,7 +52,7 @@ SimpleSAMLphp as an Identity Provider, or any other applications using it are no
 settings by leaving these options unset or setting them to `null`.
 
 If you need to restore your session's application after calling SimpleSAMLphp, you can do it by calling the `cleanup()` method of the
-`SimpleSAML_Session` class, like described [here](simplesamlphp-sp#section_6).
+`\SimpleSAML\Session` class, like described [here](simplesamlphp-sp#section_6).
 
 ### Configuring memcache
 
@@ -96,26 +96,26 @@ Here are two examples of configuration of memcache session handling:
 
 Example of redundant configuration with load balancing: This configuration makes it possible to lose both servers in the a-group or both servers in the b-group without losing any sessions. Note that sessions will be lost if one server is lost from both the a-group and the b-group.
 
-    'memcache_store.servers' => array(
-      array(
-        array('hostname' => 'mc_a1'),
-        array('hostname' => 'mc_a2'),
-      ),
-      array(
-        array('hostname' => 'mc_b1'),
-        array('hostname' => 'mc_b2'),
-      ),
-    ),
+    'memcache_store.servers' => [
+      [
+        ['hostname' => 'mc_a1'],
+        ['hostname' => 'mc_a2'],
+      ],
+      [
+        ['hostname' => 'mc_b1'],
+        ['hostname' => 'mc_b2'],
+      ],
+    ],
 
 **Example&nbsp;2.&nbsp;Example of simple configuration with only one memcache server**
 
 Example of simple configuration with only one memcache server, running on the same computer as the web server: Note that all sessions will be lost if the memcache server crashes.
 
-    'memcache_store.servers' => array(
-      array(
-        array('hostname' => 'localhost'),
-      ),
-    ),
+    'memcache_store.servers' => [
+      [
+        ['hostname' => 'localhost'],
+      ],
+    ],
 
 The expiration value (`memcache_store.expires`) is the duration for which data should be retained in memcache. Data are dropped from the memcache servers when this time expires. The time will be reset every time the data is written to the memcache servers.
 
@@ -170,15 +170,15 @@ Several metadata storage backends are available by default, including `flatfile`
 example configuration of different metadata sources in use at the same time:
 
 ```
-'metadata.sources' => array(
-    array('type' => 'flatfile'),
-    array('type' => 'flatfile', 'directory' => 'metadata/metarefresh-kalmar'),
-    array('type' => 'serialize', 'directory' => 'metadata/metarefresh-ukaccess'),
-),
+'metadata.sources' => [
+    ['type' => 'flatfile'],
+    ['type' => 'flatfile', 'directory' => 'metadata/metarefresh-kalmar'],
+    ['type' => 'serialize', 'directory' => 'metadata/metarefresh-ukaccess'],
+],
 ```
 
 You may also implement your own metadata storage handler, in a very similar way to how you would implement
-your own session handler. Your class **must** extend the `SimpleSAML_Metadata_MetaDataStorageSource` class
+your own session handler. Your class **must** extend the `\SimpleSAML\Metadata\MetaDataStorageSource` class
 and override the methods needed to change the backend used. This class **must** also be located in the
 `lib/MetadataStore/` directory of your custom module.
 
@@ -190,7 +190,7 @@ module is named _mymodule_ and your class is named _MyMetadataHandler_, you shou
 <?php
 namespace SimpleSAML\Module\mymodule\MetadataStore;
 
-class MyMetadataHandler extends SimpleSAML_Metadata_MetaDataStorageSource
+class MyMetadataHandler extends \SimpleSAML\Metadata\MetaDataStorageSource
 {
     ...
 ```
@@ -245,7 +245,7 @@ To add support for a new language, add your new language to the `language.availa
 	/*
 	 * Languages available and which language is default
 	 */
-	'language.available' => array('en', 'no', 'da', 'es', 'xx'),
+	'language.available' => ['en', 'no', 'da', 'es', 'xx'],
 	'language.default'   => 'en',
 
 Please use the standardized two-character
@@ -255,11 +255,11 @@ You also can set the default language. You should ensure that the default langua
 
 All strings that can be localized are found in the files `dictionaries/`. Add a new entry for each string, with your language code, like this:
 
-    'user_pass_header' => array(
+    'user_pass_header' => [
         'en' => 'Enter your username and password',
         'no' => 'Skriv inn brukernavn og passord',
         'xx' => 'Pooa jujjique jamba',
-      ),
+      ],
 
 You can translate as many of the texts as you would like; a full translation is not required unless you want to make this the default language. From the end users point of view, it looks best if all text fragments used in a given screen or form is in one single language.
 
diff --git a/docs/simplesamlphp-metadata-endpoints.md b/docs/simplesamlphp-metadata-endpoints.md
index 9bca9088db0db348b6d3a4ecd37cc03b0f5b827d..7200c9187de4ede82b371c1ec2de02306d06e319 100644
--- a/docs/simplesamlphp-metadata-endpoints.md
+++ b/docs/simplesamlphp-metadata-endpoints.md
@@ -32,10 +32,10 @@ It can be used when there is only a single endpoint that uses the default bindin
 Array of strings
 ----------------
 
-    'AssertionConsumerService' => array(
+    'AssertionConsumerService' => [
         'https://site1.example.org/ACS',
         'https://site2.example.org/ACS',
-    ),
+    ],
 
 This endpoint format can be used to represent multiple endpoints, all of which use the default binding.
 
@@ -43,28 +43,28 @@ This endpoint format can be used to represent multiple endpoints, all of which u
 Array of arrays
 ---------------
 
-    'AssertionConsumerService' => array(
-        array(
+    'AssertionConsumerService' => [
+        [
             'index' => 1,
             'isDefault' => TRUE,
             'Location' => 'https://sp.example.org/ACS',
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
-        ),
-        array(
+        ],
+        [
             'index' => 2,
             'Location' => 'https://sp.example.org/ACS',
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
-        ),
-    ),
+        ],
+    ],
 
 This endpoint format allows for specifying multiple endpoints with different bindings.
 It can also be used to specify the ResponseLocation attribute on endpoints, e.g. on `SingleLogoutService`:
 
-    'SingleLogoutService' => array(
-        array(
+    'SingleLogoutService' => [
+        [
             'Location' => 'https://sp.example.org/LogoutRequest',
             'ResponseLocation' => 'https://sp.example.org/LogoutResponse',
             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
-        ),
-    ),
+        ],
+    ],
 
diff --git a/docs/simplesamlphp-metadata-extensions-attributes.md b/docs/simplesamlphp-metadata-extensions-attributes.md
index 7e3c1c0bccccc91098d294970d10c410547331d1..832bc9c7d99106362f7cf65d34ccddb118524338 100644
--- a/docs/simplesamlphp-metadata-extensions-attributes.md
+++ b/docs/simplesamlphp-metadata-extensions-attributes.md
@@ -19,14 +19,14 @@ The `metadata/saml20-idp-hosted.php` entries are used to define the
 metadata extension items. An example of this is:
 
     <?php
-    $metadata['entity-id-1'] = array(
+    $metadata['entity-id-1'] = [
         /* ... */
-		'EntityAttributes' => array(
-			'urn:simplesamlphp:v1:simplesamlphp' => array('is', 'really', 'cool'),
-			'{urn:simplesamlphp:v1}foo'          => array('bar'),
-		),
+		'EntityAttributes' => [
+			'urn:simplesamlphp:v1:simplesamlphp' => ['is', 'really', 'cool'],
+			'{urn:simplesamlphp:v1}foo'          => ['bar'],
+		],
         /* ... */
-    );
+    ];
 
 The OASIS specification primarily defines how to include arbitrary
 `Attribute` and `Assertion` elements within the metadata for an IdP.
@@ -43,9 +43,9 @@ metadata. Each item in the `EntityAttributes` array defines a new
 array. Each item in this array produces a separte `<AttributeValue>`
 element within the `<Attribute>` element.
 
-		'EntityAttributes' => array(
-			'urn:simplesamlphp:v1:simplesamlphp' => array('is', 'really', 'cool'),
-		),
+		'EntityAttributes' => [
+			'urn:simplesamlphp:v1:simplesamlphp' => ['is', 'really', 'cool'],
+		],
 
 This generates:
 
@@ -58,9 +58,9 @@ This generates:
 Each `<Attribute>` element requires a `NameFormat` attribute. This is
 specified using curly braces at the beginning of the key name:
 
-		'EntityAttributes' => array(
-			'{urn:simplesamlphp:v1}foo' => array('bar'),
-		),
+		'EntityAttributes' => [
+			'{urn:simplesamlphp:v1}foo' => ['bar'],
+		],
 
 This generates:
 
@@ -76,17 +76,17 @@ Generated XML Metadata Examples
 
 If given the following configuration...
 
-    $metadata['https://www.example.com/saml/saml2/idp/metadata.php'] = array(
+    $metadata['https://www.example.com/saml/saml2/idp/metadata.php'] = [
         'host' => 'www.example.com',
         'certificate' => 'example.com.crt',
         'privatekey' => 'example.com.pem',
         'auth' => 'example-userpass',
 
-		'EntityAttributes' => array(
-			'urn:simplesamlphp:v1:simplesamlphp' => array('is', 'really', 'cool'),
-			'{urn:simplesamlphp:v1}foo'          => array('bar'),
-		),
-	);
+		'EntityAttributes' => [
+			'urn:simplesamlphp:v1:simplesamlphp' => ['is', 'really', 'cool'],
+			'{urn:simplesamlphp:v1}foo'          => ['bar'],
+		],
+	];
 
 ... will generate the following XML metadata:
 
diff --git a/docs/simplesamlphp-metadata-extensions-rpi.md b/docs/simplesamlphp-metadata-extensions-rpi.md
index 4799de19bb347347794dbf86222e071aa5e93a93..a6dc868e772c3da16b1524074eecc539b17c5e64 100644
--- a/docs/simplesamlphp-metadata-extensions-rpi.md
+++ b/docs/simplesamlphp-metadata-extensions-rpi.md
@@ -59,54 +59,54 @@ Examples
 
 Service Provider:
 
-    'default-sp' => array(
+    'default-sp' => [
         'saml:SP',
         'entityID' => NULL,
         ...
-        'RegistrationInfo' => array(
+        'RegistrationInfo' => [
             'authority' => 'urn:mace:sp.example.org',
             'instant' => '2008-01-17T11:28:03.577Z',
-            'policies' => array('en' => 'http://sp.example.org/policy', 'es' => 'http://sp.example.org/politica'),
-        ),
-    ),
+            'policies' => ['en' => 'http://sp.example.org/policy', 'es' => 'http://sp.example.org/politica'],
+        ],
+    ],
 
 Identity Provider:
 
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         'host' => '__DEFAULT__',
         ...
-        'RegistrationInfo' => array(
+        'RegistrationInfo' => [
             'authority' => 'urn:mace:idp.example.org',
             'instant' => '2008-01-17T11:28:03.577Z',
-        ),
-    );
+        ],
+    ];
 
 `aggregator` module:
 
-    $config = array(
-        'aggregators' => array(
+    $config = [
+        'aggregators' => [
             ...
-        ),
+        ],
         'maxDuration'   => 60*60*24*5,
         'reconstruct' => FALSE,
         ...
-        'RegistrationInfo' => array(
+        'RegistrationInfo' => [
             'authority' => 'urn:mace:example.federation',
             'instant' => '2008-01-17T11:28:03Z',
-            'policies' => array('en' => 'http://example.org/federation_policy', 'es' => 'https://example.org/politica_federacion'),
-        ),
-    );
+            'policies' => ['en' => 'http://example.org/federation_policy', 'es' => 'https://example.org/politica_federacion'],
+        ],
+    ];
 
 `aggregator2` module:
 
-    $config = array(
-        'example.org' => array(
-            'sources' => array(
+    $config = [
+        'example.org' => [
+            'sources' => [
                 ...
-            ),
-            'RegistrationInfo' => array(
+            ],
+            'RegistrationInfo' => [
                 'authority' => 'urn:mace:example.federation',
-                'policies' => array('en' => 'http://example.org/federation_policy', 'es' => 'https://example.org/politica_federacion'),
-            ),
-        ),
-    );
+                'policies' => ['en' => 'http://example.org/federation_policy', 'es' => 'https://example.org/politica_federacion'],
+            ],
+        ],
+    ];
diff --git a/docs/simplesamlphp-metadata-extensions-ui.md b/docs/simplesamlphp-metadata-extensions-ui.md
index 94a855d8451f8149db0e5e986a88b415b5895ffd..10dd3aba08de0354cc3da718aed118717aeef3d3 100644
--- a/docs/simplesamlphp-metadata-extensions-ui.md
+++ b/docs/simplesamlphp-metadata-extensions-ui.md
@@ -23,72 +23,72 @@ the relevant entry in `authsources.php`.
 An example for an IdP:
 
     <?php
-    $metadata['entity-id-1'] = array(
+    $metadata['entity-id-1'] = [
         /* ... */
-        'UIInfo' => array(
-            'DisplayName' => array(
+        'UIInfo' => [
+            'DisplayName' => [
                 'en' => 'English name',
                 'es' => 'Nombre en Español',
-            ),
-            'Description' => array(
+            ],
+            'Description' => [
                 'en' => 'English description',
                 'es' => 'Descripción en Español',
-            ),
-            'InformationURL' => array(
+            ],
+            'InformationURL' => [
                 'en' => 'http://example.com/info/en',
                 'es' => 'http://example.com/info/es',
-            ),
-            'PrivacyStatementURL' => array(
+            ],
+            'PrivacyStatementURL' => [
                 'en' => 'http://example.com/privacy/en',
                 'es' => 'http://example.com/privacy/es',
-            ),
-            'Keywords' => array(
-                'en' => array('communication', 'federated session'),
-                'es' => array('comunicaciĂłn', 'sesiĂłn federated'),
-            ),
-            'Logo' => array(
-                array(
+            ],
+            'Keywords' => [
+                'en' => ['communication', 'federated session'],
+                'es' => ['comunicaciĂłn', 'sesiĂłn federated'],
+            ],
+            'Logo' => [
+                [
                     'url'    => 'http://example.com/logo1.png',
                     'height' => 200,
                     'width'  => 400,
                     'lang'   => 'en',
-                ),
-                array(
+                ],
+                [
                     'url'    => 'http://example.com/logo2.png',
                     'height' => 201,
                     'width'  => 401,
-                ),
-            ),
-        ),
-        'DiscoHints' => array(
-            'IPHint'          => array('130.59.0.0/16', '2001:620::0/96'),
-            'DomainHint'      => array('example.com', 'www.example.com'),
-            'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'),
-        ),
+                ],
+            ],
+        ],
+        'DiscoHints' => [
+            'IPHint'          => ['130.59.0.0/16', '2001:620::0/96'],
+            'DomainHint'      => ['example.com', 'www.example.com'],
+            'GeolocationHint' => ['geo:47.37328,8.531126', 'geo:19.34343,12.342514'],
+        ],
         /* ... */
-    );
+    ];
 
 And for an SP it could look like this:
 
     <?php
-    $config = array(
+    $config = [
 
-        'default-sp' => array(
+        'default-sp' => [
             'saml:SP',
 
-            'UIInfo' => array(
-                'DisplayName' => array(
+            'UIInfo' => [
+                'DisplayName' => [
                     'en' => 'English name',
                     'es' => 'Nombre en Español'
-                ),
-                'Description' => array(
+                ],
+                'Description' => [
                     'en' => 'English description',
-                    'es' => 'Descripción en Español
-                ),
-            ),
+                    'es' => 'Descripción en Español'
+                ],
+            ],
             /* ... */
-        ),
-    );
+        ],
+    ];
 
 The OASIS specification primarily defines how an entity can communicate
 metadata related to IdP or service discovery and identification. There
@@ -106,52 +106,52 @@ about an IdP or SP. These properties are all children of the `UIInfo` key.
 *Note*: Most elements are localized strings that specify the language
 using the array key as the language-code:
 
-            'DisplayName' => array(
+            'DisplayName' => [
                 'en' => 'English name',
                 'es' => 'Nombre en Español',
-            ),
+            ],
 
 `DisplayName`
 :   The localized list of names for this entity
 
-            'DisplayName' => array(
+            'DisplayName' => [
                 'en' => 'English name',
                 'es' => 'Nombre en Español',
-            ),
+            ],
 
 `Description`
 :   The localized list of statements used to describe this entity
 
-            'Description' => array(
+            'Description' => [
                 'en' => 'English description',
                 'es' => 'Descripción en Español',
-            ),
+            ],
 
 `InformationURL`
 :   A localized list of URLs where more information about the entity is
     located.
 
-            'InformationURL' => array(
+            'InformationURL' => [
                 'en' => 'http://example.com/info/en',
                 'es' => 'http://example.com/info/es',
-            ),
+            ],
 
 `PrivacyStatementURL`
 :   A localized list of URLs where the entity's privacy statement is
     located.
 
-            'PrivacyStatementURL' => array(
+            'PrivacyStatementURL' => [
                 'en' => 'http://example.com/privacy/en',
                 'es' => 'http://example.com/privacy/es',
-            ),
+            ],
 
 `Keywords`
 :   A localized list of keywords used to describe the entity
 
-            'Keywords' => array(
-                'en' => array('communication', 'federated session'),
-                'es' => array('comunicaciĂłn', 'sesiĂłn federated'),
-            ),
+            'Keywords' => [
+                'en' => ['communication', 'federated session'],
+                'es' => ['comunicaciĂłn', 'sesiĂłn federated'],
+            ],
 
 :   *Note*: The `+` (plus) character is forbidden by specification from
     being part of a Keyword.
@@ -159,19 +159,19 @@ using the array key as the language-code:
 `Logo`
 :   The logos used to represent the entity
 
-            'Logo' => array(
-                array(
+            'Logo' => [
+                [
                     'url'    => 'http://example.com/logo1.png',
                     'height' => 200,
                     'width'  => 400,
                     'lang'   => 'en',
-                ),
-                array(
+                ],
+                [
                     'url'    => 'http://example.com/logo2.png',
                     'height' => 201,
                     'width'  => 401,
-                ),
-            ),
+                ],
+            ],
 
 :   An optional `lang` key containing a language-code is supported for
     localized logos.
@@ -188,20 +188,20 @@ key.
 :   This is a list of both IPv4 and IPv6 addresses in CIDR notation
     services by or associated with this entity.
 
-            'IPHint' => array('130.59.0.0/16', '2001:620::0/96'),
+            'IPHint' => ['130.59.0.0/16', '2001:620::0/96'],
 
 `DomainHint`
 :   This specifies a list of domain names serviced by or associated with
     this entity.
 
-            'DomainHint' => array('example.com', 'www.example.com'),
+            'DomainHint' => ['example.com', 'www.example.com'],
 
 `GeolocationHint`
 :   This specifies a list of geographic coordinates associated with, or
     serviced by, the entity. Coordinates are given in URI form using the
     geo URI scheme [RFC5870](http://www.ietf.org/rfc/rfc5870.txt).
 
-            'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'),
+            'GeolocationHint' => ['geo:47.37328,8.531126', 'geo:19.34343,12.342514'],
 
 
 Generated XML Metadata Examples
@@ -209,52 +209,52 @@ Generated XML Metadata Examples
 
 If given the following configuration...
 
-    $metadata['https://www.example.com/saml/saml2/idp/metadata.php'] = array(
+    $metadata['https://www.example.com/saml/saml2/idp/metadata.php'] = [
         'host' => 'www.example.com',
         'certificate' => 'example.com.crt',
         'privatekey' => 'example.com.pem',
         'auth' => 'example-userpass',
 
-        'UIInfo' => array(
-            'DisplayName' => array(
+        'UIInfo' => [
+            'DisplayName' => [
                 'en' => 'English name',
                 'es' => 'Nombre en Español',
-            ),
-            'Description' => array(
+            ],
+            'Description' => [
                 'en' => 'English description',
                 'es' => 'Descripción en Español',
-            ),
-            'InformationURL' => array(
+            ],
+            'InformationURL' => [
                 'en' => 'http://example.com/info/en',
                 'es' => 'http://example.com/info/es',
-            ),
-            'PrivacyStatementURL' => array(
+            ],
+            'PrivacyStatementURL' => [
                 'en' => 'http://example.com/privacy/en',
                 'es' => 'http://example.com/privacy/es',
-            ),
-            'Keywords' => array(
-                'en' => array('communication', 'federated session'),
-                'es' => array('comunicaciĂłn', 'sesiĂłn federated'),
-            ),
-            'Logo' => array(
-                array(
+            ],
+            'Keywords' => [
+                'en' => ['communication', 'federated session'],
+                'es' => ['comunicaciĂłn', 'sesiĂłn federated'],
+            ],
+            'Logo' => [
+                [
                     'url'    => 'http://example.com/logo1.png',
                     'height' => 200,
                     'width'  => 400,
-                ),
-                array(
+                ],
+                [
                     'url'    => 'http://example.com/logo2.png',
                     'height' => 201,
                     'width'  => 401,
-                ),
-            ),
-        ),
-        'DiscoHints' => array(
-            'IPHint'          => array('130.59.0.0/16', '2001:620::0/96'),
-            'DomainHint'      => array('example.com', 'www.example.com'),
-            'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'),
-        ),
-    );
+                ],
+            ],
+        ],
+        'DiscoHints' => [
+            'IPHint'          => ['130.59.0.0/16', '2001:620::0/96'],
+            'DomainHint'      => ['example.com', 'www.example.com'],
+            'GeolocationHint' => ['geo:47.37328,8.531126', 'geo:19.34343,12.342514'],
+        ],
+    ];
 
 ... will generate the following XML metadata:
 
diff --git a/docs/simplesamlphp-metadata-pdostoragehandler.md b/docs/simplesamlphp-metadata-pdostoragehandler.md
index 82656fb09be835821cfcf385c543c3f7f1d902e9..9724a6d2e0c60ad36c535a0f3139d9cd7a18ef09 100644
--- a/docs/simplesamlphp-metadata-pdostoragehandler.md
+++ b/docs/simplesamlphp-metadata-pdostoragehandler.md
@@ -35,10 +35,10 @@ You will first need to configure a PDO metadata source.
 
 Here is an example of flatfile plus PDO:
 
-	'metadata.sources' => array(
-		array('type' => 'flatfile'),
-		array('type' => 'pdo'),
-	),
+	'metadata.sources' => [
+		['type' => 'flatfile'],
+		['type' => 'pdo'],
+	],
 
 
 
diff --git a/docs/simplesamlphp-modules.md b/docs/simplesamlphp-modules.md
index ccbb851c81223793ed5dc742b2e26efe3014c460..ed0df99828b979396e83715f80337c86592c6a10 100644
--- a/docs/simplesamlphp-modules.md
+++ b/docs/simplesamlphp-modules.md
@@ -66,7 +66,7 @@ dictionaries
 
 :   It is also possible to specify
     `<module name>:<dictionary name>` as the default
-    dictionary when instantiating the `SimpleSAML_XHTML_Template`
+    dictionary when instantiating the `\SimpleSAML\XHTML\Template`
     class.
 
 hooks
@@ -77,20 +77,20 @@ hooks
 lib
 :   This directory contains classes which belong to this module.
     All classes must be named in the following pattern:
-    `sspmod_<module name>_<class name>` When looking up the filename of
+    `\SimpleSAML\Module\<module name>\<class name>` When looking up the filename of
     a class, SimpleSAMLphp will search for `<class name>` in the `lib`
     directory. Underscores in the class name will be translated into
     slashes.
 
 :   Thus, if SimpleSAMLphp needs to load a class named
-    `sspmod_example_Auth_Source_Example`, it will load the file named
+    `\SimpleSAML\Module\example\Auth\Source\Example`, it will load the file named
     `modules/example/lib/Auth/Source/Example.php`.
 
 templates
 :   These are module-specific templates. To use one of these
     templates, specify `<module name>:<template file>.php`
     as the template file in the constructor of
-    `SimpleSAML_XHTML_Template`. For example, `example:login-form.php`
+    `\SimpleSAML\XHTML\Template`. For example, `example:login-form.php`
     is translated to the file
     `modules/example/templates/default/login-form.php`. Note that
     `default` in the previous example is defined by the `theme.use`
@@ -150,26 +150,26 @@ authentication source.
 A typical configuration entry for an authentication source looks like 
 this:
 
-    'example-static' => array(
+    'example-static' => [
       /* This maps to modules/exampleauth/lib/Auth/Source/Static.php */
       'exampleauth:Static',
     
       /* The following is configuration which is passed on to
        * the exampleauth:Static authentication source. */
       'uid' => 'testuser',
-      'eduPersonAffiliation' => array('member', 'employee'),
-      'cn' => array('Test User'),
-    ),
+      'eduPersonAffiliation' => ['member', 'employee'],
+      'cn' => ['Test User'],
+    ],
 
 To use this authentication source in a SAML 2.0 IdP, set the
 `auth`-option of the IdP to `'example-static'`:
 
-    '__DYNAMIC:1__' => array(
+    '__DYNAMIC:1__' => [
       'host' => '__DEFAULT__',
       'privatekey' => 'example.org.pem',
       'certificate' => 'example.org.crt',
       'auth' => 'example-static',
-    ),
+    ],
 
 ### Creating authentication sources
 
diff --git a/docs/simplesamlphp-nostate.md b/docs/simplesamlphp-nostate.md
index 6d0535fb18eb8b6489cb8d7248b73ce62084b46e..208d9d5773c9ee89449585758d8c6370087fedf3 100644
--- a/docs/simplesamlphp-nostate.md
+++ b/docs/simplesamlphp-nostate.md
@@ -1,7 +1,7 @@
 Debugging "State Information Lost" errors
 =========================================
 
-**"State Information Lost"** (`SimpleSAML_Error_NoState: NOSTATE`)
+**"State Information Lost"** (`\SimpleSAML\Error\NoState: NOSTATE`)
 
 This is one of the most common errors that you can encounter when configuring
 SimpleSAMLphp. Unfortunately, it is also a generic error that can have many
diff --git a/docs/simplesamlphp-reference-idp-hosted.md b/docs/simplesamlphp-reference-idp-hosted.md
index 712e2b45c4195569992cd5a240e51de5c876e05b..276d9b7f66c5bb354a9ad3b141ad11eb210af78a 100644
--- a/docs/simplesamlphp-reference-idp-hosted.md
+++ b/docs/simplesamlphp-reference-idp-hosted.md
@@ -9,14 +9,14 @@ Both files have the following format:
 
     <?php
     /* The index of the array is the entity ID of this IdP. */
-    $metadata['entity-id-1'] = array(
+    $metadata['entity-id-1'] = [
         'host' => 'idp.example.org',
         /* Configuration options for the first IdP. */
-    );
-    $metadata['entity-id-2'] = array(
+    ];
+    $metadata['entity-id-2'] = [
         'host' => '__DEFAULT__',
         /* Configuration options for the default IdP. */
-    );
+    ];
     /* ... */
 
 The entity ID should be an URI. It can, also be on the form
@@ -50,6 +50,38 @@ Common options
 :   Certificate file which should be used by this IdP, in PEM format.
     The filename is relative to the `cert/`-directory.
 
+`contacts`
+:	Specify contacts in addition to the technical contact configured through config/config.php.
+	For example, specifying a support contact:
+
+		'contacts' => [
+		    [
+		        'contactType'       => 'support',
+		        'emailAddress'      => 'support@example.org',
+		        'givenName'         => 'John',
+		        'surName'           => 'Doe',
+		        'telephoneNumber'   => '+31(0)12345678',
+		        'company'           => 'Example Inc.',
+		    ],
+		],
+
+:	If you have support for a trust framework that requires extra attributes on the contact person element in your IdP metadata (for example, SIRTFI), you can specify an array of attributes on a contact.
+
+		'contacts' => [
+		    [
+		        'contactType'       => 'other',
+		        'emailAddress'      => 'mailto:abuse@example.org',
+		        'givenName'         => 'John',
+		        'surName'           => 'Doe',
+		        'telephoneNumber'   => '+31(0)12345678',
+		        'company'           => 'Example Inc.',
+		        'attributes'        => [
+		            'xmlns:remd'        => 'http://refeds.org/metadata',
+		            'remd:contactType'  => 'http://refeds.org/metadata/contactType/security',
+		        ],
+		    ],
+		],
+
 `host`
 :   The hostname for this IdP. One IdP can also have the `host`-option
     set to `__DEFAULT__`, and that IdP will be used when no other
@@ -64,10 +96,10 @@ Common options
 
 :   This option can be translated into multiple languages by specifying the value as an array of language-code to translated name:
 
-        'OrganizationName' => array(
+        'OrganizationName' => [
             'en' => 'Example organization',
             'no' => 'Eksempel organisation',
-        ),
+        ],
 
 :   *Note*: If you specify this option, you must also specify the `OrganizationURL` option.
 
@@ -123,37 +155,6 @@ Common options
     any value in the SP-remote metadata overrides the one configured
     in the IdP metadata.
 
-`contacts`
-:	Specify contacts in addition to the technical contact configured through config/config.php.
-	For example, specifying a support contact:
-
-		'contacts' => array(
-		    array(
-		        'contactType'       => 'support',
-		        'emailAddress'      => 'support@example.org',
-		        'givenName'         => 'John',
-		        'surName'           => 'Doe',
-		        'telephoneNumber'   => '+31(0)12345678',
-		        'company'           => 'Example Inc.',
-		    ),
-		),
-
-:	If you have support for a trust framework that requires extra attributes on the contact person element in your IdP metadata (for example, SIRTFI), you can specify an array of attributes on a contact.
-
-		'contacts' => array(
-		    array(
-		        'contactType'       => 'other',
-		        'emailAddress'      => 'mailto:abuse@example.org',
-		        'givenName'         => 'John',
-		        'surName'           => 'Doe',
-		        'telephoneNumber'   => '+31(0)12345678',
-		        'company'           => 'Example Inc.',
-		        'attributes'        => array(
-		            'xmlns:remd'        => 'http://refeds.org/metadata',
-		            'remd:contactType'  => 'http://refeds.org/metadata/contactType/security',
-		        ),
-		    ),
-		), 
 
 SAML 2.0 options
 ----------------
@@ -221,8 +222,11 @@ The following SAML 2.0 options are available:
 :   Note that this option can be set for each SP in the [SP-remote metadata](./simplesamlphp-reference-sp-remote).
 
 `NameIDFormat`
-:   The format of the NameID supported by this IdP. Defaults to the `transient` format if unspecified.
-    This parameter can be configured in multiple places, and the actual value used is fetched from metadata with
+:   The format(s) of the NameID supported by this IdP, as either an array or a string. If an array is given, the first
+    value is used as the default if the incoming request does not specify a preference. Defaults to the `transient`
+    format if unspecified.
+
+:   This parameter can be configured in multiple places, and the actual value used is fetched from metadata with
     the following priority:
 
 :   1.  SP Remote Metadata
@@ -242,7 +246,7 @@ The following SAML 2.0 options are available:
     you should configure [NameID generation filters](./saml:nameid)
     on your IdP.
 
-:   Note that the value set here will be added to the metadata generated for this IdP,
+:   Note that the value(s) set here will be added to the metadata generated for this IdP,
     in the `NameIDFormat` element.
 
 `RegistrationInfo`
@@ -329,12 +333,13 @@ The following SAML 2.0 options are available:
 	the default one.
 
 `signature.algorithm`
-:   The algorithm to use when signing any message generated by this identity provider. Defaults to RSA-SHA1.
+:   The algorithm to use when signing any message generated by this identity provider. Defaults to RSA-SHA256.
 :   Possible values:
 
     * `http://www.w3.org/2000/09/xmldsig#rsa-sha1`
        *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
+       The default.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384`
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`
 
@@ -425,7 +430,7 @@ These are some examples of IdP metadata
      * We use the '__DYNAMIC:1__' entity ID so that the entity ID
      * will be autogenerated.
      */
-    $metadata['__DYNAMIC:1__'] = array(
+    $metadata['__DYNAMIC:1__'] = [
         /*
          * We use '__DEFAULT__' as the hostname so we won't have to
          * enter a hostname.
@@ -441,4 +446,4 @@ These are some examples of IdP metadata
          * from config/authsources.php.
          */
         'auth' => 'example-userpass',
-    );
+    ];
diff --git a/docs/simplesamlphp-reference-idp-remote.md b/docs/simplesamlphp-reference-idp-remote.md
index 89526fdfdea27bad7f6f260bd733681ce05139b6..af324ef4d681f19973c632ac442dc3f02ae956b4 100644
--- a/docs/simplesamlphp-reference-idp-remote.md
+++ b/docs/simplesamlphp-reference-idp-remote.md
@@ -7,12 +7,12 @@ This is a reference for metadata options available for `metadata/saml20-idp-remo
 
     <?php
     /* The index of the array is the entity ID of this IdP. */
-    $metadata['entity-id-1'] = array(
+    $metadata['entity-id-1'] = [
         /* Configuration options for the first IdP. */
-    );
-    $metadata['entity-id-2'] = array(
+    ];
+    $metadata['entity-id-2'] = [
         /* Configuration options for the second IdP. */
-    );
+    ];
     /* ... */
 
 
@@ -50,10 +50,10 @@ The following options are common between both the SAML 2.0 protocol and Shibbole
 
 :   This option can be translated into multiple languages by specifying the value as an array of language-code to translated name:
 
-        'OrganizationName' => array(
+        'OrganizationName' => [
             'en' => 'Example organization',
             'no' => 'Eksempel organisation',
-        ),
+        ],
 
 :   *Note*: If you specify this option, you must also specify the `OrganizationURL` option.
 
@@ -80,10 +80,10 @@ The following options are common between both the SAML 2.0 protocol and Shibbole
 
 :   This option can be translated into multiple languages by specifying the value as an array of language-code to translated name:
 
-        'name' => array(
+        'name' => [
             'en' => 'A service',
             'no' => 'En tjeneste',
-        ),
+        ],
 
 `scope`
 :   An array with scopes valid for this IdP.
@@ -120,6 +120,9 @@ The following SAML 2.0 options are available:
 `hide.from.discovery`
 :   Whether to hide hide this IdP from the local discovery or not. Set to true to hide it. Defaults to false.
 
+`IDPList`
+:   The IdP is allowed to respond to an `AuthNRequest` originally sent to entityIDs in this list.
+
 `nameid.encryption`
 :   Whether NameIDs sent to this IdP should be encrypted. The default
     value is `FALSE`.
@@ -149,7 +152,7 @@ The following SAML 2.0 options are available:
 :   Endpoint URL for logout responses. Overrides the `SingleLogoutService`-option for responses.
 
 `signature.algorithm`
-:   The algorithm to use when signing any message sent to this specific identity provider. Defaults to RSA-SHA1.
+:   The algorithm to use when signing any message sent to this specific identity provider. Defaults to RSA-SHA256.
 :   Note that this option also exists in the SP configuration.
     This value in the IdP remote metadata overrides the value in the SP configuration.
 :   Possible values:
@@ -157,6 +160,7 @@ The following SAML 2.0 options are available:
     * `http://www.w3.org/2000/09/xmldsig#rsa-sha1`
        *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
+      The default.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384`
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`
 
diff --git a/docs/simplesamlphp-reference-sp-remote.md b/docs/simplesamlphp-reference-sp-remote.md
index 943c862626dd4cce16b6c3d31449c399569c610d..51b5df4e509661c508c93ff236e20d4e585a5416 100644
--- a/docs/simplesamlphp-reference-sp-remote.md
+++ b/docs/simplesamlphp-reference-sp-remote.md
@@ -9,12 +9,12 @@ Both files have the following format:
 
     <?php
     /* The index of the array is the entity ID of this SP. */
-    $metadata['entity-id-1'] = array(
+    $metadata['entity-id-1'] = [
         /* Configuration options for the first SP. */
-    );
-    $metadata['entity-id-2'] = array(
+    ];
+    $metadata['entity-id-2'] = [
         /* Configuration options for the second SP. */
-    );
+    ];
     /* ... */
 
 
@@ -54,10 +54,10 @@ and Shibboleth 1.3 protocol:
 :   This option can be translated into multiple languages by specifying
     the value as an array of language-code to translated name:
 
-        'name' => array(
+        'name' => [
             'en' => 'A service',
             'no' => 'En tjeneste',
-        ),
+        ],
 
 `OrganizationName`
 :   The name of the organization responsible for this SPP.
@@ -65,10 +65,10 @@ and Shibboleth 1.3 protocol:
 
 :   This option can be translated into multiple languages by specifying the value as an array of language-code to translated name:
 
-        'OrganizationName' => array(
+        'OrganizationName' => [
             'en' => 'Example organization',
             'no' => 'Eksempel organisation',
-        ),
+        ],
 
 :   *Note*: If you specify this option, you must also specify the `OrganizationURL` option.
 
@@ -174,8 +174,10 @@ The following SAML 2.0 options are available:
     `FALSE`.
 
 `NameIDFormat`
-:   The `NameIDFormat` this SP should receive. The three most commonly
-    used values are:
+:   The `NameIDFormat` this SP should receive. This may be specified as either a string or an array, but if an array
+    is given, the first format specified will be the one requested during an authentication request.
+
+:   The three most commonly used values are:
 
 :   1.  `urn:oasis:names:tc:SAML:2.0:nameid-format:transient`
     2.  `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent`
@@ -238,7 +240,7 @@ The following SAML 2.0 options are available:
     The value in the SP-remote metadata overrides the value in the IdP-hosted metadata.
 
 `signature.algorithm`
-:   The algorithm to use when signing any message sent to this specific service provider. Defaults to RSA-SHA1.
+:   The algorithm to use when signing any message sent to this specific service provider. Defaults to RSA-SHA256.
 :   Note that this option also exists in the IdP-hosted metadata.
     The value in the SP-remote metadata overrides the value in the IdP-hosted metadata.
 :   Possible values:
@@ -246,6 +248,7 @@ The following SAML 2.0 options are available:
     * `http://www.w3.org/2000/09/xmldsig#rsa-sha1`
        *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
+      The default.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384`
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`
 
@@ -269,6 +272,7 @@ The following SAML 2.0 options are available:
     the `attributes` array). For more advanced control over `NameID`,
     including the ability to specify any attribute regardless of
     the set sent to the SP, see the [NameID processing filters](./saml:nameid).
+    Note that the value of the attribute is collected **after** authproc-filters have run.
 
 :   Typical values can be `mail` for when using the `email` format,
     and `eduPersonTargetedID` when using the `persistent` format.
@@ -370,12 +374,13 @@ relevant for this sp. The final list is the concatenation of the list
 given as parameter to InitSSO (at the sp), the list configured at the
 sp and the list configured at the ipd (here) for this sp. The intersection
 of the final list and the idps configured at the at this idp will be
-presented to the user at the discovery service if neccessary. If only one 
+presented to the user at the discovery service if neccessary. If only one
 idp is in the intersection the discoveryservice will go directly to the idp.
 
 **Example: Configuration for scoping**
 
-     'IDPList' => array('https://idp1.wayf.dk', 'https://idp2.wayf.dk'),
+
+     'IDPList' => ['https://idp1.wayf.dk', 'https://idp2.wayf.dk'],
      
 
 Shibboleth 1.3 options
diff --git a/docs/simplesamlphp-scoping.md b/docs/simplesamlphp-scoping.md
index 3124122ed0d4bb0c3ecf2d65292ba4a6b371b4f9..c821b30e7926bf56fbffb5f217ae14643a2c99f8 100644
--- a/docs/simplesamlphp-scoping.md
+++ b/docs/simplesamlphp-scoping.md
@@ -55,11 +55,11 @@ The ProxyCount and IDPList option can be specified in the following places:
 Example configuration:
 
     # Add the IDPList
-    'IDPList' => array(
+    'IDPList' => [
         'IdPEntityID1',
         'IdPEntityID2',
         'IdPEntityID3',
-    ),
+    ],
     
     # Set ProxyCount
     'ProxyCount' => 2,
diff --git a/docs/simplesamlphp-sp-api.md b/docs/simplesamlphp-sp-api.md
index 2de1b509a698b342312ea41386657980d6efc3f9..07c851f9d2c73a46daafead3f5b79cf474273a50 100644
--- a/docs/simplesamlphp-sp-api.md
+++ b/docs/simplesamlphp-sp-api.md
@@ -42,7 +42,7 @@ Check whether the user is authenticated with this authentication source.
 `requireAuth`
 -------------
 
-    void requireAuth(array $params = array())
+    void requireAuth(array $params = [])
 
 Make sure that the user is authenticated.
 This function will only return if the user is authenticated.
@@ -65,17 +65,17 @@ See the documentation for the `login`-function for a description of the paramete
      * Return the user to the frontpage after authentication, don't post
      * the current POST data.
      */
-    $auth->requireAuth(array(
+    $auth->requireAuth([
         'ReturnTo' => 'https://sp.example.org/',
         'KeepPost' => FALSE,
-    ));
+    ]);
     print("Hello, authenticated user!");
 
 
 `login`
 -------------
 
-    void login(array $params = array())
+    void login(array $params = [])
 
 Start a login operation.
 This function will always start a new authentication process.
@@ -108,10 +108,10 @@ The [`saml:SP`](./saml:sp) authentication source also defines some parameters.
 ### Example
 
     # Send a passive authentication request.
-    $auth->login(array(
+    $auth->login([
         'isPassive' => TRUE,
         'ErrorURL' => 'https://.../error_handler.php',
-    ));
+    ]);
 
 
 `logout`
@@ -149,15 +149,15 @@ Logout, and redirect to the specified URL.
 
 Same as the previous, but check the result of the logout operation afterwards.
 
-    $auth->logout(array(
+    $auth->logout([
         'ReturnTo' => 'https://sp.example.org/logged_out.php',
         'ReturnStateParam' => 'LogoutState',
         'ReturnStateStage' => 'MyLogoutState',
-    ));
+    ]);
 
 And in logged_out.php:
 
-    $state = SimpleSAML_Auth_State::loadState((string)$_REQUEST['LogoutState'], 'MyLogoutState');
+    $state = \SimpleSAML\Auth\State::loadState((string)$_REQUEST['LogoutState'], 'MyLogoutState');
     $ls = $state['saml:sp:LogoutStatus']; /* Only works for SAML SP */
     if ($ls['Code'] === 'urn:oasis:names:tc:SAML:2.0:status:Success' && !isset($ls['SubCode'])) {
         /* Successful logout. */
@@ -178,10 +178,10 @@ If the user isn't authenticated, an empty array will be returned.
 
 The attributes will be returned as an associative array with the name of the attribute as the key and the value as an array of one or more strings:
 
-    array(
-        'uid' => array('testuser'),
-        'eduPersonAffiliation' => array('student', 'member'),
-    )
+    [
+        'uid' => ['testuser'],
+        'eduPersonAffiliation' => ['student', 'member'],
+    ]
 
 
 ### Example
diff --git a/docs/simplesamlphp-sp-migration.md b/docs/simplesamlphp-sp-migration.md
deleted file mode 100644
index ae3303cf8121dea9b631be21383994e1011bd0f8..0000000000000000000000000000000000000000
--- a/docs/simplesamlphp-sp-migration.md
+++ /dev/null
@@ -1,286 +0,0 @@
-Migrating to the `saml` module
-==============================
-
-<!-- {{TOC}} -->
-
-This document describes how you can migrate your code to use the `saml` module for authentication against SAML 2.0 and SAML 1.1 IdPs.
-It assumes that you have previously set up a SP by using redirects to `saml2/sp/initSSO.php`.
-
-The steps we are going to follow are:
-
-1. Create a new authentication source.
-2. Add the metadata for this authentication source to the IdP.
-3. Test the new authentication source.
-4. Convert the application to use the new API.
-5. Test the application.
-6. Remove the old metadata from the IdP.
-7. Disable the old SAML 2 SP.
-
-
-Create a new authentication source
-----------------------------------
-
-In this step we are going to create an authentication source which uses the `saml` module for authentication.
-To do this, we open `config/authsources.php`. Create the file if it does not exist.
-If you create the file, it should look like this:
-
-    <?php
-    $config = array(
-        /* Here we can add entries for authentication sources we want to use. */
-    );
-
-
-We are going to add an entry to this file.
-The entry should look something like this:
-
-    'default-sp' => array(
-        'saml:SP',
-
-        /*
-         * The entity ID of this SP.
-         * Can be NULL/unset, in which case an entity ID is generated based on the metadata URL.
-         */
-        'entityID' => NULL,
-
-        /*
-         * The entity ID of the IdP this should SP should contact.
-         * Can be NULL/unset, in which case the user will be shown a list of available IdPs.
-         */
-        'idp' => NULL,
-
-        /* Here you can add other options to the SP. */
-    ),
-
-`default-sp` is the name of the authentication source.
-It is used to refer to this authentication source when we use it.
-`saml:SP` tells SimpleSAMLphp that authentication with this authentication source is handled by the `saml` module.
-
-The `idp` option should be set to the same value that is set in `default-saml20-idp` in `config.php`.
-
-To ease migration, you probably want the entity ID on the new SP to be different than on the old SP.
-This makes it possible to have both the old and the new SP active on the IdP at the same time.
-
-You can also add other options this authentication source.
-See the [`saml:SP`](./saml:sp) documentation for more information.
-
-
-Add the metadata for this authentication source to the IdP
-----------------------------------------------------------
-
-After adding the authentication source on the SP, you need to register the metadata on the IdP.
-To retrieve the metadata, open the frontpage of your SimpleSAMLphp installation, and go to the federation tab.
-You should have a list of metadata entries, and one will be marked with the name of the new authentication source.
-In our case, that was `default-sp`.
-
-Click the `Show metadata` link, and you will arrive on a web page with the metadata for that service provider.
-How you proceed from here depends on which IdP you are connecting to.
-
-If you use a SimpleSAMLphp IdP, you can use the metadata in the flat file format at the bottom of the page.
-That metadata should be added to `saml20-sp-remote.php` on the IdP.
-For other IdPs you probably want to use the XML metadata.
-
-
-Test the new authentication source
-----------------------------------
-
-You should now be able to log in using the new authentication source.
-Go to the frontpage of your SimpleSAMLphp installation and open the authentication tab.
-There you will find a link to test authentication sources.
-Click that link, and select the name of your authentication source (`default-sp` in our case).
-
-You should be able to log in using that authentication source, and receive the attributes from the IdP.
-
-
-Convert the application to use the new API
-------------------------------------------
-
-This section will go through some common changes that you need to do when you are using SimpleSAMLphp from a different application.
-
-### `_include.php`
-
-You should also no longer include `.../simplesamlphp/www/_include.php`.
-Instead, you should include `.../simplesamlphp/lib/_autoload.php`.
-
-This means that you replace lines like:
-
-    require_once('.../simplesamlphp/www/_include.php');
-
-with:
-
-    require_once('.../simplesamlphp/lib/_autoload.php');
-
-`_autoload.php` will register an autoloader function for the SimpleSAMLphp classes.
-This makes it possible to access the classes from your application.
-`_include.php` does the same, but also has some side-effects that you may not want in your application.
-
-If you load any SimpleSAMLphp class files directly, you should remove those lines.
-That means that you should remove lines like the following:
-
-    require_once('SimpleSAML/Utilities.php');
-    require_once('SimpleSAML/Session.php');
-    require_once('SimpleSAML/XHTML/Template.php');
-
-
-### Authentication API
-
-There is a new authentication API in SimpleSAMLphp which can be used to authenticate against authentication sources.
-This API is designed to handle the common operations.
-
-
-#### Overview
-
-This is a quick overview of the API:
-
-    /* Get a reference to our authentication source. */
-    $as = new \SimpleSAML\Auth\Simple('default-sp');
-
-    /* Require the user to be authentcated. */
-    $as->requireAuth();
-    /* When that function returns, we have an authenticated user. */
-
-    /*
-     * Retrieve attributes of the user.
-     *
-     * Note: If the user isn't authenticated when getAttributes() is
-     * called, an empty array will be returned.
-     */
-    $attributes = $as->getAttributes();
-
-    /* Log the user out. */
-    $as->logout();
-
-
-#### `$config` and `$session`
-
-Generally, if you have:
-
-    $config = SimpleSAML_Configuration::getInstance();
-    $session = SimpleSAML_Session::getSessionFromRequest();
-
-you should replace it with this single line:
-
-    $as = new \SimpleSAML\Auth\Simple('default-sp');
-
-
-#### Requiring authentication
-
-Blocks of code like the following:
-
-    /* Check if valid local session exists.. */
-    if (!isset($session) || !$session->isValid('saml2') ) {
-      SimpleSAML_Utilities::redirect(
-        '/' . $config->getBaseURL() .
-        'saml2/sp/initSSO.php',
-        array('RelayState' => SimpleSAML_Utilities::selfURL())
-        );
-    }
-
-should be replaced with a single call to `requireAuth()`:
-
-    $as->requireAuth();
-
-
-#### Fetching attributes
-
-Where you previously called:
-
-    $session->getAttributes();
-
-you should now call:
-
-    $as->getAttributes();
-
-
-#### Logging out
-
-Redirecting to the initSLO-script:
-
-    SimpleSAML_Utilities::redirect(
-        '/' . $config->getBaseURL() .
-        'saml2/sp/initSLO.php',
-        array('RelayState' => SimpleSAML_Utilities::selfURL())
-        );
-
-should be replaced with a call to `logout()`:
-
-    $as->logout();
-
-If you want to return to a specific URL after logging out, you should include that URL as a parameter to the logout function:
-
-    $as->logout('https://example.org/');
-
-Please make sure the URL is trusted. If you obtain the URL from the user input, make sure it is trusted before
-calling $as->logout(), by using the SimpleSAML_Utilities::checkURLAllowed() method.
-
-
-#### Login link
-
-If you have any links to the initSSO-script, those links must be replaced with links to a new script.
-The URL to the new script is `https://.../simplesaml/module.php/core/as_login.php`.
-It has two mandatory parameters:
-
-  * `AuthId`: The id of the authentication source.
-  * `ReturnTo`: The URL the user should be redirected to after authentication.
-
-
-#### Logout link
-
-Any links to the initSLO-script must be replaced with links to a new script.
-The URL to the new script is `https://.../simplesaml/module.php/core/as_logout.php`.
-It has two mandatory parameters:
-
-  * `AuthId`: The id of the authentication source.
-  * `ReturnTo`: The URL the user should be redirected to after logout.
-
-
-Test the application
---------------------
-
-How you test the application is highly dependent on the application, but here are the elements you should test:
-
-
-### SP initiated login
-
-Make sure that it is still possible to log into the application.
-
-
-### IdP initiated login
-
-If you use a SimpleSAMLphp IdP, and you want users to be able to bookmark the login page, you need to test IdP initiated login.
-To test IdP initiated login from a SimpleSAMLphp IdP, you can access:
-
-    https://.../simplesaml/saml2/idp/SSOService.php?spentityid=<entity ID of your SP>&RelayState=<URL the user should be sent to after login>
-
-Note that the RelayState parameter is only supported if the IdP runs version 1.5 of SimpleSAMLphp.
-If it isn't supported by the IdP, you need to configure the `RelayState` option in the authentication source configuration.
-
-
-### SP initiated logout
-
-Make sure that logging out of your application also logs out of the IdP.
-If this does not work, users who log out of your application can log in again without entering any username or password.
-
-
-### IdP initiated logout
-
-This is used by the IdP if the user logs out of a different SP connected to the IdP.
-In this case, the user should also be logged out of your application.
-
-The easiest way to test this is if you have two SPs connected to the IdP.
-You can then log out of one SP and check that you are also logged out of the other.
-
-
-Remove the old metadata from the IdP
-------------------------------------
-
-Once the new SP works correctly, you can remove the metadata for the old SP from the IdP.
-How you do that depends on the IdP.
-If you are running a SimpleSAMLphp IdP, you can remove the entry for the old SP in `metadata/saml20-sp-remote.php`.
-
-
-Disable the old SAML 2 SP
--------------------------
-
-You may also want to disable the old SP code in SimpleSAMLphp.
-To do that, open `config/config.php`, and change the `enable.saml20-sp` option to `FALSE`.
-
diff --git a/docs/simplesamlphp-sp.md b/docs/simplesamlphp-sp.md
index dd50adab9a7c5435d95b5b24e5a6e079c70287b1..24530e6a5f2ec63e050391e7e5009589174bcfaf 100644
--- a/docs/simplesamlphp-sp.md
+++ b/docs/simplesamlphp-sp.md
@@ -22,26 +22,26 @@ The SP is configured by an entry in `config/authsources.php`.
 This is a minimal `authsources.php` for a SP:
 
     <?php
-    $config = array(
+    $config = [
 
         /* This is the name of this authentication source, and will be used to access it later. */
-        'default-sp' => array(
+        'default-sp' => [
             'saml:SP',
-        ),
-    );
+        ],
+    ];
 
 For more information about additional options available for the SP, see the [`saml:SP` reference](./saml:sp).
 
 If you want multiple Service Providers in the same site and installation, you can add more entries in the `authsources.php` configuration. If so remember to set the EntityID explicitly. Here is an example:
 
-	'sp1' => array(
+	'sp1' => [
 	    'saml:SP',
 		'entityID' => 'https://sp1.example.org/',
-	),
-	'sp2' => array(
+	],
+	'sp2' => [
 	    'saml:SP',
 		'entityID' => 'https://sp2.example.org/',
-	),
+	],
 
 ### Enabling a certificate for your Service Provider
 
@@ -55,11 +55,11 @@ Create a self-signed certificate in the `cert/` directory.
 
 Then edit your `authsources.php` entry, and add references to your certificate:
 
-	'default-sp' => array(
+	'default-sp' => [
 	    'saml:SP',
 	    'privatekey' => 'saml.pem',
 	    'certificate' => 'saml.crt',
-	),
+	],
 
 
 Adding IdPs to the SP
@@ -69,11 +69,11 @@ The service provider you are configuring needs to know about the identity provid
 This is a minimal example of a `metadata/saml20-idp-remote.php` metadata file:
 
     <?php
-    $metadata['https://example.com'] = array(
+    $metadata['https://example.com'] = [
         'SingleSignOnService'  => 'https://example.com/simplesaml/saml2/idp/SSOService.php',
         'SingleLogoutService'  => 'https://example.com/simplesaml/saml2/idp/SingleLogoutService.php',
         'certificate'          => 'example.pem',
-    );
+    ];
 
 `example.pem` under your `cert/` directory contains the certificate the identity provider uses for signing assertions.
 
@@ -91,9 +91,9 @@ An option in the authentication source allows you to configure which IdP should
 This is the `idp` option.
 
     <?php
-    $config = array(
+    $config = [
 
-        'default-sp' => array(
+        'default-sp' => [
             'saml:SP',
 
             /*
@@ -101,8 +101,8 @@ This is the `idp` option.
              * Can be NULL/unset, in which case the user will be shown a list of available IdPs.
              */
             'idp' => 'https://idp.example.com',
-        ),
-    );
+        ],
+    ];
 
 
 Exchange metadata with the IdP
@@ -180,9 +180,9 @@ Each attribute name can be used as an index into $attributes to obtain the value
 
 We can also request authentication with a specific IdP:
 
-    $as->login(array(
+    $as->login([
         'saml:idp' => 'https://idp.example.org/',
-    ));
+    ]);
 
 Other options are also available.
 Take a look in the documentation for the [SP module](./saml:sp) for a list of all parameters.
@@ -191,7 +191,7 @@ If we are using PHP sessions in SimpleSAMLphp and in the application we are prot
 existing session when invoked for the first time, and its own session will prevail afterwards. If you want to restore
 your own session after calling SimpleSAMLphp, you can do so by cleaning up the session like this:
 
-    $session = SimpleSAML_Session::getSessionFromRequest();
+    $session = \SimpleSAML\Session::getSessionFromRequest();
     $session->cleanup();
 
 If you don't cleanup SimpleSAMLphp's session and try to use $_SESSION afterwards, you won't be using your own session
diff --git a/docs/simplesamlphp-theming.md b/docs/simplesamlphp-theming.md
index 0c66fbde91ea3f948e96767901fa788113294a3d..51cbe65b5bdfd7d3bdea78d37b78c888e3c7fdc0 100644
--- a/docs/simplesamlphp-theming.md
+++ b/docs/simplesamlphp-theming.md
@@ -107,10 +107,29 @@ modules
 
 Reference these resources in your custom PHP templates under `themes/fancytheme` by using a generator for the URL:
 ```php
-<?php echo SimpleSAML_Module::getModuleURL('mymodule/logo.png'); ?>
+<?php echo SimpleSAML\Module::getModuleURL('mymodule/logo.png'); ?>
 ```
 
 Example for a custom CSS stylesheet file:
 ```html
-<link rel="stylesheet" type="text/css" href="<?php echo SimpleSAML_Module::getModuleURL('mymodule/style.css'); ?>" />
+<link rel="stylesheet" type="text/css" href="<?php echo SimpleSAML\Module::getModuleURL('mymodule/style.css'); ?>" />
 ```
+
+Migrating to Twig templates
+---------------------------
+
+In version 1.15, a new templating system based on [Twig](https://twig.symfony.com/) was introduced. As modules migrate, it will become necessary for themes to include both the old templating style described above and new Twig-based templates.
+
+Twig works by extending a base template, which can itself include other partial templates. Some of the content of the old `includes/header.php` template is now located in a separate `_header.twig` file. This can be customized by copying it from the base template:
+
+	cp templates/_header.twig modules/mymodule/themes/fancytheme/default/
+
+If you need to make more extensive customizations to the base template, you should copy it from the base theme:
+
+	cp templates/base.twig modules/mymodule/themes/fancytheme/default/
+
+Any references to `$this->data['baseurlpath']` in old-style templates can be replaced with `{{baseurlpath}}` in Twig templates. Likewise, references to `\SimpleSAML\Module::getModuleURL()` can be replaced with `{{baseurlpath}}module.php/mymodule/...`
+
+See the [Twig documentation](https://twig.symfony.com/doc/1.x/templates.html) for more information on using variables and expressions in Twig templates, and the SimpleSAMLphp wiki for [our conventions](https://github.com/simplesamlphp/simplesamlphp/wiki/Twig-conventions).
+
+The wiki also includes some information on [migrating translations](https://github.com/simplesamlphp/simplesamlphp/wiki/Migrating-translation-in-Twig) and [migrating templates](https://github.com/simplesamlphp/simplesamlphp/wiki/Twig:-Migrating-templates).
diff --git a/docs/simplesamlphp-upgrade-notes-1.15.md b/docs/simplesamlphp-upgrade-notes-1.15.md
index 19523af595a2397051f980bc29990f2fdcecba0d..a4ffd2483d3c320b80ac1e00607b8c154b033cda 100644
--- a/docs/simplesamlphp-upgrade-notes-1.15.md
+++ b/docs/simplesamlphp-upgrade-notes-1.15.md
@@ -5,7 +5,9 @@ The minimum required PHP version is now 5.4. The dependency on mcrypt has been
 dropped.
 
 A new templating system based on Twig has been introduced. The old templating
-system is still available but should be considered deprecated.
+system is still available but should be considered deprecated. Custom themes
+may need to be updated to include Twig-style templates as well. See the
+[theming documentation](simplesamlphp-theming).
 
 A new internationalization system based on Gettext has been introduced. While
 old templates can use either the old or the new system (refer to the
diff --git a/docs/simplesamlphp-upgrade-notes-1.16.md b/docs/simplesamlphp-upgrade-notes-1.16.md
new file mode 100644
index 0000000000000000000000000000000000000000..b7f225947acc6835d654e5fae7ba39b57be2e320
--- /dev/null
+++ b/docs/simplesamlphp-upgrade-notes-1.16.md
@@ -0,0 +1,25 @@
+Upgrade notes for SimpleSAMLphp 1.16
+====================================
+
+The default signature algoritm is now SHA-256 (SHA-1 has been considered
+obsolete since 2014). For entities that need it, you can switch back to
+SHA-1 by setting the `signature.algorithm` option in the remote entity
+metadata.
+
+In the Consent module, the `noconsentattributes` has been renamed to
+`attributes.exclude`. The old name continues to work but is considered
+deprecated.
+
+The class `SimpleSAML_Error_BadUserInnput` has been renamed to
+`SimpleSAML_Error_BadUserInput`.
+
+The `authmyspace` module has been removed since the service is no longer
+available. 
+
+The `casserver` module has been removed because it was an outdated version,
+the up to date module is maintained in the
+[simplesamlphp-module-casserver](https://github.com/simplesamlphp/simplesamlphp-module-casserver)
+repository. It can be installed with composer:
+```
+composer require simplesamlphp/simplesamlphp-module-casserver
+```
diff --git a/docs/simplesamlphp-upgrade-notes-1.17.md b/docs/simplesamlphp-upgrade-notes-1.17.md
new file mode 100644
index 0000000000000000000000000000000000000000..32a2dae1c7931343013fa49a1a6c4580bd71cbe6
--- /dev/null
+++ b/docs/simplesamlphp-upgrade-notes-1.17.md
@@ -0,0 +1,30 @@
+Upgrade notes for SimpleSAMLphp 1.17
+====================================
+
+The minimum PHP version required is now PHP 5.5.
+
+All (remaining) classes have been changed to namespaces. There are mappings
+from the legacy names so calling code should remain working. Custom code
+(e.g. modules) that test for class names, e.g. when catching specific
+exceptions, may need to be changed.
+
+The code, config and documentation have switched to using the modern PHP
+array syntax. This should not have an impact as both will remain working
+equally, but the code examples and config templates look slightly different.
+The following are equivalent:
+
+    // Old style array syntax
+    $config = array(
+        'authproc' => array(
+            60 => 'class:etc'
+        ),
+        'other example' => 1
+    );
+
+    // Current style array syntax
+    $config = [
+        'authproc' => [
+            60 => 'class:etc'
+        ],
+        'other example' => 1
+    ];
diff --git a/lib/SimpleSAML/Auth/Default.php b/lib/SimpleSAML/Auth/Default.php
index 17ad9c38e575ebf497d7eb6d175418225d367fb4..86c7465cd51706c59d2b46c3bbc51de9da27eb23 100644
--- a/lib/SimpleSAML/Auth/Default.php
+++ b/lib/SimpleSAML/Auth/Default.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Auth;
+
 /**
  * Implements the default behaviour for authentication.
  *
@@ -11,18 +13,17 @@
  *
  * @deprecated This class will be removed in SSP 2.0.
  */
-class SimpleSAML_Auth_Default
-{
-
 
+class DefaultAuth
+{
     /**
-     * @deprecated This method will be removed in SSP 2.0. Use SimpleSAML_Auth_Source::initLogin() instead.
+     * @deprecated This method will be removed in SSP 2.0. Use Source::initLogin() instead.
      */
     public static function initLogin(
         $authId,
         $return,
         $errorURL = null,
-        array $params = array()
+        array $params = []
     ) {
 
         $as = self::getAuthSource($authId);
@@ -32,21 +33,20 @@ class SimpleSAML_Auth_Default
 
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use
-     * SimpleSAML_Auth_State::getPersistentAuthData() instead.
+     * State::getPersistentAuthData() instead.
      */
     public static function extractPersistentAuthState(array &$state)
     {
-
-        return SimpleSAML_Auth_State::getPersistentAuthData($state);
+        return State::getPersistentAuthData($state);
     }
 
 
     /**
-     * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML_Auth_Source::loginCompleted() instead.
+     * @deprecated This method will be removed in SSP 2.0. Please use Source::loginCompleted() instead.
      */
     public static function loginCompleted($state)
     {
-        SimpleSAML_Auth_Source::loginCompleted($state);
+        Source::loginCompleted($state);
     }
 
 
@@ -58,15 +58,15 @@ class SimpleSAML_Auth_Default
         assert(is_string($returnURL));
         assert(is_string($authority));
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
 
         $state = $session->getAuthData($authority, 'LogoutState');
         $session->doLogout($authority);
 
-        $state['SimpleSAML_Auth_Default.ReturnURL'] = $returnURL;
-        $state['LogoutCompletedHandler'] = array(get_class(), 'logoutCompleted');
+        $state['\SimpleSAML\Auth\DefaultAuth.ReturnURL'] = $returnURL;
+        $state['LogoutCompletedHandler'] = [get_class(), 'logoutCompleted'];
 
-        $as = SimpleSAML_Auth_Source::getById($authority);
+        $as = Source::getById($authority);
         if ($as === null) {
             // The authority wasn't an authentication source...
             self::logoutCompleted($state);
@@ -96,28 +96,28 @@ class SimpleSAML_Auth_Default
     public static function logoutCompleted($state)
     {
         assert(is_array($state));
-        assert(array_key_exists('SimpleSAML_Auth_Default.ReturnURL', $state));
+        assert(array_key_exists('\SimpleSAML\Auth\DefaultAuth.ReturnURL', $state));
 
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['SimpleSAML_Auth_Default.ReturnURL']);
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['\SimpleSAML\Auth\DefaultAuth.ReturnURL']);
     }
 
 
     /**
-     * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML_Auth_Source::logoutCallback() instead.
+     * @deprecated This method will be removed in SSP 2.0. Please use Source::logoutCallback() instead.
      */
     public static function logoutCallback($state)
     {
-        SimpleSAML_Auth_Source::logoutCallback($state);
+        Source::logoutCallback($state);
     }
 
 
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use
-     * sspmod_saml_Auth_Source_SP::handleUnsolicitedAuth() instead.
+     * \SimpleSAML\Module\saml\Auth\Source\SP::handleUnsolicitedAuth() instead.
      */
     public static function handleUnsolicitedAuth($authId, array $state, $redirectTo)
     {
-        sspmod_saml_Auth_Source_SP::handleUnsolicitedAuth($authId, $state, $redirectTo);
+        \SimpleSAML\Module\saml\Auth\Source\SP::handleUnsolicitedAuth($authId, $state, $redirectTo);
     }
 
 
@@ -125,14 +125,14 @@ class SimpleSAML_Auth_Default
      * Return an authentication source by ID.
      *
      * @param string $id The id of the authentication source.
-     * @return SimpleSAML_Auth_Source The authentication source.
-     * @throws Exception If the $id does not correspond with an authentication source.
+     * @return Source The authentication source.
+     * @throws \Exception If the $id does not correspond with an authentication source.
      */
     private static function getAuthSource($id)
     {
-        $as = SimpleSAML_Auth_Source::getById($id);
+        $as = Source::getById($id);
         if ($as === null) {
-            throw new Exception('Invalid authentication source: ' . $id);
+            throw new \Exception('Invalid authentication source: '.$id);
         }
         return $as;
     }
diff --git a/lib/SimpleSAML/Auth/LDAP.php b/lib/SimpleSAML/Auth/LDAP.php
index cc7cf38bccab084105aaf8cde04410850594ad11..c83d221f9c73d69869edf334a97e77f16a96121a 100644
--- a/lib/SimpleSAML/Auth/LDAP.php
+++ b/lib/SimpleSAML/Auth/LDAP.php
@@ -1,8 +1,14 @@
 <?php
 
+namespace SimpleSAML\Auth;
+
+use SimpleSAML\Error;
+use SimpleSAML\Logger;
+
 /**
  * Constants defining possible errors
  */
+
 define('ERR_INTERNAL', 1);
 define('ERR_NO_USER', 2);
 define('ERR_WRONG_PW', 3);
@@ -22,7 +28,8 @@ if (!defined('LDAP_OPT_DIAGNOSTIC_MESSAGE')) {
  * @author Anders Lund, UNINETT AS. <anders.lund@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Auth_LDAP
+
+class LDAP
 {
     /**
      * LDAP link identifier.
@@ -53,15 +60,21 @@ class SimpleSAML_Auth_LDAP
      * @param int $port
      * @param bool $referrals
      */
-    public function __construct($hostname, $enable_tls = true, $debug = false, $timeout = 0, $port = 389, $referrals = true)
-    {
+    public function __construct(
+        $hostname,
+        $enable_tls = true,
+        $debug = false,
+        $timeout = 0,
+        $port = 389,
+        $referrals = true
+    ) {
         // Debug
-        SimpleSAML\Logger::debug('Library - LDAP __construct(): Setup LDAP with ' .
-                        'host=\'' . $hostname .
-                        '\', tls=' . var_export($enable_tls, true) .
-                        ', debug=' . var_export($debug, true) .
-                        ', timeout=' . var_export($timeout, true) .
-                        ', referrals=' . var_export($referrals, true));
+        Logger::debug('Library - LDAP __construct(): Setup LDAP with '.
+            'host=\''.$hostname.
+            '\', tls='.var_export($enable_tls, true).
+            ', debug='.var_export($debug, true).
+            ', timeout='.var_export($timeout, true).
+            ', referrals='.var_export($referrals, true));
 
         /*
          * Set debug level before calling connect. Note that this passes
@@ -70,26 +83,36 @@ class SimpleSAML_Auth_LDAP
          * OpenLDAP 2.x.x or Netscape Directory SDK x.x needed for this option.
          */
         if ($debug && !ldap_set_option(null, LDAP_OPT_DEBUG_LEVEL, 7)) {
-                SimpleSAML\Logger::warning('Library - LDAP __construct(): Unable to set debug level (LDAP_OPT_DEBUG_LEVEL) to 7');
+            Logger::warning('Library - LDAP __construct(): Unable to set debug level (LDAP_OPT_DEBUG_LEVEL) to 7');
         }
 
         /*
          * Prepare a connection for to this LDAP server. Note that this function
          * doesn't actually connect to the server.
          */
-        $this->ldap = @ldap_connect($hostname, $port);
-        if ($this->ldap === false) {
-            throw $this->makeException('Library - LDAP __construct(): Unable to connect to \'' . $hostname . '\'', ERR_INTERNAL);
+        $resource = @ldap_connect($hostname, $port);
+        if ($resource === false) {
+            throw $this->makeException(
+                'Library - LDAP __construct(): Unable to connect to \''.$hostname.'\'',
+                ERR_INTERNAL
+            );
         }
+        $this->ldap = $resource;
 
         // Enable LDAP protocol version 3
         if (!@ldap_set_option($this->ldap, LDAP_OPT_PROTOCOL_VERSION, 3)) {
-            throw $this->makeException('Library - LDAP __construct(): Failed to set LDAP Protocol version (LDAP_OPT_PROTOCOL_VERSION) to 3', ERR_INTERNAL);
+            throw $this->makeException(
+                'Library - LDAP __construct(): Failed to set LDAP Protocol version (LDAP_OPT_PROTOCOL_VERSION) to 3',
+                ERR_INTERNAL
+            );
         }
 
         // Set referral option
         if (!@ldap_set_option($this->ldap, LDAP_OPT_REFERRALS, $referrals)) {
-            throw $this->makeException('Library - LDAP __construct(): Failed to set LDAP Referrals (LDAP_OPT_REFERRALS) to '.$referrals, ERR_INTERNAL);
+            throw $this->makeException(
+                'Library - LDAP __construct(): Failed to set LDAP Referrals (LDAP_OPT_REFERRALS) to '.$referrals,
+                ERR_INTERNAL
+            );
         }
 
         // Set timeouts, if supported
@@ -97,17 +120,22 @@ class SimpleSAML_Auth_LDAP
         $this->timeout = $timeout;
         if ($timeout > 0) {
             if (!@ldap_set_option($this->ldap, LDAP_OPT_NETWORK_TIMEOUT, $timeout)) {
-                SimpleSAML\Logger::warning('Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_NETWORK_TIMEOUT) to ' . $timeout);
+                Logger::warning(
+                    'Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_NETWORK_TIMEOUT) to '.$timeout
+                );
             }
             if (!@ldap_set_option($this->ldap, LDAP_OPT_TIMELIMIT, $timeout)) {
-                SimpleSAML\Logger::warning('Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_TIMELIMIT) to ' . $timeout);
+                Logger::warning(
+                    'Library - LDAP __construct(): Unable to set timeouts (LDAP_OPT_TIMELIMIT) to '.$timeout
+                );
             }
         }
 
         // Enable TLS, if needed
         if (stripos($hostname, "ldaps:") === false && $enable_tls) {
             if (!@ldap_start_tls($this->ldap)) {
-                throw $this->makeException('Library - LDAP __construct(): Unable to force TLS', ERR_INTERNAL);
+                throw $this->makeException('Library - LDAP __construct():'.
+                    ' Unable to force TLS', ERR_INTERNAL);
             }
         }
     }
@@ -119,7 +147,7 @@ class SimpleSAML_Auth_LDAP
      *
      * @param string $description
      * The exception's description
-     * @return Exception
+     * @return \Exception
      */
     private function makeException($description, $type = null)
     {
@@ -127,7 +155,7 @@ class SimpleSAML_Auth_LDAP
 
         // Log LDAP code and description, if possible
         if (empty($this->ldap)) {
-            SimpleSAML\Logger::error($description);
+            Logger::error($description);
         } else {
             $errNo = @ldap_errno($this->ldap);
         }
@@ -136,45 +164,48 @@ class SimpleSAML_Auth_LDAP
         if ($type) {
             if ($errNo !== 0) {
                 // Only log real LDAP errors; not success
-                SimpleSAML\Logger::error($description . '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')');
+                Logger::error($description.'; cause: \''.ldap_error($this->ldap).'\' (0x'.dechex($errNo).')');
             } else {
-                SimpleSAML\Logger::error($description);
+                Logger::error($description);
             }
 
             switch ($type) {
                 case ERR_INTERNAL:// 1 - ExInternal
-                    return new SimpleSAML_Error_Exception($description, $errNo);
+                    return new Error\Exception($description, $errNo);
                 case ERR_NO_USER:// 2 - ExUserNotFound
-                    return new SimpleSAML_Error_UserNotFound($description, $errNo);
+                    return new Error\UserNotFound($description, $errNo);
                 case ERR_WRONG_PW:// 3 - ExInvalidCredential
-                    return new SimpleSAML_Error_InvalidCredential($description, $errNo);
+                    return new Error\InvalidCredential($description, $errNo);
                 case ERR_AS_DATA_INCONSIST:// 4 - ExAsDataInconsist
-                    return new SimpleSAML_Error_AuthSource('ldap', $description);
+                    return new Error\AuthSource('ldap', $description);
                 case ERR_AS_INTERNAL:// 5 - ExAsInternal
-                    return new SimpleSAML_Error_AuthSource('ldap', $description);
+                    return new Error\AuthSource('ldap', $description);
             }
         } else {
             if ($errNo !== 0) {
-                $description .= '; cause: \'' . ldap_error($this->ldap) . '\' (0x' . dechex($errNo) . ')';
-                if (@ldap_get_option($this->ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extendedError) && !empty($extendedError)) {
-                    $description .= '; additional: \'' . $extendedError . '\'';
+                $description .= '; cause: \''.ldap_error($this->ldap).'\' (0x'.dechex($errNo).')';
+                if (@ldap_get_option($this->ldap, LDAP_OPT_DIAGNOSTIC_MESSAGE, $extendedError)
+                    && !empty($extendedError)
+                ) {
+                    $description .= '; additional: \''.$extendedError.'\'';
                 }
             }
             switch ($errNo) {
                 case 0x20://LDAP_NO_SUCH_OBJECT
-                    SimpleSAML\Logger::warning($description);
-                    return new SimpleSAML_Error_UserNotFound($description, $errNo);
+                    Logger::warning($description);
+                    return new Error\UserNotFound($description, $errNo);
                 case 0x31://LDAP_INVALID_CREDENTIALS
-                    SimpleSAML\Logger::info($description);
-                    return new SimpleSAML_Error_InvalidCredential($description, $errNo);
+                    Logger::info($description);
+                    return new Error\InvalidCredential($description, $errNo);
                 case -1://NO_SERVER_CONNECTION
-                    SimpleSAML\Logger::error($description);
-                    return new SimpleSAML_Error_AuthSource('ldap', $description);
+                    Logger::error($description);
+                    return new Error\AuthSource('ldap', $description);
                 default:
-                    SimpleSAML\Logger::error($description);
-                    return new SimpleSAML_Error_AuthSource('ldap', $description);
+                    Logger::error($description);
+                    return new Error\AuthSource('ldap', $description);
             }
         }
+        return new \Exception('Unknown LDAP error.');
     }
 
 
@@ -187,41 +218,54 @@ class SimpleSAML_Auth_LDAP
      * The attribute name(s) to search for.
      * @param string $value
      * The attribute value to search for.
+     * Additional search filter
+     * @param string|null $searchFilter
+     * The scope of the search
+     * @param string $scope
      * @return string
      * The DN of the resulting found element.
-     * @throws SimpleSAML_Error_Exception if:
+     * @throws Error\Exception if:
      * - Attribute parameter is wrong type
-     * @throws SimpleSAML_Error_AuthSource if:
+     * @throws Error\AuthSource if:
      * - Not able to connect to LDAP server
      * - False search result
      * - Count return false
      * - Searche found more than one result
      * - Failed to get first entry from result
      * - Failed to get DN for entry
-     * @throws SimpleSAML_Error_UserNotFound if:
+     * @throws Error\UserNotFound if:
      * - Zero entries were found
      */
-    private function search($base, $attribute, $value, $searchFilter = null)
+    private function search($base, $attribute, $value, $searchFilter = null, $scope = "subtree")
     {
         // Create the search filter
         $attribute = self::escape_filter_value($attribute, false);
         $value = self::escape_filter_value($value, true);
         $filter = '';
         foreach ($attribute as $attr) {
-            $filter .= '(' . $attr . '=' . $value. ')';
+            $filter .= '('.$attr.'='.$value.')';
         }
-        $filter = '(|' . $filter . ')';
+        $filter = '(|'.$filter.')';
 
         // Append LDAP filters if defined
-        if ($searchFilter != null) {
+        if ($searchFilter !== null) {
             $filter = "(&".$filter."".$searchFilter.")";
         }
 
         // Search using generated filter
-        SimpleSAML\Logger::debug('Library - LDAP search(): Searching base \'' . $base . '\' for \'' . $filter . '\'');
-        $result = @ldap_search($this->ldap, $base, $filter, array(), 0, 0, $this->timeout, LDAP_DEREF_NEVER);
+        Logger::debug('Library - LDAP search(): Searching base ('.$scope.') \''.$base.'\' for \''.$filter.'\'');
+        if ($scope === 'base') {
+            $result = @ldap_read($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
+        } elseif ($scope === 'onelevel') {
+            $result = @ldap_list($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
+        } else {
+            $result = @ldap_search($this->ldap, $base, $filter, [], 0, 0, $this->timeout, LDAP_DEREF_NEVER);
+        }
+
         if ($result === false) {
-            throw $this->makeException('Library - LDAP search(): Failed search on base \'' . $base . '\' for \'' . $filter . '\'');
+            throw $this->makeException(
+                'Library - LDAP search(): Failed search on base \''.$base.'\' for \''.$filter.'\''
+            );
         }
 
         // Sanity checks on search results
@@ -230,21 +274,32 @@ class SimpleSAML_Auth_LDAP
             throw $this->makeException('Library - LDAP search(): Failed to get number of entries returned');
         } elseif ($count > 1) {
             // More than one entry is found. External error
-            throw $this->makeException('Library - LDAP search(): Found ' . $count . ' entries searching base \'' . $base . '\' for \'' . $filter . '\'', ERR_AS_DATA_INCONSIST);
+            throw $this->makeException(
+                'Library - LDAP search(): Found '.$count.' entries searching base \''.$base.'\' for \''.$filter.'\'',
+                ERR_AS_DATA_INCONSIST
+            );
         } elseif ($count === 0) {
             // No entry is fond => wrong username is given (or not registered in the catalogue). User error
-            throw $this->makeException('Library - LDAP search(): Found no entries searching base \'' . $base . '\' for \'' . $filter . '\'', ERR_NO_USER);
+            throw $this->makeException(
+                'Library - LDAP search(): Found no entries searching base \''.$base.'\' for \''.$filter.'\'',
+                ERR_NO_USER
+            );
         }
 
 
         // Resolve the DN from the search result
         $entry = @ldap_first_entry($this->ldap, $result);
         if ($entry === false) {
-            throw $this->makeException('Library - LDAP search(): Unable to retrieve result after searching base \'' . $base . '\' for \'' . $filter . '\'');
+            throw $this->makeException(
+                'Library - LDAP search(): Unable to retrieve result after searching base \''.
+                    $base.'\' for \''.$filter.'\''
+            );
         }
         $dn = @ldap_get_dn($this->ldap, $entry);
         if ($dn === false) {
-            throw $this->makeException('Library - LDAP search(): Unable to get DN after searching base \'' . $base . '\' for \'' . $filter . '\'');
+            throw $this->makeException(
+                'Library - LDAP search(): Unable to get DN after searching base \''.$base.'\' for \''.$filter.'\''
+            );
         }
         return $dn;
     }
@@ -264,44 +319,52 @@ class SimpleSAML_Auth_LDAP
      * Defaults to FALSE.
      * @param string|null $searchFilter
      * Additional searchFilter to be added to the (attribute=value) filter
+     * @param string $scope
+     * The scope of the search
      * @return string
      * The DN of the matching element, if found. If no element was found and
      * $allowZeroHits is set to FALSE, an exception will be thrown; otherwise
      * NULL will be returned.
-     * @throws SimpleSAML_Error_AuthSource if:
+     * @throws Error\AuthSource if:
      * - LDAP search encounter some problems when searching cataloge
      * - Not able to connect to LDAP server
-     * @throws SimpleSAML_Error_UserNotFound if:
+     * @throws Error\UserNotFound if:
      * - $allowZeroHits is FALSE and no result is found
      *
      */
-    public function searchfordn($base, $attribute, $value, $allowZeroHits = false, $searchFilter = null)
-    {
+    public function searchfordn(
+        $base,
+        $attribute,
+        $value,
+        $allowZeroHits = false,
+        $searchFilter = null,
+        $scope = 'subtree'
+    ) {
         // Traverse all search bases, returning DN if found
-        $bases = SimpleSAML\Utils\Arrays::arrayize($base);
+        $bases = \SimpleSAML\Utils\Arrays::arrayize($base);
         foreach ($bases as $current) {
             try {
                 // Single base search
-                $result = $this->search($current, $attribute, $value, $searchFilter);
+                $result = $this->search($current, $attribute, $value, $searchFilter, $scope);
 
                 // We don't hawe to look any futher if user is found
                 if (!empty($result)) {
                     return $result;
                 }
                 // If search failed, attempt the other base DNs
-            } catch (SimpleSAML_Error_UserNotFound $e) {
+            } catch (Error\UserNotFound $e) {
                 // Just continue searching
             }
         }
         // Decide what to do for zero entries
-        SimpleSAML\Logger::debug('Library - LDAP searchfordn(): No entries found');
+        Logger::debug('Library - LDAP searchfordn(): No entries found');
         if ($allowZeroHits) {
             // Zero hits allowed
             return null;
         } else {
             // Zero hits not allowed
-            throw $this->makeException('Library - LDAP searchfordn(): LDAP search returned zero entries for filter \'(' .
-                join(' | ', $attribute) . ' = ' . $value . ')\' on base(s) \'(' . join(' & ', $bases) . ')\'', 2);
+            throw $this->makeException('Library - LDAP searchfordn(): LDAP search returned zero entries for'.
+                ' filter \'('.join(' | ', $attribute).' = '.$value.')\' on base(s) \'('.join(' & ', $bases).')\'', 2);
         }
     }
 
@@ -310,16 +373,24 @@ class SimpleSAML_Auth_LDAP
      * This method was created specifically for the ldap:AttributeAddUsersGroups->searchActiveDirectory()
      * method, but could be used for other LDAP search needs. It will search LDAP and return all the entries.
      *
-     * @throws Exception
+     * @throws \Exception
      * @param string|array $bases
-     * @param string|array $filters Array of 'attribute' => 'values' to be combined into the filter, or a raw filter string
+     * @param string|array $filters Array of 'attribute' => 'values' to be combined into the filter,
+     *     or a raw filter string
      * @param string|array $attributes Array of attributes requested from LDAP
      * @param bool $and If multiple filters defined, then either bind them with & or |
      * @param bool $escape Weather to escape the filter values or not
+     * @param string $scope The scope of the search
      * @return array
      */
-    public function searchformultiple($bases, $filters, $attributes = array(), $and = true, $escape = true)
-    {
+    public function searchformultiple(
+        $bases,
+        $filters,
+        $attributes = [],
+        $and = true,
+        $escape = true,
+        $scope = 'subtree'
+    ) {
         // Escape the filter values, if requested
         if ($escape) {
             $filters = $this->escape_filter_value($filters, false);
@@ -332,7 +403,7 @@ class SimpleSAML_Auth_LDAP
                 $filter .= "($attribute=$value)";
             }
             if (count($filters) > 1) {
-                $filter = ($and ? '(&' : '(|') . $filter . ')';
+                $filter = ($and ? '(&' : '(|').$filter.')';
             }
         } elseif (is_string($filters)) {
             $filter = $filters;
@@ -352,7 +423,14 @@ class SimpleSAML_Auth_LDAP
         // Search each base until result is found
         $result = false;
         foreach ($bases as $base) {
-            $result = @ldap_search($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
+            if ($scope === 'base') {
+                $result = @ldap_read($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
+            } elseif ($scope === 'onelevel') {
+                $result = @ldap_list($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
+            } else {
+                $result = @ldap_search($this->ldap, $base, $filter, $attributes, 0, 0, $this->timeout);
+            }
+
             if ($result !== false && @ldap_count_entries($this->ldap, $result) > 0) {
                 break;
             }
@@ -361,14 +439,14 @@ class SimpleSAML_Auth_LDAP
         // Verify that a result was found in one of the bases
         if ($result === false) {
             throw $this->makeException(
-                'ldap:LdapConnection->search_manual : Failed to search LDAP using base(s) [' .
-                implode('; ', $bases) . '] with filter [' . $filter . ']. LDAP error [' .
-                ldap_error($this->ldap) . ']'
+                'ldap:LdapConnection->search_manual : Failed to search LDAP using base(s) ['.
+                implode('; ', $bases).'] with filter ['.$filter.']. LDAP error ['.
+                ldap_error($this->ldap).']'
             );
         } elseif (@ldap_count_entries($this->ldap, $result) < 1) {
             throw $this->makeException(
-                'ldap:LdapConnection->search_manual : No entries found in LDAP using base(s) [' .
-                implode('; ', $bases) . '] with filter [' . $filter . ']',
+                'ldap:LdapConnection->search_manual : No entries found in LDAP using base(s) ['.
+                implode('; ', $bases).'] with filter ['.$filter.']',
                 ERR_NO_USER
             );
         }
@@ -420,7 +498,7 @@ class SimpleSAML_Auth_LDAP
      * Returns TRUE if successful, FALSE if
      * LDAP_INVALID_CREDENTIALS, LDAP_X_PROXY_AUTHZ_FAILURE,
      * LDAP_INAPPROPRIATE_AUTH, LDAP_INSUFFICIENT_ACCESS
-     * @throws SimpleSAML_Error_Exception on other errors
+     * @throws Error\Exception on other errors
      */
     public function bind($dn, $password, array $sasl_args = null)
     {
@@ -451,7 +529,7 @@ class SimpleSAML_Auth_LDAP
         if ($error === true) {
             // Good
             $this->authz_id = $authz_id;
-            SimpleSAML\Logger::debug('Library - LDAP bind(): Bind successful with DN \'' . $dn . '\'');
+            Logger::debug('Library - LDAP bind(): Bind successful with DN \''.$dn.'\'');
             return true;
         }
 
@@ -474,7 +552,7 @@ class SimpleSAML_Auth_LDAP
         }
 
         // Bad
-        throw $this->makeException('Library - LDAP bind(): Bind failed with DN \'' . $dn . '\'');
+        throw $this->makeException('Library - LDAP bind(): Bind failed with DN \''.$dn.'\'');
     }
 
 
@@ -491,16 +569,16 @@ class SimpleSAML_Auth_LDAP
         // Attempt to set the LDAP option
         if (!@ldap_set_option($this->ldap, $option, $value)) {
             throw $this->makeException(
-                'ldap:LdapConnection->setOption : Failed to set LDAP option [' .
-                $option . '] with the value [' . $value . '] error: ' . ldap_error($this->ldap),
+                'ldap:LdapConnection->setOption : Failed to set LDAP option ['.
+                $option.'] with the value ['.$value.'] error: '.ldap_error($this->ldap),
                 ERR_INTERNAL
             );
         }
 
         // Log debug message
-        SimpleSAML\Logger::debug(
-            'ldap:LdapConnection->setOption : Set the LDAP option [' .
-            $option . '] with the value [' . $value . ']'
+        Logger::debug(
+            'ldap:LdapConnection->setOption : Set the LDAP option ['.
+            $option.'] with the value ['.$value.']'
         );
     }
 
@@ -526,50 +604,55 @@ class SimpleSAML_Auth_LDAP
         // Preparations, including a pretty debug message...
         $description = 'all attributes';
         if (is_array($attributes)) {
-            $description = '\'' . join(',', $attributes) . '\'';
+            $description = '\''.join(',', $attributes).'\'';
         } else {
             // Get all attributes...
             // TODO: Verify that this originally was the intended behaviour. Could $attributes be a string?
-            $attributes = array();
+            $attributes = [];
         }
-        SimpleSAML\Logger::debug('Library - LDAP getAttributes(): Getting ' . $description . ' from DN \'' . $dn . '\'');
+        Logger::debug('Library - LDAP getAttributes(): Getting '.$description.' from DN \''.$dn.'\'');
 
         // Attempt to get attributes
         // TODO: Should aliases be dereferenced?
         $result = @ldap_read($this->ldap, $dn, 'objectClass=*', $attributes, 0, 0, $this->timeout);
         if ($result === false) {
-            throw $this->makeException('Library - LDAP getAttributes(): Failed to get attributes from DN \'' . $dn . '\'');
+            throw $this->makeException('Library - LDAP getAttributes(): Failed to get attributes from DN \''.$dn.'\'');
         }
         $entry = @ldap_first_entry($this->ldap, $result);
         if ($entry === false) {
-            throw $this->makeException('Library - LDAP getAttributes(): Could not get first entry from DN \'' . $dn . '\'');
+            throw $this->makeException('Library - LDAP getAttributes(): Could not get first entry from DN \''.$dn.'\'');
         }
-        $attributes = @ldap_get_attributes($this->ldap, $entry);  // Recycling $attributes... Possibly bad practice.
+        $attributes = @ldap_get_attributes($this->ldap, $entry); // Recycling $attributes... Possibly bad practice.
         if ($attributes === false) {
-            throw $this->makeException('Library - LDAP getAttributes(): Could not get attributes of first entry from DN \'' . $dn . '\'');
+            throw $this->makeException(
+                'Library - LDAP getAttributes(): Could not get attributes of first entry from DN \''.$dn.'\''
+            );
         }
 
         // Parsing each found attribute into our result set
-        $result = array();  // Recycling $result... Possibly bad practice.
+        $result = []; // Recycling $result... Possibly bad practice.
         for ($i = 0; $i < $attributes['count']; $i++) {
             // Ignore attributes that exceed the maximum allowed size
             $name = $attributes[$i];
             $attribute = $attributes[$name];
 
             // Deciding whether to base64 encode
-            $values = array();
+            $values = [];
             for ($j = 0; $j < $attribute['count']; $j++) {
                 $value = $attribute[$j];
 
-                if (!empty($maxsize) && strlen($value) >= $maxsize) {
+                if (!empty($maxsize) && strlen($value) > $maxsize) {
                     // Ignoring and warning
-                    SimpleSAML\Logger::warning('Library - LDAP getAttributes(): Attribute \'' .
-                        $name . '\' exceeded maximum allowed size by ' + ($maxsize - strlen($value)));
+                    Logger::warning('Library - LDAP getAttributes(): Attribute \''.
+                        $name.'\' exceeded maximum allowed size by '.(strlen($value) - $maxsize));
                     continue;
                 }
 
                 // Base64 encode binary attributes
-                if (strtolower($name) === 'jpegphoto' || strtolower($name) === 'objectguid') {
+                if (strtolower($name) === 'jpegphoto'
+                    || strtolower($name) === 'objectguid'
+                    || strtolower($name) === 'ms-ds-consistencyguid'
+                ) {
                     $values[] = base64_encode($value);
                 } else {
                     $values[] = $value;
@@ -581,7 +664,7 @@ class SimpleSAML_Auth_LDAP
         }
 
         // We're done
-        SimpleSAML\Logger::debug('Library - LDAP getAttributes(): Found attributes \'(' . join(',', array_keys($result)) . ')\'');
+        Logger::debug('Library - LDAP getAttributes(): Found attributes \'('.join(',', array_keys($result)).')\'');
         return $result;
     }
 
@@ -612,11 +695,14 @@ class SimpleSAML_Auth_LDAP
             $dn = $this->searchfordn($config['searchbase'], $config['searchattributes'], $username);
         }
 
-        if ($password !== null) { // checking users credentials ... assuming below that she may read her own attributes ...
+        if ($password !== null) {
+            // checking users credentials ... assuming below that she may read her own attributes ...
             // escape characters with a special meaning, also in the password
             $password = addcslashes($password, ',+"\\<>;*');
             if (!$this->bind($dn, $password)) {
-                SimpleSAML\Logger::info('Library - LDAP validate(): Failed to authenticate \''. $username . '\' using DN \'' . $dn . '\'');
+                Logger::info(
+                    'Library - LDAP validate(): Failed to authenticate \''.$username.'\' using DN \''.$dn.'\''
+                );
                 return false;
             }
         }
@@ -642,7 +728,7 @@ class SimpleSAML_Auth_LDAP
      * @param string|array $values Array of values to escape
      * @return array Array $values, but escaped
      */
-    public static function escape_filter_value($values = array(), $singleValue = true)
+    public static function escape_filter_value($values = [], $singleValue = true)
     {
         // Parameter validation
         $values = \SimpleSAML\Utils\Arrays::arrayize($values);
@@ -658,7 +744,7 @@ class SimpleSAML_Auth_LDAP
             $val = self::asc2hex32($val);
 
             if (null === $val) {
-                $val = '\0';  // apply escaped "null" if string is empty
+                $val = '\0'; // apply escaped "null" if string is empty
             }
 
             $values[$key] = $val;
@@ -698,7 +784,7 @@ class SimpleSAML_Auth_LDAP
     /**
      * Convert SASL authz_id into a DN
      */
-    private function authzid_to_dn($searchBase, $searchAttributes, $authz_id)
+    private function authzidToDn($searchBase, $searchAttributes, $authz_id)
     {
         if (preg_match("/^dn:/", $authz_id)) {
             return preg_replace("/^dn:/", "", $authz_id);
@@ -743,7 +829,7 @@ class SimpleSAML_Auth_LDAP
             $authz_id = $this->authz_id;
         }
 
-        $dn = $this->authzid_to_dn($searchBase, $searchAttributes, $authz_id);
+        $dn = $this->authzidToDn($searchBase, $searchAttributes, $authz_id);
 
         if (!isset($dn) || ($dn == '')) {
             throw $this->makeException('Cannot figure userID');
diff --git a/lib/SimpleSAML/Auth/ProcessingChain.php b/lib/SimpleSAML/Auth/ProcessingChain.php
index 1477203f73d366b8e0aa9463e3f6b6bb92f933cc..9f7daf3a3b2bb55cf4576fa3935c1003a269b293 100644
--- a/lib/SimpleSAML/Auth/ProcessingChain.php
+++ b/lib/SimpleSAML/Auth/ProcessingChain.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Auth;
+
 /**
  * Class for implementing authentication processing chains for IdPs.
  *
@@ -10,20 +12,19 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Auth_ProcessingChain
-{
-
 
+class ProcessingChain
+{
     /**
      * The list of remaining filters which should be applied to the state.
      */
-    const FILTERS_INDEX = 'SimpleSAML_Auth_ProcessingChain.filters';
+    const FILTERS_INDEX = '\SimpleSAML\Auth\ProcessingChain.filters';
 
 
     /**
      * The stage we use for completed requests.
      */
-    const COMPLETED_STAGE = 'SimpleSAML_Auth_ProcessingChain.completed';
+    const COMPLETED_STAGE = '\SimpleSAML\Auth\ProcessingChain.completed';
 
 
     /**
@@ -51,10 +52,10 @@ class SimpleSAML_Auth_ProcessingChain
         assert(is_array($idpMetadata));
         assert(is_array($spMetadata));
 
-        $this->filters = array();
+        $this->filters = [];
 
-        $config = SimpleSAML_Configuration::getInstance();
-        $configauthproc = $config->getArray('authproc.' . $mode, null);
+        $config = \SimpleSAML\Configuration::getInstance();
+        $configauthproc = $config->getArray('authproc.'.$mode, null);
 
         if (!empty($configauthproc)) {
             $configfilters = self::parseFilterList($configauthproc);
@@ -71,9 +72,8 @@ class SimpleSAML_Auth_ProcessingChain
             self::addFilters($this->filters, $spFilters);
         }
 
-
-        SimpleSAML\Logger::debug('Filter config for ' . $idpMetadata['entityid'] . '->' .
-            $spMetadata['entityid'] . ': ' . str_replace("\n", '', var_export($this->filters, true)));
+        \SimpleSAML\Logger::debug('Filter config for '.$idpMetadata['entityid'].'->'.
+            $spMetadata['entityid'].': '.str_replace("\n", '', var_export($this->filters, true)));
     }
 
 
@@ -94,14 +94,14 @@ class SimpleSAML_Auth_ProcessingChain
             $fp = $filter->priority;
 
             // Find insertion position for filter
-            for ($i = count($target)-1; $i >= 0; $i--) {
+            for ($i = count($target) - 1; $i >= 0; $i--) {
                 if ($target[$i]->priority <= $fp) {
                     // The new filter should be inserted after this one
                     break;
                 }
             }
             /* $i now points to the filter which should preceede the current filter. */
-            array_splice($target, $i+1, 0, array($filter));
+            array_splice($target, $i + 1, 0, [$filter]);
         }
     }
 
@@ -110,21 +110,21 @@ class SimpleSAML_Auth_ProcessingChain
      * Parse an array of authentication processing filters.
      *
      * @param array $filterSrc  Array with filter configuration.
-     * @return array  Array of SimpleSAML_Auth_ProcessingFilter objects.
+     * @return array  Array of ProcessingFilter objects.
      */
     private static function parseFilterList($filterSrc)
     {
         assert(is_array($filterSrc));
 
-        $parsedFilters = array();
+        $parsedFilters = [];
 
         foreach ($filterSrc as $priority => $filter) {
             if (is_string($filter)) {
-                $filter = array('class' => $filter);
+                $filter = ['class' => $filter];
             }
 
             if (!is_array($filter)) {
-                throw new Exception('Invalid authentication processing filter configuration: ' .
+                throw new \Exception('Invalid authentication processing filter configuration: '.
                     'One of the filters wasn\'t a string or an array.');
             }
 
@@ -138,20 +138,24 @@ class SimpleSAML_Auth_ProcessingChain
     /**
      * Parse an authentication processing filter.
      *
-     * @param array $config     Array with the authentication processing filter configuration.
-     * @param int $priority     The priority of the current filter, (not included in the filter
-     *                          definition.)
-     * @return SimpleSAML_Auth_ProcessingFilter  The parsed filter.
+     * @param array $config      Array with the authentication processing filter configuration.
+     * @param int $priority      The priority of the current filter, (not included in the filter
+     *                           definition.)
+     * @return ProcessingFilter  The parsed filter.
      */
     private static function parseFilter($config, $priority)
     {
         assert(is_array($config));
 
         if (!array_key_exists('class', $config)) {
-            throw new Exception('Authentication processing filter without name given.');
+            throw new \Exception('Authentication processing filter without name given.');
         }
 
-        $className = SimpleSAML\Module::resolveClass($config['class'], 'Auth_Process', 'SimpleSAML_Auth_ProcessingFilter');
+        $className = \SimpleSAML\Module::resolveClass(
+            $config['class'],
+            'Auth_Process',
+            '\SimpleSAML\Auth\ProcessingFilter'
+        );
         $config['%priority'] = $priority;
         unset($config['class']);
         return new $className($config, null);
@@ -170,11 +174,11 @@ class SimpleSAML_Auth_ProcessingChain
      * If an exception is thrown during processing, it should be handled by the caller of
      * this function. If the user has redirected to a different page, the exception will be
      * returned through the exception handler defined on the state array. See
-     * SimpleSAML_Auth_State for more information.
+     * State for more information.
      *
-     * @see SimpleSAML_Auth_State
-     * @see SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL
-     * @see SimpleSAML_Auth_State::EXCEPTION_HANDLER_FUNC
+     * @see State
+     * @see State::EXCEPTION_HANDLER_URL
+     * @see State::EXCEPTION_HANDLER_FUNC
      *
      * @param array &$state  The state we are processing.
      */
@@ -197,15 +201,15 @@ class SimpleSAML_Auth_ProcessingChain
                 $filter = array_shift($state[self::FILTERS_INDEX]);
                 $filter->process($state);
             }
-        } catch (SimpleSAML_Error_Exception $e) {
+        } catch (\SimpleSAML\Error\Exception $e) {
             // No need to convert the exception
             throw $e;
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             /*
-			 * To be consistent with the exception we return after an redirect,
-			 * we convert this exception before returning it.
-			 */
-            throw new SimpleSAML_Error_UnserializableException($e);
+             * To be consistent with the exception we return after an redirect,
+             * we convert this exception before returning it.
+             */
+            throw new \SimpleSAML\Error\UnserializableException($e);
         }
 
         // Completed
@@ -231,11 +235,11 @@ class SimpleSAML_Auth_ProcessingChain
             $filter = array_shift($state[self::FILTERS_INDEX]);
             try {
                 $filter->process($state);
-            } catch (SimpleSAML_Error_Exception $e) {
-                SimpleSAML_Auth_State::throwException($state, $e);
-            } catch (Exception $e) {
-                $e = new SimpleSAML_Error_UnserializableException($e);
-                SimpleSAML_Auth_State::throwException($state, $e);
+            } catch (\SimpleSAML\Error\Exception $e) {
+                State::throwException($state, $e);
+            } catch (\Exception $e) {
+                $e = new \SimpleSAML\Error\UnserializableException($e);
+                State::throwException($state, $e);
             }
         }
 
@@ -247,16 +251,16 @@ class SimpleSAML_Auth_ProcessingChain
 
         if (array_key_exists('ReturnURL', $state)) {
             /*
-			 * Save state information, and redirect to the URL specified
-			 * in $state['ReturnURL'].
-			 */
-            $id = SimpleSAML_Auth_State::saveState($state, self::COMPLETED_STAGE);
-            \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['ReturnURL'], array(self::AUTHPARAM => $id));
+             * Save state information, and redirect to the URL specified
+             * in $state['ReturnURL'].
+             */
+            $id = State::saveState($state, self::COMPLETED_STAGE);
+            \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['ReturnURL'], [self::AUTHPARAM => $id]);
         } else {
             /* Pass the state to the function defined in $state['ReturnCall']. */
 
             // We are done with the state array in the session. Delete it.
-            SimpleSAML_Auth_State::deleteState($state);
+            State::deleteState($state);
 
             $func = $state['ReturnCall'];
             assert(is_callable($func));
@@ -270,7 +274,7 @@ class SimpleSAML_Auth_ProcessingChain
     /**
      * Process the given state passivly.
      *
-     * Modules with user interaction are expected to throw an SimpleSAML_Error_NoPassive exception
+     * Modules with user interaction are expected to throw an \SimpleSAML\Module\saml\Error\NoPassive exception
      * which are silently ignored. Exceptions of other types are passed further up the call stack.
      *
      * This function will only return if processing completes.
@@ -298,9 +302,11 @@ class SimpleSAML_Auth_ProcessingChain
             $filter = array_shift($state[self::FILTERS_INDEX]);
             try {
                 $filter->process($state);
-
-            // Ignore SimpleSAML_Error_NoPassive exceptions
-            } catch (SimpleSAML_Error_NoPassive $e) {
+            } catch (\SimpleSAML\Error\NoPassive $e) {
+                // @deprecated will be removed in 2.0
+                // Ignore \SimpleSAML\Error\NoPassive exceptions
+            } catch (\SimpleSAML\Module\saml\Error\NoPassive $e) {
+                // Ignore \SimpleSAML\Module\saml\Error\NoPassive exceptions
             }
         }
     }
@@ -309,14 +315,14 @@ class SimpleSAML_Auth_ProcessingChain
      * Retrieve a state which has finished processing.
      *
      * @param string $id The state identifier.
-     * @see SimpleSAML_Auth_State::parseStateID()
-     * @return Array The state referenced by the $id parameter.
+     * @see State::parseStateID()
+     * @return array The state referenced by the $id parameter.
      */
     public static function fetchProcessedState($id)
     {
         assert(is_string($id));
 
-        return SimpleSAML_Auth_State::loadState($id, self::COMPLETED_STAGE);
+        return State::loadState($id, self::COMPLETED_STAGE);
     }
 
 
@@ -330,10 +336,10 @@ class SimpleSAML_Auth_ProcessingChain
 
         if (isset($state['Destination']['userid.attribute'])) {
             $attributeName = $state['Destination']['userid.attribute'];
-            SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
+            \SimpleSAML\Logger::debug("The 'userid.attribute' option has been deprecated.");
         } elseif (isset($state['Source']['userid.attribute'])) {
             $attributeName = $state['Source']['userid.attribute'];
-            SimpleSAML\Logger::warning("The 'userid.attribute' option has been deprecated.");
+            \SimpleSAML\Logger::debug("The 'userid.attribute' option has been deprecated.");
         } else {
             // Default attribute
             $attributeName = 'eduPersonPrincipalName';
@@ -345,12 +351,12 @@ class SimpleSAML_Auth_ProcessingChain
 
         $uid = $state['Attributes'][$attributeName];
         if (count($uid) === 0) {
-            SimpleSAML\Logger::warning('Empty user id attribute [' . $attributeName . '].');
+            \SimpleSAML\Logger::warning('Empty user id attribute ['.$attributeName.'].');
             return;
         }
 
         if (count($uid) > 1) {
-            SimpleSAML\Logger::warning('Multiple attribute values for user id attribute [' . $attributeName . '].');
+            \SimpleSAML\Logger::warning('Multiple attribute values for user id attribute ['.$attributeName.'].');
             return;
         }
 
@@ -358,7 +364,7 @@ class SimpleSAML_Auth_ProcessingChain
         $uid = $uid[0];
 
         if (empty($uid)) {
-            SimpleSAML\Logger::warning('Empty value in attribute '.$attributeName.". on user. Cannot set UserID.");
+            \SimpleSAML\Logger::warning('Empty value in attribute '.$attributeName.". on user. Cannot set UserID.");
             return;
         }
         $state['UserID'] = $uid;
diff --git a/lib/SimpleSAML/Auth/ProcessingFilter.php b/lib/SimpleSAML/Auth/ProcessingFilter.php
index e6126da1de01bd040d39c5a8feff6f813761b290..8c01b1d7b8dcf4e9d5db1494b65bd7facd7c93e0 100644
--- a/lib/SimpleSAML/Auth/ProcessingFilter.php
+++ b/lib/SimpleSAML/Auth/ProcessingFilter.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Auth;
 
 /**
  * Base class for authentication processing filters.
@@ -18,9 +19,9 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-abstract class SimpleSAML_Auth_ProcessingFilter
-{
 
+abstract class ProcessingFilter
+{
     /**
      * Priority of this filter.
      *
@@ -49,7 +50,7 @@ abstract class SimpleSAML_Auth_ProcessingFilter
         if (array_key_exists('%priority', $config)) {
             $this->priority = $config['%priority'];
             if (!is_int($this->priority)) {
-                throw new Exception('Invalid priority: ' . var_export($this->priority, true));
+                throw new \Exception('Invalid priority: '.var_export($this->priority, true));
             }
             unset($config['%priority']);
         }
diff --git a/lib/SimpleSAML/Auth/Simple.php b/lib/SimpleSAML/Auth/Simple.php
index 9ad8e86a2d575cc8ab3a5edd289c4b4266ae8fc9..a0a0aae44a41eb9771b95bb41b85d49c8f3b89a7 100644
--- a/lib/SimpleSAML/Auth/Simple.php
+++ b/lib/SimpleSAML/Auth/Simple.php
@@ -2,12 +2,10 @@
 
 namespace SimpleSAML\Auth;
 
-use \SimpleSAML_Auth_Source as Source;
-use \SimpleSAML_Auth_State as State;
-use \SimpleSAML_Configuration as Configuration;
-use \SimpleSAML_Error_AuthSource as AuthSourceError;
+use \SimpleSAML\Configuration;
+use \SimpleSAML\Error\AuthSource as AuthSourceError;
 use \SimpleSAML\Module;
-use \SimpleSAML_Session as Session;
+use \SimpleSAML\Session;
 use \SimpleSAML\Utils\HTTP;
 
 /**
@@ -15,9 +13,9 @@ use \SimpleSAML\Utils\HTTP;
  *
  * @package SimpleSAMLphp
  */
+
 class Simple
 {
-
     /**
      * The id of the authentication source we are accessing.
      *
@@ -26,7 +24,7 @@ class Simple
     protected $authSource;
 
     /**
-     * @var \SimpleSAML_Configuration|null
+     * @var Configuration|null
      */
     protected $app_config;
 
@@ -47,9 +45,9 @@ class Simple
     /**
      * Retrieve the implementing authentication source.
      *
-     * @return \SimpleSAML_Auth_Source The authentication source.
+     * @return Source The authentication source.
      *
-     * @throws \SimpleSAML_Error_AuthSource If the requested auth source is unknown.
+     * @throws AuthSourceError If the requested auth source is unknown.
      */
     public function getAuthSource()
     {
@@ -90,9 +88,8 @@ class Simple
      *
      * @param array $params Various options to the authentication request. See the documentation.
      */
-    public function requireAuth(array $params = array())
+    public function requireAuth(array $params = [])
     {
-
         $session = Session::getSessionFromRequest();
 
         if ($session->isValid($this->authSource)) {
@@ -118,9 +115,8 @@ class Simple
      *
      * @param array $params Various options to the authentication request.
      */
-    public function login(array $params = array())
+    public function login(array $params = [])
     {
-
         if (array_key_exists('KeepPost', $params)) {
             $keepPost = (bool) $params['KeepPost'];
         } else {
@@ -187,9 +183,9 @@ class Simple
         }
 
         if (is_string($params)) {
-            $params = array(
+            $params = [
                 'ReturnTo' => $params,
-            );
+            ];
         }
 
         assert(is_array($params));
@@ -208,7 +204,7 @@ class Simple
 
             $session->doLogout($this->authSource);
 
-            $params['LogoutCompletedHandler'] = array(get_class(), 'logoutCompleted');
+            $params['LogoutCompletedHandler'] = [get_class(), 'logoutCompleted'];
 
             $as = Source::getById($this->authSource);
             if ($as !== null) {
@@ -236,13 +232,13 @@ class Simple
             call_user_func($state['ReturnCallback'], $state);
             assert(false);
         } else {
-            $params = array();
+            $params = [];
             if (isset($state['ReturnStateParam']) || isset($state['ReturnStateStage'])) {
                 assert(isset($state['ReturnStateParam'], $state['ReturnStateStage']));
                 $stateID = State::saveState($state, $state['ReturnStateStage']);
                 $params[$state['ReturnStateParam']] = $stateID;
             }
-            \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['ReturnTo'], $params);
+            HTTP::redirectTrustedURL($state['ReturnTo'], $params);
         }
     }
 
@@ -257,10 +253,9 @@ class Simple
      */
     public function getAttributes()
     {
-
         if (!$this->isAuthenticated()) {
             // Not authenticated
-            return array();
+            return [];
         }
 
         // Authenticated
@@ -296,7 +291,6 @@ class Simple
      */
     public function getAuthDataArray()
     {
-
         if (!$this->isAuthenticated()) {
             return null;
         }
@@ -322,10 +316,10 @@ class Simple
             $returnTo = HTTP::getSelfURL();
         }
 
-        $login = Module::getModuleURL('core/as_login.php', array(
+        $login = Module::getModuleURL('core/as_login.php', [
             'AuthId'   => $this->authSource,
             'ReturnTo' => $returnTo,
-        ));
+        ]);
 
         return $login;
     }
@@ -347,10 +341,10 @@ class Simple
             $returnTo = HTTP::getSelfURL();
         }
 
-        $logout = Module::getModuleURL('core/as_logout.php', array(
+        $logout = Module::getModuleURL('core/as_logout.php', [
             'AuthId'   => $this->authSource,
             'ReturnTo' => $returnTo,
-        ));
+        ]);
 
         return $logout;
     }
@@ -373,14 +367,14 @@ class Simple
         }
 
         $scheme = parse_url($url, PHP_URL_SCHEME);
-        $host = parse_url($url, PHP_URL_HOST) ?: HTTP::getSelfHost();
-        $port = parse_url($url, PHP_URL_PORT) ?: (
+        $host = parse_url($url, PHP_URL_HOST) ? : HTTP::getSelfHost();
+        $port = parse_url($url, PHP_URL_PORT) ? : (
             $scheme ? '' : trim(HTTP::getServerPort(), ':')
         );
-        $scheme = $scheme ?: (HTTP::getServerHTTPS() ? 'https' : 'http');
-        $path = parse_url($url, PHP_URL_PATH) ?: '/';
-        $query = parse_url($url, PHP_URL_QUERY) ?: '';
-        $fragment = parse_url($url, PHP_URL_FRAGMENT) ?: '';
+        $scheme = $scheme ? : (HTTP::getServerHTTPS() ? 'https' : 'http');
+        $path = parse_url($url, PHP_URL_PATH) ? : '/';
+        $query = parse_url($url, PHP_URL_QUERY) ? : '';
+        $fragment = parse_url($url, PHP_URL_FRAGMENT) ? : '';
 
         $port = !empty($port) ? ':'.$port : '';
         if (($scheme === 'http' && $port === ':80') || ($scheme === 'https' && $port === ':443')) {
@@ -392,7 +386,7 @@ class Simple
             return $scheme.'://'.$host.$port.$path.($query ? '?'.$query : '').($fragment ? '#'.$fragment : '');
         }
 
-        $base =  trim($this->app_config->getString(
+        $base = trim($this->app_config->getString(
             'baseURL',
             $scheme.'://'.$host.$port
         ), '/');
diff --git a/lib/SimpleSAML/Auth/Source.php b/lib/SimpleSAML/Auth/Source.php
index 349d097df7810f252812418a5523768f45984c0d..9cd8486415c308341b93a76a550d4d7ae8fe03f1 100644
--- a/lib/SimpleSAML/Auth/Source.php
+++ b/lib/SimpleSAML/Auth/Source.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Auth;
 
 /**
  * This class defines a base class for authentication source.
@@ -9,10 +10,9 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-abstract class SimpleSAML_Auth_Source
-{
-
 
+abstract class Source
+{
     /**
      * The authentication source identifier. This identifier can be used to look up this object, for example when
      * returning from a login form.
@@ -46,16 +46,16 @@ abstract class SimpleSAML_Auth_Source
      *
      * @param string $type The type of the authentication source.
      *
-     * @return SimpleSAML_Auth_Source[]  Array of SimpleSAML_Auth_Source objects of the specified type.
+     * @return Source[]  Array of \SimpleSAML\Auth\Source objects of the specified type.
      * @throws Exception If the authentication source is invalid.
      */
     public static function getSourcesOfType($type)
     {
         assert(is_string($type));
 
-        $config = SimpleSAML_Configuration::getConfig('authsources.php');
+        $config = \SimpleSAML\Configuration::getConfig('authsources.php');
 
-        $ret = array();
+        $ret = [];
 
         $sources = $config->getOptions();
         foreach ($sources as $id) {
@@ -115,7 +115,7 @@ abstract class SimpleSAML_Auth_Source
         assert(isset($state['ReturnCallback']));
 
         // the default implementation just copies over the previous authentication data
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $data = $session->getAuthState($this->authId);
         foreach ($data as $k => $v) {
             $state[$k] = $v;
@@ -137,7 +137,7 @@ abstract class SimpleSAML_Auth_Source
         assert(is_array($state));
         assert(array_key_exists('LoginCompletedHandler', $state));
 
-        SimpleSAML_Auth_State::deleteState($state);
+        State::deleteState($state);
 
         $func = $state['LoginCompletedHandler'];
         assert(is_callable($func));
@@ -160,42 +160,42 @@ abstract class SimpleSAML_Auth_Source
      * @param array $params Extra information about the login. Different authentication requestors may provide different
      * information. Optional, will default to an empty array.
      */
-    public function initLogin($return, $errorURL = null, array $params = array())
+    public function initLogin($return, $errorURL = null, array $params = [])
     {
         assert(is_string($return) || is_array($return));
         assert(is_string($errorURL) || $errorURL === null);
 
-        $state = array_merge($params, array(
-            'SimpleSAML_Auth_Default.id' => $this->authId, // TODO: remove in 2.0
-            'SimpleSAML_Auth_Source.id' => $this->authId,
-            'SimpleSAML_Auth_Default.Return' => $return, // TODO: remove in 2.0
-            'SimpleSAML_Auth_Source.Return' => $return,
-            'SimpleSAML_Auth_Default.ErrorURL' => $errorURL, // TODO: remove in 2.0
-            'SimpleSAML_Auth_Source.ErrorURL' => $errorURL,
-            'LoginCompletedHandler' => array(get_class(), 'loginCompleted'),
-            'LogoutCallback' => array(get_class(), 'logoutCallback'),
-            'LogoutCallbackState' => array(
-                'SimpleSAML_Auth_Default.logoutSource' => $this->authId, // TODO: remove in 2.0
-                'SimpleSAML_Auth_Source.logoutSource' => $this->authId,
-            ),
-        ));
+        $state = array_merge($params, [
+            '\SimpleSAML\Auth\DefaultAuth.id' => $this->authId, // TODO: remove in 2.0
+            '\SimpleSAML\Auth\Source.id' => $this->authId,
+            '\SimpleSAML\Auth\DefaultAuth.Return' => $return, // TODO: remove in 2.0
+            '\SimpleSAML\Auth\Source.Return' => $return,
+            '\SimpleSAML\Auth\DefaultAuth.ErrorURL' => $errorURL, // TODO: remove in 2.0
+            '\SimpleSAML\Auth\Source.ErrorURL' => $errorURL,
+            'LoginCompletedHandler' => [get_class(), 'loginCompleted'],
+            'LogoutCallback' => [get_class(), 'logoutCallback'],
+            'LogoutCallbackState' => [
+                '\SimpleSAML\Auth\DefaultAuth.logoutSource' => $this->authId, // TODO: remove in 2.0
+                '\SimpleSAML\Auth\Source.logoutSource' => $this->authId,
+            ],
+        ]);
 
         if (is_string($return)) {
-            $state['SimpleSAML_Auth_Default.ReturnURL'] = $return; // TODO: remove in 2.0
-            $state['SimpleSAML_Auth_Source.ReturnURL'] = $return;
+            $state['\SimpleSAML\Auth\DefaultAuth.ReturnURL'] = $return; // TODO: remove in 2.0
+            $state['\SimpleSAML\Auth\Source.ReturnURL'] = $return;
         }
 
         if ($errorURL !== null) {
-            $state[SimpleSAML_Auth_State::EXCEPTION_HANDLER_URL] = $errorURL;
+            $state[State::EXCEPTION_HANDLER_URL] = $errorURL;
         }
 
         try {
             $this->authenticate($state);
-        } catch (SimpleSAML_Error_Exception $e) {
-            SimpleSAML_Auth_State::throwException($state, $e);
-        } catch (Exception $e) {
-            $e = new SimpleSAML_Error_UnserializableException($e);
-            SimpleSAML_Auth_State::throwException($state, $e);
+        } catch (\SimpleSAML\Error\Exception $e) {
+            State::throwException($state, $e);
+        } catch (\Exception $e) {
+            $e = new \SimpleSAML\Error\UnserializableException($e);
+            State::throwException($state, $e);
         }
         self::loginCompleted($state);
     }
@@ -211,19 +211,20 @@ abstract class SimpleSAML_Auth_Source
     public static function loginCompleted($state)
     {
         assert(is_array($state));
-        assert(array_key_exists('SimpleSAML_Auth_Source.Return', $state));
-        assert(array_key_exists('SimpleSAML_Auth_Source.id', $state));
+        assert(array_key_exists('\SimpleSAML\Auth\Source.Return', $state));
+        assert(array_key_exists('\SimpleSAML\Auth\Source.id', $state));
         assert(array_key_exists('Attributes', $state));
         assert(!array_key_exists('LogoutState', $state) || is_array($state['LogoutState']));
 
-        $return = $state['SimpleSAML_Auth_Source.Return'];
+        $return = $state['\SimpleSAML\Auth\Source.Return'];
 
         // save session state
-        $session = SimpleSAML_Session::getSessionFromRequest();
-        $authId = $state['SimpleSAML_Auth_Source.id'];
-        $session->doLogin($authId, SimpleSAML_Auth_State::getPersistentAuthData($state));
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $authId = $state['\SimpleSAML\Auth\Source.id'];
+        $session->doLogin($authId, State::getPersistentAuthData($state));
 
-        if (is_string($return)) { // redirect...
+        if (is_string($return)) {
+            // redirect...
             \SimpleSAML\Utils\HTTP::redirectTrustedURL($return);
         } else {
             call_user_func($return, $state);
@@ -266,7 +267,7 @@ abstract class SimpleSAML_Auth_Source
         assert(is_array($state));
         assert(array_key_exists('LogoutCompletedHandler', $state));
 
-        SimpleSAML_Auth_State::deleteState($state);
+        State::deleteState($state);
 
         $func = $state['LogoutCompletedHandler'];
         assert(is_callable($func));
@@ -285,8 +286,8 @@ abstract class SimpleSAML_Auth_Source
      * @param string $authId The authentication source identifier.
      * @param array  $config The configuration.
      *
-     * @return SimpleSAML_Auth_Source The parsed authentication source.
-     * @throws Exception If the authentication source is invalid.
+     * @return Source The parsed authentication source.
+     * @throws \Exception If the authentication source is invalid.
      */
     private static function parseAuthSource($authId, $config)
     {
@@ -295,11 +296,30 @@ abstract class SimpleSAML_Auth_Source
 
         self::validateSource($config, $authId);
 
-        $className = SimpleSAML\Module::resolveClass($config[0], 'Auth_Source', 'SimpleSAML_Auth_Source');
+        $id = $config[0];
+        $info = ['AuthId' => $authId];
+        $authSource = null;
 
-        $info = array('AuthId' => $authId);
         unset($config[0]);
-        return new $className($info, $config);
+
+        try {
+            // Check whether or not there's a factory responsible for instantiating our Auth Source instance
+            $factoryClass = \SimpleSAML\Module::resolveClass(
+                $id,
+                'Auth_Source_Factory',
+                '\SimpleSAML\Auth\SourceFactory'
+            );
+
+            /** @var SourceFactory $factory */
+            $factory = new $factoryClass;
+            $authSource = $factory->create($info, $config);
+        } catch (\Exception $e) {
+            // If not, instantiate the Auth Source here
+            $className = \SimpleSAML\Module::resolveClass($id, 'Auth_Source', '\SimpleSAML\Auth\Source');
+            $authSource = new $className($info, $config);
+        }
+
+        return $authSource;
     }
 
 
@@ -317,9 +337,9 @@ abstract class SimpleSAML_Auth_Source
      * @param string      $authId The authentication source identifier.
      * @param string|NULL $type The type of authentication source. If NULL, any type will be accepted.
      *
-     * @return SimpleSAML_Auth_Source|NULL The AuthSource object, or NULL if no authentication
+     * @return Source|NULL The AuthSource object, or NULL if no authentication
      *     source with the given identifier is found.
-     * @throws SimpleSAML_Error_Exception If no such authentication source is found or it is invalid.
+     * @throws \SimpleSAML\Error\Exception If no such authentication source is found or it is invalid.
      */
     public static function getById($authId, $type = null)
     {
@@ -327,12 +347,12 @@ abstract class SimpleSAML_Auth_Source
         assert($type === null || is_string($type));
 
         // for now - load and parse config file
-        $config = SimpleSAML_Configuration::getConfig('authsources.php');
+        $config = \SimpleSAML\Configuration::getConfig('authsources.php');
 
         $authConfig = $config->getArray($authId, null);
         if ($authConfig === null) {
             if ($type !== null) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'No authentication source with id '.
                     var_export($authId, true).' found.'
                 );
@@ -347,7 +367,7 @@ abstract class SimpleSAML_Auth_Source
         }
 
         // the authentication source doesn't have the correct type
-        throw new SimpleSAML_Error_Exception(
+        throw new \SimpleSAML\Error\Exception(
             'Invalid type of authentication source '.
             var_export($authId, true).'. Was '.var_export(get_class($ret), true).
             ', should be '.var_export($type, true).'.'
@@ -363,13 +383,13 @@ abstract class SimpleSAML_Auth_Source
     public static function logoutCallback($state)
     {
         assert(is_array($state));
-        assert(array_key_exists('SimpleSAML_Auth_Source.logoutSource', $state));
+        assert(array_key_exists('\SimpleSAML\Auth\Source.logoutSource', $state));
 
-        $source = $state['SimpleSAML_Auth_Source.logoutSource'];
+        $source = $state['\SimpleSAML\Auth\Source.logoutSource'];
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         if (!$session->isValid($source)) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Received logout from an invalid authentication source '.
                 var_export($source, true)
             );
@@ -406,22 +426,22 @@ abstract class SimpleSAML_Auth_Source
         if (array_key_exists('LogoutCallbackState', $state)) {
             $callbackState = $state['LogoutCallbackState'];
         } else {
-            $callbackState = array();
+            $callbackState = [];
         }
 
         $id = strlen($this->authId).':'.$this->authId.$assoc;
 
-        $data = array(
+        $data = [
             'callback' => $callback,
             'state'    => $callbackState,
-        );
+        ];
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $session->setData(
-            'SimpleSAML_Auth_Source.LogoutCallbacks',
+            '\SimpleSAML\Auth\Source.LogoutCallbacks',
             $id,
             $data,
-            SimpleSAML_Session::DATA_TIMEOUT_SESSION_END
+            \SimpleSAML\Session::DATA_TIMEOUT_SESSION_END
         );
     }
 
@@ -442,9 +462,9 @@ abstract class SimpleSAML_Auth_Source
 
         $id = strlen($this->authId).':'.$this->authId.$assoc;
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
 
-        $data = $session->getData('SimpleSAML_Auth_Source.LogoutCallbacks', $id);
+        $data = $session->getData('\SimpleSAML\Auth\Source.LogoutCallbacks', $id);
         if ($data === null) {
             // FIXME: fix for IdP-first flow (issue 397) -> reevaluate logout callback infrastructure
             $session->doLogout($this->authId);
@@ -459,7 +479,7 @@ abstract class SimpleSAML_Auth_Source
         $callback = $data['callback'];
         $callbackState = $data['state'];
 
-        $session->deleteData('SimpleSAML_Auth_Source.LogoutCallbacks', $id);
+        $session->deleteData('\SimpleSAML\Auth\Source.LogoutCallbacks', $id);
         call_user_func($callback, $callbackState);
     }
 
@@ -471,7 +491,7 @@ abstract class SimpleSAML_Auth_Source
      */
     public static function getSources()
     {
-        $config = SimpleSAML_Configuration::getOptionalConfig('authsources.php');
+        $config = \SimpleSAML\Configuration::getOptionalConfig('authsources.php');
 
         return $config->getOptions();
     }
@@ -483,12 +503,12 @@ abstract class SimpleSAML_Auth_Source
      * @param array $source An array with the auth source configuration.
      * @param string $id The auth source identifier.
      *
-     * @throws Exception If the first element of $source is not an identifier for the auth source.
+     * @throws \Exception If the first element of $source is not an identifier for the auth source.
      */
     protected static function validateSource($source, $id)
     {
         if (!array_key_exists(0, $source) || !is_string($source[0])) {
-            throw new Exception(
+            throw new \Exception(
                 'Invalid authentication source \''.$id.
                 '\': First element must be a string which identifies the authentication source.'
             );
diff --git a/lib/SimpleSAML/Auth/SourceFactory.php b/lib/SimpleSAML/Auth/SourceFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f5fdfafbeccf28ad2c37c1e18cb30844fea8055
--- /dev/null
+++ b/lib/SimpleSAML/Auth/SourceFactory.php
@@ -0,0 +1,13 @@
+<?php
+
+namespace SimpleSAML\Auth;
+
+interface SourceFactory
+{
+    /**
+     * @param array $info
+     * @param array $config
+     * @return Source
+     */
+    public function create(array $info, array $config);
+}
diff --git a/lib/SimpleSAML/Auth/State.php b/lib/SimpleSAML/Auth/State.php
index 06bee7ae8e48058d0e5f9cffd29d0fc2f857373f..8ee2986db0612988e7fcd8fa3154c7be6935adc4 100644
--- a/lib/SimpleSAML/Auth/State.php
+++ b/lib/SimpleSAML/Auth/State.php
@@ -1,15 +1,16 @@
 <?php
 
+namespace SimpleSAML\Auth;
 
 /**
  * This is a helper class for saving and loading state information.
  *
  * The state must be an associative array. This class will add additional keys to this
- * array. These keys will always start with 'SimpleSAML_Auth_State.'.
+ * array. These keys will always start with '\SimpleSAML\Auth\State.'.
  *
  * It is also possible to add a restart URL to the state. If state information is lost, for
  * example because it timed out, or the user loaded a bookmarked page, the loadState function
- * will redirect to this URL. To use this, set $state[SimpleSAML_Auth_State::RESTART] to this
+ * will redirect to this URL. To use this, set $state[\SimpleSAML\Auth\State::RESTART] to this
  * URL.
  *
  * Both the saveState and the loadState function takes in a $stage parameter. This parameter is
@@ -28,63 +29,62 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Auth_State
-{
-
 
+class State
+{
     /**
      * The index in the state array which contains the identifier.
      */
-    const ID = 'SimpleSAML_Auth_State.id';
+    const ID = '\SimpleSAML\Auth\State.id';
 
 
     /**
      * The index in the cloned state array which contains the identifier of the
      * original state.
      */
-    const CLONE_ORIGINAL_ID = 'SimpleSAML_Auth_State.cloneOriginalId';
+    const CLONE_ORIGINAL_ID = '\SimpleSAML\Auth\State.cloneOriginalId';
 
 
     /**
      * The index in the state array which contains the current stage.
      */
-    const STAGE = 'SimpleSAML_Auth_State.stage';
+    const STAGE = '\SimpleSAML\Auth\State.stage';
 
 
     /**
      * The index in the state array which contains the restart URL.
      */
-    const RESTART = 'SimpleSAML_Auth_State.restartURL';
+    const RESTART = '\SimpleSAML\Auth\State.restartURL';
 
 
     /**
      * The index in the state array which contains the exception handler URL.
      */
-    const EXCEPTION_HANDLER_URL = 'SimpleSAML_Auth_State.exceptionURL';
+    const EXCEPTION_HANDLER_URL = '\SimpleSAML\Auth\State.exceptionURL';
 
 
     /**
      * The index in the state array which contains the exception handler function.
      */
-    const EXCEPTION_HANDLER_FUNC = 'SimpleSAML_Auth_State.exceptionFunc';
+    const EXCEPTION_HANDLER_FUNC = '\SimpleSAML\Auth\State.exceptionFunc';
 
 
     /**
      * The index in the state array which contains the exception data.
      */
-    const EXCEPTION_DATA = 'SimpleSAML_Auth_State.exceptionData';
+    const EXCEPTION_DATA = '\SimpleSAML\Auth\State.exceptionData';
 
 
     /**
      * The stage of a state with an exception.
      */
-    const EXCEPTION_STAGE = 'SimpleSAML_Auth_State.exceptionStage';
+    const EXCEPTION_STAGE = '\SimpleSAML\Auth\State.exceptionStage';
 
 
     /**
      * The URL parameter which contains the exception state id.
      */
-    const EXCEPTION_PARAM = 'SimpleSAML_Auth_State_exceptionId';
+    const EXCEPTION_PARAM = '\SimpleSAML\Auth\State.exceptionId';
 
 
     /**
@@ -103,7 +103,7 @@ class SimpleSAML_Auth_State
     public static function getPersistentAuthData(array $state)
     {
         // save persistent authentication data
-        $persistent = array();
+        $persistent = [];
 
         if (array_key_exists('PersistentAuthData', $state)) {
             foreach ($state['PersistentAuthData'] as $key) {
@@ -114,14 +114,14 @@ class SimpleSAML_Auth_State
         }
 
         // add those that should always be included
-        $mandatory = array(
+        $mandatory = [
             'Attributes',
             'Expire',
             'LogoutState',
             'AuthInstant',
             'RememberMe',
             'saml:sp:NameID'
-        );
+        ];
         foreach ($mandatory as $key) {
             if (isset($state[$key])) {
                 $persistent[$key] = $state[$key];
@@ -148,7 +148,7 @@ class SimpleSAML_Auth_State
         assert(is_bool($rawId));
 
         if (!array_key_exists(self::ID, $state)) {
-            $state[self::ID] = SimpleSAML\Utils\Random::generateID();
+            $state[self::ID] = \SimpleSAML\Utils\Random::generateID();
         }
 
         $id = $state[self::ID];
@@ -171,7 +171,7 @@ class SimpleSAML_Auth_State
     private static function getStateTimeout()
     {
         if (self::$stateTimeout === null) {
-            $globalConfig = SimpleSAML_Configuration::getInstance();
+            $globalConfig = \SimpleSAML\Configuration::getInstance();
             self::$stateTimeout = $globalConfig->getInteger('session.state.timeout', 60 * 60);
         }
 
@@ -205,10 +205,10 @@ class SimpleSAML_Auth_State
 
         // Save state
         $serializedState = serialize($state);
-        $session = SimpleSAML_Session::getSessionFromRequest();
-        $session->setData('SimpleSAML_Auth_State', $id, $serializedState, self::getStateTimeout());
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $session->setData('\SimpleSAML\Auth\State', $id, $serializedState, self::getStateTimeout());
 
-        SimpleSAML\Logger::debug('Saved state: '.var_export($return, true));
+        \SimpleSAML\Logger::debug('Saved state: '.var_export($return, true));
 
         return $return;
     }
@@ -231,9 +231,9 @@ class SimpleSAML_Auth_State
             $clonedState[self::CLONE_ORIGINAL_ID] = $state[self::ID];
             unset($clonedState[self::ID]);
 
-            SimpleSAML\Logger::debug('Cloned state: '.var_export($state[self::ID], true));
+            \SimpleSAML\Logger::debug('Cloned state: '.var_export($state[self::ID], true));
         } else {
-            SimpleSAML\Logger::debug('Cloned state with undefined id.');
+            \SimpleSAML\Logger::debug('Cloned state with undefined id.');
         }
 
         return $clonedState;
@@ -251,8 +251,8 @@ class SimpleSAML_Auth_State
      * @param string $stage The stage the state should have been saved in.
      * @param bool   $allowMissing Whether to allow the state to be missing.
      *
-     * @throws SimpleSAML_Error_NoState If we couldn't find the state and there's no URL defined to redirect to.
-     * @throws Exception If the stage of the state is invalid and there's no URL defined to redirect to.
+     * @throws \SimpleSAML\Error\NoState If we couldn't find the state and there's no URL defined to redirect to.
+     * @throws \Exception If the stage of the state is invalid and there's no URL defined to redirect to.
      *
      * @return array|NULL  State information, or null if the state is missing and $allowMissing is true.
      */
@@ -261,12 +261,12 @@ class SimpleSAML_Auth_State
         assert(is_string($id));
         assert(is_string($stage));
         assert(is_bool($allowMissing));
-        SimpleSAML\Logger::debug('Loading state: '.var_export($id, true));
+        \SimpleSAML\Logger::debug('Loading state: '.var_export($id, true));
 
         $sid = self::parseStateID($id);
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
-        $state = $session->getData('SimpleSAML_Auth_State', $sid['id']);
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $state = $session->getData('\SimpleSAML\Auth\State', $sid['id']);
 
         if ($state === null) {
             // Could not find saved data
@@ -275,7 +275,7 @@ class SimpleSAML_Auth_State
             }
 
             if ($sid['url'] === null) {
-                throw new SimpleSAML_Error_NoState();
+                throw new \SimpleSAML\Error\NoState();
             }
 
             \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
@@ -296,10 +296,10 @@ class SimpleSAML_Auth_State
             $msg = 'Wrong stage in state. Was \''.$state[self::STAGE].
                 '\', should be \''.$stage.'\'.';
 
-            SimpleSAML\Logger::warning($msg);
+            \SimpleSAML\Logger::warning($msg);
 
             if ($sid['url'] === null) {
-                throw new Exception($msg);
+                throw new \Exception($msg);
             }
 
             \SimpleSAML\Utils\HTTP::redirectUntrustedURL($sid['url']);
@@ -325,10 +325,10 @@ class SimpleSAML_Auth_State
             return;
         }
 
-        SimpleSAML\Logger::debug('Deleting state: '.var_export($state[self::ID], true));
+        \SimpleSAML\Logger::debug('Deleting state: '.var_export($state[self::ID], true));
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
-        $session->deleteData('SimpleSAML_Auth_State', $state[self::ID]);
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $session->deleteData('\SimpleSAML\Auth\State', $state[self::ID]);
     }
 
 
@@ -336,11 +336,11 @@ class SimpleSAML_Auth_State
      * Throw exception to the state exception handler.
      *
      * @param array                      $state The state array.
-     * @param SimpleSAML_Error_Exception $exception The exception.
+     * @param \SimpleSAML\Error\Exception $exception The exception.
      *
-     * @throws SimpleSAML_Error_Exception If there is no exception handler defined, it will just throw the $exception.
+     * @throws \SimpleSAML\Error\Exception If there is no exception handler defined, it will just throw the $exception.
      */
-    public static function throwException($state, SimpleSAML_Error_Exception $exception)
+    public static function throwException($state, \SimpleSAML\Error\Exception $exception)
     {
         assert(is_array($state));
 
@@ -352,7 +352,7 @@ class SimpleSAML_Auth_State
             // Redirect to the exception handler
             \SimpleSAML\Utils\HTTP::redirectTrustedURL(
                 $state[self::EXCEPTION_HANDLER_URL],
-                array(self::EXCEPTION_PARAM => $id)
+                [self::EXCEPTION_PARAM => $id]
             );
         } elseif (array_key_exists(self::EXCEPTION_HANDLER_FUNC, $state)) {
             // Call the exception handler
@@ -415,6 +415,6 @@ class SimpleSAML_Auth_State
         if (count($tmp) === 2) {
             $url = $tmp[1];
         }
-        return array('id' => $id, 'url' => $url);
+        return ['id' => $id, 'url' => $url];
     }
 }
diff --git a/lib/SimpleSAML/Auth/TimeLimitedToken.php b/lib/SimpleSAML/Auth/TimeLimitedToken.php
index 920dd2d1269d0ae452f5910fa358ba77e23c8ab7..eb6620d5ec039213f25ba8acee90b7a8b9350a48 100644
--- a/lib/SimpleSAML/Auth/TimeLimitedToken.php
+++ b/lib/SimpleSAML/Auth/TimeLimitedToken.php
@@ -5,9 +5,9 @@ namespace SimpleSAML\Auth;
 /**
  * A class that generates and verifies time-limited tokens.
  */
+
 class TimeLimitedToken
 {
-
     /**
      * @var string
      */
diff --git a/lib/SimpleSAML/AuthMemCookie.php b/lib/SimpleSAML/AuthMemCookie.php
index 33944677e48399d63c2bbc9863e5dd9e42fea77a..6b4455400c4a1709638da0f9747f1ed696c97362 100644
--- a/lib/SimpleSAML/AuthMemCookie.php
+++ b/lib/SimpleSAML/AuthMemCookie.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML;
 
 /**
  * This is a helper class for the Auth MemCookie module.
@@ -10,17 +11,17 @@
  *
  * @deprecated This class has been deprecated and will be removed in SSP 2.0. Use the memcookie module instead.
  */
-class SimpleSAML_AuthMemCookie
-{
 
+class AuthMemCookie
+{
     /**
-     * @var SimpleSAML_AuthMemCookie This is the singleton instance of this class.
+     * @var AuthMemCookie This is the singleton instance of this class.
      */
     private static $instance = null;
 
 
     /**
-     * @var SimpleSAML_Configuration The configuration for Auth MemCookie.
+     * @var Configuration The configuration for Auth MemCookie.
      */
     private $amcConfig;
 
@@ -28,12 +29,12 @@ class SimpleSAML_AuthMemCookie
     /**
      * This function is used to retrieve the singleton instance of this class.
      *
-     * @return SimpleSAML_AuthMemCookie The singleton instance of this class.
+     * @return AuthMemCookie The singleton instance of this class.
      */
     public static function getInstance()
     {
         if (self::$instance === null) {
-            self::$instance = new SimpleSAML_AuthMemCookie();
+            self::$instance = new AuthMemCookie();
         }
 
         return self::$instance;
@@ -46,7 +47,7 @@ class SimpleSAML_AuthMemCookie
     private function __construct()
     {
         // load AuthMemCookie configuration
-        $this->amcConfig = SimpleSAML_Configuration::getConfig('authmemcookie.php');
+        $this->amcConfig = Configuration::getConfig('authmemcookie.php');
     }
 
 
@@ -71,7 +72,7 @@ class SimpleSAML_AuthMemCookie
     {
         $cookieName = $this->amcConfig->getString('cookiename', 'AuthMemCookie');
         if (!is_string($cookieName) || strlen($cookieName) === 0) {
-            throw new Exception(
+            throw new \Exception(
                 "Configuration option 'cookiename' contains an invalid value. This option should be a string."
             );
         }
@@ -109,17 +110,19 @@ class SimpleSAML_AuthMemCookie
     /**
      * This function creates and initializes a Memcache object from our configuration.
      *
-     * @return Memcache A Memcache object initialized from our configuration.
-     * @throws Exception If the servers configuration is invalid.
+     * @return \Memcache A Memcache object initialized from our configuration.
+     * @throws \Exception If the servers configuration is invalid.
      */
     public function getMemcache()
     {
         $memcacheHost = $this->amcConfig->getString('memcache.host', '127.0.0.1');
         $memcachePort = $this->amcConfig->getInteger('memcache.port', 11211);
 
-        $class = class_exists('Memcache') ? 'Memcache' : (class_exists('Memcached') ? 'Memcached' : FALSE);
+        $class = class_exists('Memcache') ? '\Memcache' : (class_exists('Memcached') ? '\Memcached' : false);
         if (!$class) {
-            throw new Exception('Missing Memcached implementation. You must install either the Memcache or Memcached extension.');
+            throw new \Exception(
+                'Missing Memcached implementation. You must install either the Memcache or Memcached extension.'
+            );
         }
 
         // Create the Memcache(d) object.
diff --git a/lib/SimpleSAML/Bindings/Shib13/Artifact.php b/lib/SimpleSAML/Bindings/Shib13/Artifact.php
index 726461aaff844d3d79dd6eb55d0b47d63fd7d300..3ce30d977fbb3d902817729e0a071af86eb85864 100644
--- a/lib/SimpleSAML/Bindings/Shib13/Artifact.php
+++ b/lib/SimpleSAML/Bindings/Shib13/Artifact.php
@@ -9,6 +9,7 @@
 namespace SimpleSAML\Bindings\Shib13;
 
 use SAML2\DOMDocumentFactory;
+use SimpleSAML\Error;
 use SimpleSAML\Utils\Config;
 use SimpleSAML\Utils\HTTP;
 use SimpleSAML\Utils\Random;
@@ -18,7 +19,6 @@ use SimpleSAML\Utils\XML;
 
 class Artifact
 {
-
     /**
      * Parse the query string, and extract the SAMLart parameters.
      *
@@ -33,7 +33,7 @@ class Artifact
 
         // We need to process the query string manually, to capture all SAMLart parameters
 
-        $artifacts = array();
+        $artifacts = [];
 
         $elements = explode('&', $_SERVER['QUERY_STRING']);
         foreach ($elements as $element) {
@@ -58,20 +58,20 @@ class Artifact
      */
     private static function buildRequest(array $artifacts)
     {
-        $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">' .
-            '<SOAP-ENV:Body>' .
-            '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"' .
-            ' RequestID="' . Random::generateID() . '"' .
-            ' MajorVersion="1" MinorVersion="1"' .
-            ' IssueInstant="' . Time::generateTimestamp() . '"' .
+        $msg = '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'.
+            '<SOAP-ENV:Body>'.
+            '<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"'.
+            ' RequestID="'.Random::generateID().'"'.
+            ' MajorVersion="1" MinorVersion="1"'.
+            ' IssueInstant="'.Time::generateTimestamp().'"'.
             '>';
 
         foreach ($artifacts as $a) {
-            $msg .= '<samlp:AssertionArtifact>' . htmlspecialchars($a) . '</samlp:AssertionArtifact>';
+            $msg .= '<samlp:AssertionArtifact>'.htmlspecialchars($a).'</samlp:AssertionArtifact>';
         }
 
-        $msg .= '</samlp:Request>' .
-            '</SOAP-ENV:Body>' .
+        $msg .= '</samlp:Request>'.
+            '</SOAP-ENV:Body>'.
             '</SOAP-ENV:Envelope>';
 
         return $msg;
@@ -83,7 +83,7 @@ class Artifact
      *
      * @param string $soapResponse The SOAP response.
      * @return string The <saml1p:Response> element, as a string.
-     * @throws \SimpleSAML_Error_Exception
+     * @throws Error\Exception
      */
     private static function extractResponse($soapResponse)
     {
@@ -92,24 +92,24 @@ class Artifact
         try {
             $doc = DOMDocumentFactory::fromString($soapResponse);
         } catch (\Exception $e) {
-            throw new \SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.');
+            throw new Error\Exception('Error parsing SAML 1 artifact response.');
         }
 
         $soapEnvelope = $doc->firstChild;
         if (!XML::isDOMNodeOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) {
-            throw new \SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.');
+            throw new Error\Exception('Expected artifact response to contain a <soap:Envelope> element.');
         }
 
         $soapBody = XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/');
         if (count($soapBody) === 0) {
-            throw new \SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.');
+            throw new Error\Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.');
         }
         $soapBody = $soapBody[0];
 
 
         $responseElement = XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol');
         if (count($responseElement) === 0) {
-            throw new \SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.');
+            throw new Error\Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.');
         }
         $responseElement = $responseElement[0];
 
@@ -128,19 +128,22 @@ class Artifact
     /**
      * This function receives a SAML 1.1 artifact.
      *
-     * @param \SimpleSAML_Configuration $spMetadata The metadata of the SP.
-     * @param \SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
      * @return string The <saml1p:Response> element, as an XML string.
-     * @throws \SimpleSAML_Error_Exception
+     * @throws Error\Exception
      */
-    public static function receive(\SimpleSAML_Configuration $spMetadata, \SimpleSAML_Configuration $idpMetadata)
+    public static function receive(\SimpleSAML\Configuration $spMetadata, \SimpleSAML\Configuration $idpMetadata)
     {
         $artifacts = self::getArtifacts();
         $request = self::buildRequest($artifacts);
 
         XML::debugSAMLMessage($request, 'out');
 
-        $url = $idpMetadata->getDefaultEndpoint('ArtifactResolutionService', array('urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding'));
+        $url = $idpMetadata->getDefaultEndpoint(
+            'ArtifactResolutionService',
+            ['urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding']
+        );
         $url = $url['Location'];
 
         $peerPublicKeys = $idpMetadata->getPublicKeys('signing', true);
@@ -149,33 +152,33 @@ class Artifact
             if ($key['type'] !== 'X509Certificate') {
                 continue;
             }
-            $certData .= "-----BEGIN CERTIFICATE-----\n" .
-                chunk_split($key['X509Certificate'], 64) .
+            $certData .= "-----BEGIN CERTIFICATE-----\n".
+                chunk_split($key['X509Certificate'], 64).
                 "-----END CERTIFICATE-----\n";
         }
 
-        $file = System::getTempDir() . DIRECTORY_SEPARATOR . sha1($certData) . '.crt';
+        $file = System::getTempDir().DIRECTORY_SEPARATOR.sha1($certData).'.crt';
         if (!file_exists($file)) {
             System::writeFile($file, $certData);
         }
 
         $spKeyCertFile = Config::getCertPath($spMetadata->getString('privatekey'));
 
-        $opts = array(
-            'ssl' => array(
+        $opts = [
+            'ssl' => [
                 'verify_peer' => true,
                 'cafile' => $file,
                 'local_cert' => $spKeyCertFile,
                 'capture_peer_cert' => true,
                 'capture_peer_chain' => true,
-            ),
-            'http' => array(
+            ],
+            'http' => [
                 'method' => 'POST',
                 'content' => $request,
-                'header' => 'SOAPAction: http://www.oasis-open.org/committees/security' . "\r\n" .
+                'header' => 'SOAPAction: http://www.oasis-open.org/committees/security'."\r\n".
                     'Content-Type: text/xml',
-            ),
-        );
+            ],
+        ];
 
         // Fetch the artifact
         $response = HTTP::fetch($url, $opts);
diff --git a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
index 5359c8ff30aef0ffdc8747ca7c0eeda1f0385ed7..893682c1b8569bb0eb2e619f4f38a1b453e79c73 100644
--- a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
+++ b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php
@@ -19,14 +19,13 @@ use SimpleSAML\XML\Signer;
 
 class HTTPPost
 {
-
     /**
-     * @var \SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $configuration = null;
 
     /**
-     * @var \SimpleSAML_Metadata_MetaDataStorageHandler
+     * @var \SimpleSAML\Metadata\MetaDataStorageHandler
      */
     private $metadata = null;
 
@@ -34,12 +33,12 @@ class HTTPPost
     /**
      * Constructor for the \SimpleSAML\Bindings\Shib13\HTTPPost class.
      *
-     * @param \SimpleSAML_Configuration                   $configuration The configuration to use.
-     * @param \SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore A store where to find metadata.
+     * @param \SimpleSAML\Configuration                   $configuration The configuration to use.
+     * @param \SimpleSAML\Metadata\MetaDataStorageHandler $metadatastore A store where to find metadata.
      */
     public function __construct(
-        \SimpleSAML_Configuration $configuration,
-        \SimpleSAML_Metadata_MetaDataStorageHandler $metadatastore
+        \SimpleSAML\Configuration $configuration,
+        \SimpleSAML\Metadata\MetaDataStorageHandler $metadatastore
     ) {
         $this->configuration = $configuration;
         $this->metadata = $metadatastore;
@@ -50,15 +49,15 @@ class HTTPPost
      * Send an authenticationResponse using HTTP-POST.
      *
      * @param string                    $response The response which should be sent.
-     * @param \SimpleSAML_Configuration $idpmd The metadata of the IdP which is sending the response.
-     * @param \SimpleSAML_Configuration $spmd The metadata of the SP which is receiving the response.
+     * @param \SimpleSAML\Configuration $idpmd The metadata of the IdP which is sending the response.
+     * @param \SimpleSAML\Configuration $spmd The metadata of the SP which is receiving the response.
      * @param string|null               $relayState The relaystate for the SP.
      * @param string                    $shire The shire which should receive the response.
      */
     public function sendResponse(
         $response,
-        \SimpleSAML_Configuration $idpmd,
-        \SimpleSAML_Configuration $spmd,
+        \SimpleSAML\Configuration $idpmd,
+        \SimpleSAML\Configuration $spmd,
         $relayState,
         $shire
     ) {
@@ -89,11 +88,11 @@ class HTTPPost
             $signResponse = true;
         }
 
-        $signer = new Signer(array(
+        $signer = new Signer([
             'privatekey_array' => $privatekey,
             'publickey_array'  => $publickey,
             'id'               => ($signResponse ? 'ResponseID' : 'AssertionID'),
-        ));
+        ]);
 
         if ($idpmd->hasValue('certificatechain')) {
             $signer->addCertificate($idpmd->getString('certificatechain'));
@@ -114,10 +113,10 @@ class HTTPPost
 
         XML::debugSAMLMessage($response, 'out');
 
-        HTTP::submitPOSTData($shire, array(
+        HTTP::submitPOSTData($shire, [
             'TARGET'       => $relayState,
             'SAMLResponse' => base64_encode($response),
-        ));
+        ]);
     }
 
 
diff --git a/lib/SimpleSAML/Configuration.php b/lib/SimpleSAML/Configuration.php
index 71e618ae9492fb7335122bfceddae19716a62503..f9275d521f0704d3d2499c47b920976f9aac161d 100644
--- a/lib/SimpleSAML/Configuration.php
+++ b/lib/SimpleSAML/Configuration.php
@@ -1,5 +1,8 @@
 <?php
 
+namespace SimpleSAML;
+
+use SimpleSAML\Utils\System;
 
 /**
  * Configuration of SimpleSAMLphp
@@ -7,7 +10,7 @@
  * @author Andreas Aakre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
+class Configuration implements Utils\ClearableState
 {
     /**
      * A default value which means that the given option is required.
@@ -22,7 +25,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @var array
      */
-    private static $instance = array();
+    private static $instance = [];
 
 
     /**
@@ -33,7 +36,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @var array
      */
-    private static $configDirs = array();
+    private static $configDirs = [];
 
 
     /**
@@ -43,7 +46,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @var array
      */
-    private static $loadedConfigs = array();
+    private static $loadedConfigs = [];
 
 
     /**
@@ -99,10 +102,10 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @param string $filename The full path of the configuration file.
      * @param bool $required Whether the file is required.
      *
-     * @return SimpleSAML_Configuration The configuration file. An exception will be thrown if the
+     * @return \SimpleSAML\Configuration The configuration file. An exception will be thrown if the
      *                                   configuration file is missing.
      *
-     * @throws Exception If the configuration file is invalid or missing.
+     * @throws \Exception If the configuration file is invalid or missing.
      */
     private static function loadFromFile($filename, $required)
     {
@@ -118,12 +121,12 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
             // the file initializes a variable named '$config'
             ob_start();
-            if (interface_exists('Throwable')) {
+            if (interface_exists('Throwable', false)) {
                 try {
                     require($filename);
-                } catch (ParseError $e) {
-                    self::$loadedConfigs[$filename] = self::loadFromArray(array(), '[ARRAY]', 'simplesaml');
-                    throw new SimpleSAML\Error\ConfigurationError($e->getMessage(), $filename, array());
+                } catch (\ParseError $e) {
+                    self::$loadedConfigs[$filename] = self::loadFromArray([], '[ARRAY]', 'simplesaml');
+                    throw new Error\ConfigurationError($e->getMessage(), $filename, []);
                 }
             } else {
                 require($filename);
@@ -134,7 +137,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
             // check that $config exists
             if (!isset($config)) {
-                throw new \SimpleSAML\Error\ConfigurationError(
+                throw new Error\ConfigurationError(
                     '$config is not defined in the configuration file.',
                     $filename
                 );
@@ -142,7 +145,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
             // check that $config is initialized to an array
             if (!is_array($config)) {
-                throw new \SimpleSAML\Error\ConfigurationError(
+                throw new Error\ConfigurationError(
                     '$config is not an array.',
                     $filename
                 );
@@ -150,28 +153,28 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
             // check that $config is not empty
             if (empty($config)) {
-                throw new \SimpleSAML\Error\ConfigurationError(
+                throw new Error\ConfigurationError(
                     '$config is empty.',
                     $filename
                 );
             }
         } elseif ($required) {
             // file does not exist, but is required
-            throw new \SimpleSAML\Error\ConfigurationError('Missing configuration file', $filename);
+            throw new Error\ConfigurationError('Missing configuration file', $filename);
         } else {
             // file does not exist, but is optional, so return an empty configuration object without saving it
-            $cfg = new SimpleSAML_Configuration(array(), $filename);
+            $cfg = new Configuration([], $filename);
             $cfg->filename = $filename;
             return $cfg;
         }
 
-        $cfg = new SimpleSAML_Configuration($config, $filename);
+        $cfg = new Configuration($config, $filename);
         $cfg->filename = $filename;
 
         self::$loadedConfigs[$filename] = $cfg;
 
         if ($spurious_output) {
-            SimpleSAML\Logger::warning(
+            Logger::warning(
                 "The configuration file '$filename' generates output. Please review your configuration."
             );
         }
@@ -194,6 +197,38 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         self::$configDirs[$configSet] = $path;
     }
 
+    /**
+     * Store a pre-initialized configuration.
+     *
+     * Allows consumers to create configuration objects without having them
+     * loaded from a file.
+     *
+     * @param \SimpleSAML\Configuration $config  The configuration object to store
+     * @param string $filename  The name of the configuration file.
+     * @param string $configSet  The configuration set. Optional, defaults to 'simplesaml'.
+     */
+    public static function setPreLoadedConfig(
+        Configuration $config,
+        $filename = 'config.php',
+        $configSet = 'simplesaml'
+    ) {
+        assert(is_string($filename));
+        assert(is_string($configSet));
+
+        if (!array_key_exists($configSet, self::$configDirs)) {
+            if ($configSet !== 'simplesaml') {
+                throw new \Exception('Configuration set \''.$configSet.'\' not initialized.');
+            } else {
+                self::$configDirs['simplesaml'] = dirname(dirname(dirname(__FILE__))).'/config';
+            }
+        }
+
+        $dir = self::$configDirs[$configSet];
+        $filePath = $dir.'/'.$filename;
+
+        self::$loadedConfigs[$filePath] = $config;
+    }
+
 
     /**
      * Load a configuration file from a configuration set.
@@ -201,8 +236,8 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @param string $filename The name of the configuration file.
      * @param string $configSet The configuration set. Optional, defaults to 'simplesaml'.
      *
-     * @return SimpleSAML_Configuration The SimpleSAML_Configuration object.
-     * @throws Exception If the configuration set is not initialized.
+     * @return \SimpleSAML\Configuration The Configuration object.
+     * @throws \Exception If the configuration set is not initialized.
      */
     public static function getConfig($filename = 'config.php', $configSet = 'simplesaml')
     {
@@ -211,9 +246,9 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         if (!array_key_exists($configSet, self::$configDirs)) {
             if ($configSet !== 'simplesaml') {
-                throw new Exception('Configuration set \''.$configSet.'\' not initialized.');
+                throw new \Exception('Configuration set \''.$configSet.'\' not initialized.');
             } else {
-                self::$configDirs['simplesaml'] = SimpleSAML\Utils\Config::getConfigDir();
+                self::$configDirs['simplesaml'] = Utils\Config::getConfigDir();
             }
         }
 
@@ -231,8 +266,8 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @param string $filename The name of the configuration file.
      * @param string $configSet The configuration set. Optional, defaults to 'simplesaml'.
      *
-     * @return SimpleSAML_Configuration A configuration object.
-     * @throws Exception If the configuration set is not initialized.
+     * @return \SimpleSAML\Configuration A configuration object.
+     * @throws \Exception If the configuration set is not initialized.
      */
     public static function getOptionalConfig($filename = 'config.php', $configSet = 'simplesaml')
     {
@@ -241,9 +276,9 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         if (!array_key_exists($configSet, self::$configDirs)) {
             if ($configSet !== 'simplesaml') {
-                throw new Exception('Configuration set \''.$configSet.'\' not initialized.');
+                throw new \Exception('Configuration set \''.$configSet.'\' not initialized.');
             } else {
-                self::$configDirs['simplesaml'] = SimpleSAML\Utils\Config::getConfigDir();
+                self::$configDirs['simplesaml'] = Utils\Config::getConfigDir();
             }
         }
 
@@ -262,14 +297,14 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * instance with that name will be kept for it to be retrieved later with getInstance($instance). If null, the
      * configuration will not be kept for later use. Defaults to null.
      *
-     * @return SimpleSAML_Configuration The configuration object.
+     * @return \SimpleSAML\Configuration The configuration object.
      */
     public static function loadFromArray($config, $location = '[ARRAY]', $instance = null)
     {
         assert(is_array($config));
         assert(is_string($location));
 
-        $c = new SimpleSAML_Configuration($config, $location);
+        $c = new Configuration($config, $location);
         if ($instance !== null) {
             self::$instance[$instance] = $c;
         }
@@ -288,9 +323,9 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @param string $instancename The instance name of the configuration file. Deprecated.
      *
-     * @return SimpleSAML_Configuration The configuration object.
+     * @return \SimpleSAML\Configuration The configuration object.
      *
-     * @throws Exception If the configuration with $instancename name is not initialized.
+     * @throws \Exception If the configuration with $instancename name is not initialized.
      */
     public static function getInstance($instancename = 'simplesaml')
     {
@@ -304,12 +339,12 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         if ($instancename === 'simplesaml') {
             try {
                 return self::getConfig();
-            } catch (SimpleSAML\Error\ConfigurationError $e) {
-                throw \SimpleSAML\Error\CriticalConfigurationError::fromException($e);
+            } catch (Error\ConfigurationError $e) {
+                throw Error\CriticalConfigurationError::fromException($e);
             }
         }
 
-        throw new \SimpleSAML\Error\CriticalConfigurationError(
+        throw new Error\CriticalConfigurationError(
             'Configuration with name '.$instancename.' is not initialized.'
         );
     }
@@ -393,19 +428,19 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @param string $name Name of the configuration option.
      * @param mixed  $default Default value of the configuration option. This parameter will default to null if not
-     *                        specified. This can be set to SimpleSAML_Configuration::REQUIRED_OPTION, which will
+     *                        specified. This can be set to \SimpleSAML\Configuration::REQUIRED_OPTION, which will
      *                        cause an exception to be thrown if the option isn't found.
      *
      * @return mixed The configuration option with name $name, or $default if the option was not found.
      *
-     * @throws Exception If the required option cannot be retrieved.
+     * @throws \Exception If the required option cannot be retrieved.
      */
     public function getValue($name, $default = null)
     {
         // return the default value if the option is unset
         if (!array_key_exists($name, $this->configuration)) {
             if ($default === self::REQUIRED_OPTION) {
-                throw new Exception(
+                throw new \Exception(
                     $this->location.': Could not retrieve the required option '.
                     var_export($name, true)
                 );
@@ -457,7 +492,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return string The absolute path relative to the root of the website.
      *
-     * @throws SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
+     * @throws \SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
      *
      * @deprecated This method will be removed in SimpleSAMLphp 2.0. Please use getBasePath() instead.
      */
@@ -465,13 +500,13 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
     {
         if (!$this->deprecated_base_url_used) {
             $this->deprecated_base_url_used = true;
-            SimpleSAML\Logger::warning(
-                "SimpleSAML_Configuration::getBaseURL() is deprecated, please use getBasePath() instead."
+            Logger::warning(
+                "\SimpleSAML\Configuration::getBaseURL() is deprecated, please use getBasePath() instead."
             );
         }
         if (preg_match('/^\*(.*)$/D', $this->getString('baseurlpath', 'simplesaml/'), $matches)) {
             // deprecated behaviour, will be removed in the future
-            return \SimpleSAML\Utils\HTTP::getFirstPathElement(false).$matches[1];
+            return Utils\HTTP::getFirstPathElement(false).$matches[1];
         }
         return ltrim($this->getBasePath(), '/');
     }
@@ -484,7 +519,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return string The absolute path where SimpleSAMLphp can be reached in the web server.
      *
-     * @throws SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
+     * @throws \SimpleSAML\Error\CriticalConfigurationError If the format of 'baseurlpath' is incorrect.
      */
     public function getBasePath()
     {
@@ -509,8 +544,8 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
              * with the configuration. Use a guessed base path instead of the one provided.
              */
             $c = $this->toArray();
-            $c['baseurlpath'] = SimpleSAML\Utils\HTTP::guessBasePath();
-            throw new SimpleSAML\Error\CriticalConfigurationError(
+            $c['baseurlpath'] = Utils\HTTP::guessBasePath();
+            throw new Error\CriticalConfigurationError(
                 'Incorrect format for option \'baseurlpath\'. Value is: "'.
                 $this->getString('baseurlpath', 'simplesaml/').'". Valid format is in the form'.
                 ' [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/].',
@@ -539,19 +574,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         assert(is_string($path));
 
-        /* Prepend path with basedir if it doesn't start with a slash or a Windows drive letter (e.g. "C:\"). We assume
-         * getBaseDir ends with a slash.
-         */
-        if ($path[0] !== '/' &&
-            !(preg_match('@^[a-z]:[\\\\/]@i', $path, $matches) && is_dir($matches[0]))
-        ) {
-            $path = $this->getBaseDir().$path;
-        }
-
-        // remove trailing slashes
-        $path = rtrim($path, '/');
-
-        return $path;
+        return System::resolvePath($path, $this->getBaseDir());
     }
 
 
@@ -641,7 +664,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @return boolean|mixed The option with the given name, or $default if the option isn't found and $default is
      *     specified.
      *
-     * @throws Exception If the option is not boolean.
+     * @throws \Exception If the option is not boolean.
      */
     public function getBoolean($name, $default = self::REQUIRED_OPTION)
     {
@@ -655,7 +678,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_bool($ret)) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': The option '.var_export($name, true).
                 ' is not a valid boolean value.'
             );
@@ -679,7 +702,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @return string|mixed The option with the given name, or $default if the option isn't found and $default is
      *     specified.
      *
-     * @throws Exception If the option is not a string.
+     * @throws \Exception If the option is not a string.
      */
     public function getString($name, $default = self::REQUIRED_OPTION)
     {
@@ -693,7 +716,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_string($ret)) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': The option '.var_export($name, true).
                 ' is not a valid string value.'
             );
@@ -717,7 +740,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @return int|mixed The option with the given name, or $default if the option isn't found and $default is
      * specified.
      *
-     * @throws Exception If the option is not an integer.
+     * @throws \Exception If the option is not an integer.
      */
     public function getInteger($name, $default = self::REQUIRED_OPTION)
     {
@@ -731,7 +754,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_int($ret)) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': The option '.var_export($name, true).
                 ' is not a valid integer value.'
             );
@@ -759,7 +782,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @return int|mixed The option with the given name, or $default if the option isn't found and $default is
      *     specified.
      *
-     * @throws Exception If the option is not in the range specified.
+     * @throws \Exception If the option is not in the range specified.
      */
     public function getIntegerRange($name, $minimum, $maximum, $default = self::REQUIRED_OPTION)
     {
@@ -775,7 +798,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if ($ret < $minimum || $ret > $maximum) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': Value of option '.var_export($name, true).
                 ' is out of range. Value is '.$ret.', allowed range is ['
                 .$minimum.' - '.$maximum.']'
@@ -805,7 +828,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return mixed The option with the given name, or $default if the option isn't found and $default is given.
      *
-     * @throws Exception If the option does not have any of the allowed values.
+     * @throws \Exception If the option does not have any of the allowed values.
      */
     public function getValueValidate($name, $allowedValues, $default = self::REQUIRED_OPTION)
     {
@@ -819,13 +842,13 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!in_array($ret, $allowedValues, true)) {
-            $strValues = array();
+            $strValues = [];
             foreach ($allowedValues as $av) {
                 $strValues[] = var_export($av, true);
             }
             $strValues = implode(', ', $strValues);
 
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': Invalid value given for the option '.
                 var_export($name, true).'. It should have one of the following values: '.
                 $strValues.'; but it had the following value: '.var_export($ret, true)
@@ -850,7 +873,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      * @return array|mixed The option with the given name, or $default if the option isn't found and $default is
      * specified.
      *
-     * @throws Exception If the option is not an array.
+     * @throws \Exception If the option is not an array.
      */
     public function getArray($name, $default = self::REQUIRED_OPTION)
     {
@@ -864,7 +887,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_array($ret)) {
-            throw new Exception($this->location.': The option '.var_export($name, true).' is not an array.');
+            throw new \Exception($this->location.': The option '.var_export($name, true).' is not an array.');
         }
 
         return $ret;
@@ -895,7 +918,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_array($ret)) {
-            $ret = array($ret);
+            $ret = [$ret];
         }
 
         return $ret;
@@ -914,7 +937,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array The option with the given name, or $default if the option isn't found and $default is specified.
      *
-     * @throws Exception If the option is not a string or an array of strings.
+     * @throws \Exception If the option is not a string or an array of strings.
      */
     public function getArrayizeString($name, $default = self::REQUIRED_OPTION)
     {
@@ -929,7 +952,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         foreach ($ret as $value) {
             if (!is_string($value)) {
-                throw new Exception(
+                throw new \Exception(
                     $this->location.': The option '.var_export($name, true).
                     ' must be a string or an array of strings.'
                 );
@@ -941,9 +964,9 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
 
     /**
-     * Retrieve an array as a SimpleSAML_Configuration object.
+     * Retrieve an array as a \SimpleSAML\Configuration object.
      *
-     * This function will load the value of an option into a SimpleSAML_Configuration object. The option must contain
+     * This function will load the value of an option into a \SimpleSAML\Configuration object. The option must contain
      * an array.
      *
      * An exception will be thrown if this option isn't an array, or if this option isn't found, and no default value
@@ -956,7 +979,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return mixed The option with the given name, or $default if the option isn't found and $default is specified.
      *
-     * @throws Exception If the option is not an array.
+     * @throws \Exception If the option is not an array.
      */
     public function getConfigItem($name, $default = self::REQUIRED_OPTION)
     {
@@ -970,7 +993,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_array($ret)) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': The option '.var_export($name, true).
                 ' is not an array.'
             );
@@ -981,11 +1004,11 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
 
     /**
-     * Retrieve an array of arrays as an array of SimpleSAML_Configuration objects.
+     * Retrieve an array of arrays as an array of \SimpleSAML\Configuration objects.
      *
      * This function will retrieve an option containing an array of arrays, and create an array of
-     * SimpleSAML_Configuration objects from that array. The indexes in the new array will be the same as the original
-     * indexes, but the values will be SimpleSAML_Configuration objects.
+     * \SimpleSAML\Configuration objects from that array. The indexes in the new array will be the same as the original
+     * indexes, but the values will be \SimpleSAML\Configuration objects.
      *
      * An exception will be thrown if this option isn't an array of arrays, or if this option isn't found, and no
      * default value is given.
@@ -997,7 +1020,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return mixed The option with the given name, or $default if the option isn't found and $default is specified.
      *
-     * @throws Exception If the value of this element is not an array.
+     * @throws \Exception If the value of this element is not an array.
      */
     public function getConfigList($name, $default = self::REQUIRED_OPTION)
     {
@@ -1011,18 +1034,18 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         }
 
         if (!is_array($ret)) {
-            throw new Exception(
+            throw new \Exception(
                 $this->location.': The option '.var_export($name, true).
                 ' is not an array.'
             );
         }
 
-        $out = array();
+        $out = [];
         foreach ($ret as $index => $config) {
             $newLoc = $this->location.'['.var_export($name, true).']['.
                 var_export($index, true).']';
             if (!is_array($config)) {
-                throw new Exception($newLoc.': The value of this element was expected to be an array.');
+                throw new \Exception($newLoc.': The value of this element was expected to be an array.');
             }
             $out[$index] = self::loadFromArray($config, $newLoc);
         }
@@ -1066,7 +1089,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return string The default binding.
      *
-     * @throws Exception If the default binding is missing for this endpoint type.
+     * @throws \Exception If the default binding is missing for this endpoint type.
      */
     private function getDefaultBinding($endpointType)
     {
@@ -1087,7 +1110,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
             case 'shib13-sp-remote:AssertionConsumerService':
                 return 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post';
             default:
-                throw new Exception('Missing default binding for '.$endpointType.' in '.$set);
+                throw new \Exception('Missing default binding for '.$endpointType.' in '.$set);
         }
     }
 
@@ -1099,7 +1122,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array Array of endpoints of the given type.
      *
-     * @throws Exception If any element of the configuration options for this endpoint type is incorrect.
+     * @throws \Exception If any element of the configuration options for this endpoint type is incorrect.
      */
     public function getEndpoints($endpointType)
     {
@@ -1109,16 +1132,16 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         if (!array_key_exists($endpointType, $this->configuration)) {
             // no endpoints of the given type
-            return array();
+            return [];
         }
 
 
         $eps = $this->configuration[$endpointType];
         if (is_string($eps)) {
             // for backwards-compatibility
-            $eps = array($eps);
+            $eps = [$eps];
         } elseif (!is_array($eps)) {
-            throw new Exception($loc.': Expected array or string.');
+            throw new \Exception($loc.': Expected array or string.');
         }
 
 
@@ -1127,41 +1150,41 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
             if (is_string($ep)) {
                 // for backwards-compatibility
-                $ep = array(
+                $ep = [
                     'Location' => $ep,
                     'Binding'  => $this->getDefaultBinding($endpointType),
-                );
+                ];
                 $responseLocation = $this->getString($endpointType.'Response', null);
                 if ($responseLocation !== null) {
                     $ep['ResponseLocation'] = $responseLocation;
                 }
             } elseif (!is_array($ep)) {
-                throw new Exception($iloc.': Expected a string or an array.');
+                throw new \Exception($iloc.': Expected a string or an array.');
             }
 
             if (!array_key_exists('Location', $ep)) {
-                throw new Exception($iloc.': Missing Location.');
+                throw new \Exception($iloc.': Missing Location.');
             }
             if (!is_string($ep['Location'])) {
-                throw new Exception($iloc.': Location must be a string.');
+                throw new \Exception($iloc.': Location must be a string.');
             }
 
             if (!array_key_exists('Binding', $ep)) {
-                throw new Exception($iloc.': Missing Binding.');
+                throw new \Exception($iloc.': Missing Binding.');
             }
             if (!is_string($ep['Binding'])) {
-                throw new Exception($iloc.': Binding must be a string.');
+                throw new \Exception($iloc.': Binding must be a string.');
             }
 
             if (array_key_exists('ResponseLocation', $ep)) {
                 if (!is_string($ep['ResponseLocation'])) {
-                    throw new Exception($iloc.': ResponseLocation must be a string.');
+                    throw new \Exception($iloc.': ResponseLocation must be a string.');
                 }
             }
 
             if (array_key_exists('index', $ep)) {
                 if (!is_int($ep['index'])) {
-                    throw new Exception($iloc.': index must be an integer.');
+                    throw new \Exception($iloc.': index must be an integer.');
                 }
             }
         }
@@ -1180,7 +1203,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array|null The default endpoint, or null if no acceptable endpoints are used.
      *
-     * @throws Exception If no supported endpoint is found.
+     * @throws \Exception If no supported endpoint is found.
      */
     public function getEndpointPrioritizedByBinding($endpointType, array $bindings, $default = self::REQUIRED_OPTION)
     {
@@ -1198,7 +1221,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         if ($default === self::REQUIRED_OPTION) {
             $loc = $this->location.'['.var_export($endpointType, true).']:';
-            throw new Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
+            throw new \Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
         }
 
         return $default;
@@ -1215,7 +1238,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array|null The default endpoint, or null if no acceptable endpoints are used.
      *
-     * @throws Exception If no supported endpoint is found.
+     * @throws \Exception If no supported endpoint is found.
      */
     public function getDefaultEndpoint($endpointType, array $bindings = null, $default = self::REQUIRED_OPTION)
     {
@@ -1223,14 +1246,14 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
 
         $endpoints = $this->getEndpoints($endpointType);
 
-        $defaultEndpoint = \SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($endpoints, $bindings);
+        $defaultEndpoint = Utils\Config\Metadata::getDefaultEndpoint($endpoints, $bindings);
         if ($defaultEndpoint !== null) {
             return $defaultEndpoint;
         }
 
         if ($default === self::REQUIRED_OPTION) {
             $loc = $this->location.'['.var_export($endpointType, true).']:';
-            throw new Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
+            throw new \Exception($loc.'Could not find a supported '.$endpointType.' endpoint.');
         }
 
         return $default;
@@ -1248,7 +1271,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array Associative array with language => string pairs.
      *
-     * @throws Exception If the translation is not an array or a string, or its index or value are not strings.
+     * @throws \Exception If the translation is not an array or a string, or its index or value are not strings.
      */
     public function getLocalizedString($name, $default = self::REQUIRED_OPTION)
     {
@@ -1263,19 +1286,19 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         $loc = $this->location.'['.var_export($name, true).']';
 
         if (is_string($ret)) {
-            $ret = array('en' => $ret,);
+            $ret = ['en' => $ret];
         }
 
         if (!is_array($ret)) {
-            throw new Exception($loc.': Must be an array or a string.');
+            throw new \Exception($loc.': Must be an array or a string.');
         }
 
         foreach ($ret as $k => $v) {
             if (!is_string($k)) {
-                throw new Exception($loc.': Invalid language code: '.var_export($k, true));
+                throw new \Exception($loc.': Invalid language code: '.var_export($k, true));
             }
             if (!is_string($v)) {
-                throw new Exception($loc.'['.var_export($v, true).']: Must be a string.');
+                throw new \Exception($loc.'['.var_export($v, true).']: Must be a string.');
             }
         }
 
@@ -1294,8 +1317,8 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      *
      * @return array Public key data, or empty array if no public key or was found.
      *
-     * @throws Exception If the certificate or public key cannot be loaded from a file.
-     * @throws SimpleSAML_Error_Exception If the file does not contain a valid PEM-encoded certificate, or there is no
+     * @throws \Exception If the certificate or public key cannot be loaded from a file.
+     * @throws \SimpleSAML\Error\Exception If the file does not contain a valid PEM-encoded certificate, or there is no
      * certificate in the metadata.
      */
     public function getPublicKeys($use = null, $required = false, $prefix = '')
@@ -1304,7 +1327,7 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         assert(is_string($prefix));
 
         if ($this->hasValue($prefix.'keys')) {
-            $ret = array();
+            $ret = [];
             foreach ($this->getArray($prefix.'keys') as $key) {
                 if ($use !== null && isset($key[$use]) && !$key[$use]) {
                     continue;
@@ -1319,44 +1342,44 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
         } elseif ($this->hasValue($prefix.'certData')) {
             $certData = $this->getString($prefix.'certData');
             $certData = preg_replace('/\s+/', '', $certData);
-            return array(
-                array(
+            return [
+                [
                     'encryption'      => true,
                     'signing'         => true,
                     'type'            => 'X509Certificate',
                     'X509Certificate' => $certData,
-                ),
-            );
+                ],
+            ];
         } elseif ($this->hasValue($prefix.'certificate')) {
             $file = $this->getString($prefix.'certificate');
-            $file = \SimpleSAML\Utils\Config::getCertPath($file);
+            $file = Utils\Config::getCertPath($file);
             $data = @file_get_contents($file);
 
             if ($data === false) {
-                throw new Exception($this->location.': Unable to load certificate/public key from file "'.$file.'".');
+                throw new \Exception($this->location.': Unable to load certificate/public key from file "'.$file.'".');
             }
 
             // extract certificate data (if this is a certificate)
             $pattern = '/^-----BEGIN CERTIFICATE-----([^-]*)^-----END CERTIFICATE-----/m';
             if (!preg_match($pattern, $data, $matches)) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     $this->location.': Could not find PEM encoded certificate in "'.$file.'".'
                 );
             }
             $certData = preg_replace('/\s+/', '', $matches[1]);
 
-            return array(
-                array(
+            return [
+                [
                     'encryption'      => true,
                     'signing'         => true,
                     'type'            => 'X509Certificate',
                     'X509Certificate' => $certData,
-                ),
-            );
+                ],
+            ];
         } elseif ($required === true) {
-            throw new SimpleSAML_Error_Exception($this->location.': Missing certificate in metadata.');
+            throw new \SimpleSAML\Error\Exception($this->location.': Missing certificate in metadata.');
         } else {
-            return array();
+            return [];
         }
     }
 
@@ -1367,8 +1390,8 @@ class SimpleSAML_Configuration implements \SimpleSAML\Utils\ClearableState
      */
     public static function clearInternalState()
     {
-        self::$configDirs = array();
-        self::$instance = array();
-        self::$loadedConfigs = array();
+        self::$configDirs = [];
+        self::$instance = [];
+        self::$loadedConfigs = [];
     }
 }
diff --git a/lib/SimpleSAML/Database.php b/lib/SimpleSAML/Database.php
index 85e19134ebbdc505adecf1f84c990fe5a2a213a3..94c9b788f14ec3e53f0162cf8f5c0e210cfb3929 100644
--- a/lib/SimpleSAML/Database.php
+++ b/lib/SimpleSAML/Database.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace SimpleSAML;
 
 /**
@@ -18,11 +19,10 @@ namespace SimpleSAML;
 
 class Database
 {
-
     /**
      * This variable holds the instance of the session - Singleton approach.
      */
-    private static $instance = array();
+    private static $instance = [];
 
     /**
      * PDO Object for the Master database server
@@ -32,7 +32,7 @@ class Database
     /**
      * Array of PDO Objects for configured database slaves
      */
-    private $dbSlaves = array();
+    private $dbSlaves = [];
 
     /**
      * Prefix to apply to the tables
@@ -48,13 +48,13 @@ class Database
     /**
      * Retrieves the current database instance. Will create a new one if there isn't an existing connection.
      *
-     * @param \SimpleSAML_Configuration $altConfig Optional: Instance of a SimpleSAML_Configuration class
+     * @param \SimpleSAML\Configuration $altConfig Optional: Instance of a \SimpleSAML\Configuration class
      *
      * @return \SimpleSAML\Database The shared database connection.
      */
     public static function getInstance($altConfig = null)
     {
-        $config = ($altConfig) ? $altConfig : \SimpleSAML_Configuration::getInstance();
+        $config = ($altConfig) ? $altConfig : Configuration::getInstance();
         $instanceId = self::generateInstanceId($config);
 
         // check if we already have initialized the session
@@ -71,13 +71,13 @@ class Database
     /**
      * Private constructor that restricts instantiation to getInstance().
      *
-     * @param \SimpleSAML_Configuration $config Instance of the SimpleSAML_Configuration class
+     * @param \SimpleSAML\Configuration $config Instance of the \SimpleSAML\Configuration class
      */
     private function __construct($config)
     {
-        $driverOptions = $config->getArray('database.driver_options', array());
+        $driverOptions = $config->getArray('database.driver_options', []);
         if ($config->getBoolean('database.persistent', true)) {
-            $driverOptions = array(\PDO::ATTR_PERSISTENT => true);
+            $driverOptions = [\PDO::ATTR_PERSISTENT => true];
         }
 
         // connect to the master
@@ -89,19 +89,17 @@ class Database
         );
 
         // connect to any configured slaves
-        $slaves = $config->getArray('database.slaves', array());
-        if (count($slaves >= 1)) {
-            foreach ($slaves as $slave) {
-                array_push(
-                    $this->dbSlaves,
-                    $this->connect(
-                        $slave['dsn'],
-                        $slave['username'],
-                        $slave['password'],
-                        $driverOptions
-                    )
-                );
-            }
+        $slaves = $config->getArray('database.slaves', []);
+        foreach ($slaves as $slave) {
+            array_push(
+                $this->dbSlaves,
+                $this->connect(
+                    $slave['dsn'],
+                    $slave['username'],
+                    $slave['password'],
+                    $driverOptions
+                )
+            );
         }
 
         $this->tablePrefix = $config->getString('database.prefix', '');
@@ -111,22 +109,22 @@ class Database
     /**
      * Generate an Instance ID based on the database configuration.
      *
-     * @param \SimpleSAML_Configuration $config Configuration class
+     * @param \SimpleSAML\Configuration $config Configuration class
      *
      * @return string $instanceId
      */
     private static function generateInstanceId($config)
     {
-        $assembledConfig = array(
-            'master' => array(
+        $assembledConfig = [
+            'master' => [
                 'database.dsn'        => $config->getString('database.dsn'),
                 'database.username'   => $config->getString('database.username', null),
                 'database.password'   => $config->getString('database.password', null),
                 'database.prefix'     => $config->getString('database.prefix', ''),
                 'database.persistent' => $config->getBoolean('database.persistent', false),
-            ),
-            'slaves' => $config->getArray('database.slaves', array()),
-        );
+            ],
+            'slaves' => $config->getArray('database.slaves', []),
+        ];
 
         return sha1(serialize($assembledConfig));
     }
@@ -194,7 +192,7 @@ class Database
      * @param array  $params Parameters
      *
      * @throws \Exception If an error happens while trying to execute the query.
-     * @return \PDOStatement object
+     * @return bool|\PDOStatement object
      */
     private function query($db, $stmt, $params)
     {
@@ -254,7 +252,7 @@ class Database
      *
      * @return int The number of rows affected by the query.
      */
-    public function write($stmt, $params = array())
+    public function write($stmt, $params = [])
     {
         $db = $this->dbMaster;
 
@@ -273,9 +271,9 @@ class Database
      * @param string $stmt Prepared SQL statement
      * @param array  $params Parameters
      *
-     * @return \PDOStatement object
+     * @return \PDOStatement|bool object
      */
-    public function read($stmt, $params = array())
+    public function read($stmt, $params = [])
     {
         $db = $this->getSlave();
 
diff --git a/lib/SimpleSAML/Error/Assertion.php b/lib/SimpleSAML/Error/Assertion.php
index 3497d32b2f4adce9331e1c71f4971e7760abee79..c16f61164ceb5a1afb84f91bd9a7762b15e6449c 100644
--- a/lib/SimpleSAML/Error/Assertion.php
+++ b/lib/SimpleSAML/Error/Assertion.php
@@ -1,81 +1,86 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Class for creating exceptions from assertion failures.
  *
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_Assertion extends SimpleSAML_Error_Exception {
-
-
-	/**
-	 * The assertion which failed, or NULL if only an expression was passed to the
-	 * assert-function.
-	 */
-	private $assertion;
-
-
-	/**
-	 * Constructor for the assertion exception.
-	 *
-	 * Should only be called from the onAssertion handler.
-	 *
-	 * @param string|NULL $assertion  The assertion which failed, or NULL if the assert-function was
-	 *                                given an expression.
-	 */
-	public function __construct($assertion = NULL) {
-		assert($assertion === null || is_string($assertion));
-
-		$msg = 'Assertion failed: ' . var_export($assertion, TRUE);
-		parent::__construct($msg);
-
-		$this->assertion = $assertion;
-	}
-
-
-	/**
-	 * Retrieve the assertion which failed.
-	 *
-	 * @return string|NULL  The assertion which failed, or NULL if the assert-function was called with an expression.
-	 */
-	public function getAssertion() {
-		return $this->assertion;
-	}
-
-
-	/**
-	 * Install this assertion handler.
-	 *
-	 * This function will register this assertion handler. If will not enable assertions if they are
-	 * disabled.
-	 */
-	public static function installHandler() {
-
-		assert_options(ASSERT_WARNING,    0);
-		assert_options(ASSERT_QUIET_EVAL, 0);
-		assert_options(ASSERT_CALLBACK,   array('SimpleSAML_Error_Assertion', 'onAssertion'));
-	}
-
-
-	/**
-	 * Handle assertion.
-	 *
-	 * This function handles an assertion.
-	 *
-	 * @param string $file  The file assert was called from.
-	 * @param int $line  The line assert was called from.
-	 * @param mixed $message  The expression which was passed to the assert-function.
-	 */
-	public static function onAssertion($file, $line, $message) {
-
-		if(!empty($message)) {
-			$exception = new self($message);
-		} else {
-			$exception = new self();
-		}
-
-		$exception->logError();
-	}
 
+class Assertion extends Exception
+{
+    /**
+     * The assertion which failed, or null if only an expression was passed to the
+     * assert-function.
+     */
+    private $assertion;
+
+
+    /**
+     * Constructor for the assertion exception.
+     *
+     * Should only be called from the onAssertion handler.
+     *
+     * @param string|null $assertion  The assertion which failed, or null if the assert-function was
+     *                                given an expression.
+     */
+    public function __construct($assertion = null)
+    {
+        assert($assertion === null || is_string($assertion));
+
+        $msg = 'Assertion failed: '.var_export($assertion, true);
+        parent::__construct($msg);
+
+        $this->assertion = $assertion;
+    }
+
+
+    /**
+     * Retrieve the assertion which failed.
+     *
+     * @return string|null  The assertion which failed, or null if the assert-function was called with an expression.
+     */
+    public function getAssertion()
+    {
+        return $this->assertion;
+    }
+
+
+    /**
+     * Install this assertion handler.
+     *
+     * This function will register this assertion handler. If will not enable assertions if they are
+     * disabled.
+     */
+    public static function installHandler()
+    {
+
+        assert_options(ASSERT_WARNING, 0);
+        assert_options(ASSERT_QUIET_EVAL, 0);
+        assert_options(ASSERT_CALLBACK, ['\SimpleSAML\Error\Assertion', 'onAssertion']);
+    }
+
+
+    /**
+     * Handle assertion.
+     *
+     * This function handles an assertion.
+     *
+     * @param string $file  The file assert was called from.
+     * @param int $line  The line assert was called from.
+     * @param mixed $message  The expression which was passed to the assert-function.
+     */
+    public static function onAssertion($file, $line, $message)
+    {
+
+        if (!empty($message)) {
+            $exception = new self($message);
+        } else {
+            $exception = new self();
+        }
+
+        $exception->logError();
+    }
 }
diff --git a/lib/SimpleSAML/Error/AuthSource.php b/lib/SimpleSAML/Error/AuthSource.php
index 119ffc4b38740d61c86f5f1be96f015dad42fd62..e075aa7bc45a5036300550bdd440de478acaae1a 100644
--- a/lib/SimpleSAML/Error/AuthSource.php
+++ b/lib/SimpleSAML/Error/AuthSource.php
@@ -1,68 +1,72 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * Baseclass for auth source exceptions.
- * 
+ *
  * @package SimpleSAMLphp_base
  *
  */
-class SimpleSAML_Error_AuthSource extends SimpleSAML_Error_Error {
-
-
-	/**
-	 * Authsource module name.
-	 */
-	private $authsource;
 
+class AuthSource extends Error
+{
+    /**
+     * Authsource module name.
+     */
+    private $authsource;
 
-	/**
-	 * Reason why this request was invalid.
-	 */
-	private $reason;
 
+    /**
+     * Reason why this request was invalid.
+     */
+    private $reason;
 
-	/**
-	 * Create a new AuthSource error.
-	 *
-	 * @param string $authsource  Authsource module name from where this error was thrown.
-	 * @param string $reason  Description of the error.
-	 */
-	public function __construct($authsource, $reason, $cause = NULL) {
-		assert(is_string($authsource));
-		assert(is_string($reason));
 
-		$this->authsource = $authsource;
-		$this->reason = $reason;
-		parent::__construct(
-			array(
-				'AUTHSOURCEERROR',
-				'%AUTHSOURCE%' => htmlspecialchars(var_export($this->authsource, TRUE)),
-				'%REASON%' => htmlspecialchars(var_export($this->reason, TRUE))
-			),
-			$cause
-		);
+    /**
+     * Create a new AuthSource error.
+     *
+     * @param string $authsource  Authsource module name from where this error was thrown.
+     * @param string $reason  Description of the error.
+     */
+    public function __construct($authsource, $reason, $cause = null)
+    {
+        assert(is_string($authsource));
+        assert(is_string($reason));
 
-		$this->message = "Error with authentication source '$authsource': $reason";
-	}
+        $this->authsource = $authsource;
+        $this->reason = $reason;
+        parent::__construct(
+            [
+                'AUTHSOURCEERROR',
+                '%AUTHSOURCE%' => htmlspecialchars(var_export($this->authsource, true)),
+                '%REASON%' => htmlspecialchars(var_export($this->reason, true))
+            ],
+            $cause
+        );
 
+        $this->message = "Error with authentication source '$authsource': $reason";
+    }
 
-	/**
-	 * Retrieve the authsource module name from where this error was thrown.
-	 *
-	 * @return string  Authsource module name.
-	 */
-	public function getAuthSource() {
-		return $this->authsource;
-	}
 
+    /**
+     * Retrieve the authsource module name from where this error was thrown.
+     *
+     * @return string  Authsource module name.
+     */
+    public function getAuthSource()
+    {
+        return $this->authsource;
+    }
 
-	/**
-	 * Retrieve the reason why the request was invalid.
-	 *
-	 * @return string  The reason why the request was invalid.
-	 */
-	public function getReason() {
-		return $this->reason;
-	}
 
-	
+    /**
+     * Retrieve the reason why the request was invalid.
+     *
+     * @return string  The reason why the request was invalid.
+     */
+    public function getReason()
+    {
+        return $this->reason;
+    }
 }
diff --git a/lib/SimpleSAML/Error/BadRequest.php b/lib/SimpleSAML/Error/BadRequest.php
index 21b57296b53ca363d58d59f2f0f690ab8e0082a5..1deb08c0bf3e9c3d2b9982868454168fc76dc29a 100644
--- a/lib/SimpleSAML/Error/BadRequest.php
+++ b/lib/SimpleSAML/Error/BadRequest.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Exception which will show a 400 Bad Request error page.
  *
@@ -9,36 +11,37 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_BadRequest extends SimpleSAML_Error_Error {
-
-
-	/**
-	 * Reason why this request was invalid.
-	 */
-	private $reason;
-
-
-	/**
-	 * Create a new BadRequest error.
-	 *
-	 * @param string $reason  Description of why the request was unacceptable.
-	 */
-	public function __construct($reason) {
-		assert(is_string($reason));
-
-		$this->reason = $reason;
-		parent::__construct(array('BADREQUEST', '%REASON%' => $this->reason));
-		$this->httpCode = 400;
-	}
-
-
-	/**
-	 * Retrieve the reason why the request was invalid.
-	 *
-	 * @return string  The reason why the request was invalid.
-	 */
-	public function getReason() {
-		return $this->reason;
-	}
 
+class BadRequest extends Error
+{
+    /**
+     * Reason why this request was invalid.
+     */
+    private $reason;
+
+
+    /**
+     * Create a new BadRequest error.
+     *
+     * @param string $reason  Description of why the request was unacceptable.
+     */
+    public function __construct($reason)
+    {
+        assert(is_string($reason));
+
+        $this->reason = $reason;
+        parent::__construct(['BADREQUEST', '%REASON%' => $this->reason]);
+        $this->httpCode = 400;
+    }
+
+
+    /**
+     * Retrieve the reason why the request was invalid.
+     *
+     * @return string  The reason why the request was invalid.
+     */
+    public function getReason()
+    {
+        return $this->reason;
+    }
 }
diff --git a/lib/SimpleSAML/Error/BadUserInnput.php b/lib/SimpleSAML/Error/BadUserInput.php
similarity index 66%
rename from lib/SimpleSAML/Error/BadUserInnput.php
rename to lib/SimpleSAML/Error/BadUserInput.php
index 48386c16ecea80a3275363f7058f8006aafaf122..5f94dcc0493fc0a17a88cb4a17d9aabed17921f8 100644
--- a/lib/SimpleSAML/Error/BadUserInnput.php
+++ b/lib/SimpleSAML/Error/BadUserInput.php
@@ -1,11 +1,15 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * Exception indicating illegal innput from user.
- * 
+ *
  * @author Thomas Graff <thomas.graff@uninett.no>
  * @package SimpleSAMLphp_base
  *
  */
-class SimpleSAML_Error_BadUserInnput extends SimpleSAML_Error_User{
-	
+
+class BadUserInput extends User
+{
 }
diff --git a/lib/SimpleSAML/Error/CannotSetCookie.php b/lib/SimpleSAML/Error/CannotSetCookie.php
index 31a25b0c535bb1006856f8e6f6741f25aac16556..70287404f9f7d9fb48a2d2e0e7718020b09f910a 100644
--- a/lib/SimpleSAML/Error/CannotSetCookie.php
+++ b/lib/SimpleSAML/Error/CannotSetCookie.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * Exception to indicate that we cannot set a cookie.
  *
@@ -6,12 +9,8 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Error;
-
-
-class CannotSetCookie extends \SimpleSAML_Error_Exception
+class CannotSetCookie extends Exception
 {
-
     /**
      * The exception was thrown for unknown reasons.
      *
diff --git a/lib/SimpleSAML/Error/ConfigurationError.php b/lib/SimpleSAML/Error/ConfigurationError.php
index 15eb30f366ee918b0226f1345587598c52cb4b2d..128093dad543d0991272cae7d353fc9156bfe442 100644
--- a/lib/SimpleSAML/Error/ConfigurationError.php
+++ b/lib/SimpleSAML/Error/ConfigurationError.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * This exception represents a configuration error.
  *
@@ -6,12 +9,8 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Error;
-
-
-class ConfigurationError extends \SimpleSAML_Error_Error
+class ConfigurationError extends Error
 {
-
     /**
      * The reason for this exception.
      *
@@ -38,7 +37,7 @@ class ConfigurationError extends \SimpleSAML_Error_Error
     {
         $file_str = '';
         $reason_str = '.';
-        $params = array('CONFIG');
+        $params = ['CONFIG'];
         if ($file !== null) {
             $params['%FILE%'] = $file;
             $basepath = dirname(dirname(dirname(dirname(__FILE__)))).'/';
diff --git a/lib/SimpleSAML/Error/CriticalConfigurationError.php b/lib/SimpleSAML/Error/CriticalConfigurationError.php
index 76af87ff8acbcb33fd404e6ff96aabbdc1c50c2a..d41367fbf051cd6800045888928c134a47551798 100644
--- a/lib/SimpleSAML/Error/CriticalConfigurationError.php
+++ b/lib/SimpleSAML/Error/CriticalConfigurationError.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * This exception represents a configuration error that we cannot recover from.
  *
@@ -18,23 +21,19 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Error;
-
-
 class CriticalConfigurationError extends ConfigurationError
 {
-
     /**
      * This is the bare minimum configuration that we can use.
      *
      * @var array
      */
-    private static $minimum_config = array(
+    private static $minimum_config = [
         'logging.handler' => 'errorlog',
         'logging.level'  => \SimpleSAML\Logger::DEBUG,
         'errorreporting' => false,
         'debug'          => true,
-    );
+    ];
 
 
     /**
@@ -42,7 +41,7 @@ class CriticalConfigurationError extends ConfigurationError
      *
      * @param string|null $reason The reason for this critical error.
      * @param string|null $file The configuration file that originated this error.
-     * @param array|null The configuration array that led to this problem.
+     * @param array|null $config The configuration array that led to this problem.
      */
     public function __construct($reason = null, $file = null, $config = null)
     {
@@ -51,7 +50,7 @@ class CriticalConfigurationError extends ConfigurationError
             $config['baseurlpath'] = \SimpleSAML\Utils\HTTP::guessBasePath();
         }
 
-        \SimpleSAML_Configuration::loadFromArray(
+        \SimpleSAML\Configuration::loadFromArray(
             $config,
             '',
             'simplesaml'
@@ -61,7 +60,7 @@ class CriticalConfigurationError extends ConfigurationError
 
 
     /**
-     * @param \Exception $exception
+     * @param ConfigurationError $exception
      *
      * @return CriticalConfigurationError
      */
diff --git a/lib/SimpleSAML/Error/Error.php b/lib/SimpleSAML/Error/Error.php
index 55b47a46010a8848c40e7ade837c52c7c722a2c5..0d8d011a0b659ded18caa3023e504d0968fcff65 100644
--- a/lib/SimpleSAML/Error/Error.php
+++ b/lib/SimpleSAML/Error/Error.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Error;
 
 /**
  * Class that wraps SimpleSAMLphp errors in exceptions.
@@ -7,7 +8,8 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
+
+class Error extends Exception
 {
     /**
      * The error code.
@@ -65,10 +67,10 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
      * (with index 0), is the error code, while the other elements are replacements for the error text.
      *
      * @param mixed     $errorCode One of the error codes defined in the errors dictionary.
-     * @param Exception $cause The exception which caused this fatal error (if any). Optional.
+     * @param \Exception $cause The exception which caused this fatal error (if any). Optional.
      * @param int|null  $httpCode The HTTP response code to use. Optional.
      */
-    public function __construct($errorCode, Exception $cause = null, $httpCode = null)
+    public function __construct($errorCode, \Exception $cause = null, $httpCode = null)
     {
         assert(is_string($errorCode) || is_array($errorCode));
 
@@ -77,7 +79,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
             unset($this->parameters[0]);
             $this->errorCode = $errorCode[0];
         } else {
-            $this->parameters = array();
+            $this->parameters = [];
             $this->errorCode = $errorCode;
         }
 
@@ -91,8 +93,8 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
             $this->dictTitle = '{'.$this->module.':errors:title_'.$moduleCode[1].'}';
             $this->dictDescr = '{'.$this->module.':errors:descr_'.$moduleCode[1].'}';
         } else {
-            $this->dictTitle = SimpleSAML\Error\ErrorCodes::getErrorCodeTitle($this->errorCode);
-            $this->dictDescr = SimpleSAML\Error\ErrorCodes::getErrorCodeDescription($this->errorCode);
+            $this->dictTitle = ErrorCodes::getErrorCodeTitle($this->errorCode);
+            $this->dictDescr = ErrorCodes::getErrorCodeDescription($this->errorCode);
         }
 
         if (!empty($this->parameters)) {
@@ -163,30 +165,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
      */
     protected function setHTTPCode()
     {
-        // Some mostly used HTTP codes
-        $httpCodesMap = array(
-            400 => 'HTTP/1.0 400 Bad Request',
-            403 => 'HTTP/1.0 403 Forbidden',
-            404 => 'HTTP/1.0 404 Not Found',
-            405 => 'HTTP/1.0 405 Method Not Allowed',
-            500 => 'HTTP/1.0 500 Internal Server Error',
-            501 => 'HTTP/1.0 501 Method Not Implemented',
-            503 => 'HTTP/1.0 503 Service Temporarily Unavailable',
-        );
-
-        $httpCode = $this->httpCode;
-
-        if (function_exists('http_response_code')) {
-            http_response_code($httpCode);
-            return;
-        }
-
-        if (!array_key_exists($this->httpCode, $httpCodesMap)) {
-            $httpCode = 500;
-            SimpleSAML\Logger::warning('HTTP response code not defined: '.var_export($this->httpCode, true));
-        }
-
-        header($httpCodesMap[$httpCode]);
+        http_response_code($this->httpCode);
     }
 
 
@@ -202,10 +181,10 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
         $etrace = implode("\n", $data);
 
         $reportId = bin2hex(openssl_random_pseudo_bytes(4));
-        SimpleSAML\Logger::error('Error report with id '.$reportId.' generated.');
+        \SimpleSAML\Logger::error('Error report with id '.$reportId.' generated.');
 
-        $config = SimpleSAML_Configuration::getInstance();
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $config = \SimpleSAML\Configuration::getInstance();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
 
         if (isset($_SERVER['HTTP_REFERER'])) {
             $referer = $_SERVER['HTTP_REFERER'];
@@ -217,7 +196,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
         } else {
             $referer = 'unknown';
         }
-        $errorData = array(
+        $errorData = [
             'exceptionMsg'   => $emsg,
             'exceptionTrace' => $etrace,
             'reportId'       => $reportId,
@@ -225,7 +204,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
             'url'            => \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(),
             'version'        => $config->getVersion(),
             'referer'        => $referer,
-        );
+        ];
         $session->setData('core:errorreport', $reportId, $errorData);
 
         return $errorData;
@@ -245,9 +224,9 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
         $this->logError();
 
         $errorData = $this->saveError();
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = \SimpleSAML\Configuration::getInstance();
 
-        $data = array();
+        $data = [];
         $data['showerrors'] = $config->getBoolean('showerrors', true);
         $data['error'] = $errorData;
         $data['errorCode'] = $this->errorCode;
@@ -268,7 +247,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
         }
 
         $data['email'] = '';
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $authorities = $session->getAuthorities();
         foreach ($authorities as $authority) {
             $attributes = $session->getAuthData($authority, 'Attributes');
@@ -284,7 +263,7 @@ class SimpleSAML_Error_Error extends SimpleSAML_Error_Exception
             call_user_func($show_function, $config, $data);
             assert(false);
         } else {
-            $t = new SimpleSAML_XHTML_Template($config, 'error.php', 'errors');
+            $t = new \SimpleSAML\XHTML\Template($config, 'error.php', 'errors');
             $t->data = array_merge($t->data, $data);
             $t->data['dictTitleTranslated'] = $t->getTranslator()->t($t->data['dictTitle']);
             $t->data['dictDescrTranslated'] = $t->getTranslator()->t($t->data['dictDescr'], $t->data['parameters']);
diff --git a/lib/SimpleSAML/Error/ErrorCodes.php b/lib/SimpleSAML/Error/ErrorCodes.php
index 3563a2d3d8f0c8eeb60a69f5246264174c86d38d..d15f8c46ff268d03933ec39b011f03f3547fac90 100644
--- a/lib/SimpleSAML/Error/ErrorCodes.php
+++ b/lib/SimpleSAML/Error/ErrorCodes.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * Class that maps SimpleSAMLphp error codes to translateable strings.
  *
@@ -6,8 +9,6 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Error;
-
 class ErrorCodes
 {
     /**
@@ -17,7 +18,7 @@ class ErrorCodes
      */
     final public static function defaultGetAllErrorCodeTitles()
     {
-        return array(
+        return [
             'ACSPARAMS' => \SimpleSAML\Locale\Translate::noop('{errors:title_ACSPARAMS}'),
             'ARSPARAMS' => \SimpleSAML\Locale\Translate::noop('{errors:title_ARSPARAMS}'),
             'AUTHSOURCEERROR' => \SimpleSAML\Locale\Translate::noop('{errors:title_AUTHSOURCEERROR}'),
@@ -51,7 +52,7 @@ class ErrorCodes
             'UNKNOWNCERT' => \SimpleSAML\Locale\Translate::noop('{errors:title_UNKNOWNCERT}'),
             'USERABORTED' => \SimpleSAML\Locale\Translate::noop('{errors:title_USERABORTED}'),
             'WRONGUSERPASS' => \SimpleSAML\Locale\Translate::noop('{errors:title_WRONGUSERPASS}'),
-        );
+        ];
     }
 
 
@@ -71,11 +72,11 @@ class ErrorCodes
     /**
      * Fetch all default translation strings for error code descriptions.
      *
-     * @return string A map from error code to error code description
+     * @return array A map from error code to error code description
      */
     final public static function defaultGetAllErrorCodeDescriptions()
     {
-        return array(
+        return [
             'ACSPARAMS' => \SimpleSAML\Locale\Translate::noop('{errors:descr_ACSPARAMS}'),
             'ARSPARAMS' => \SimpleSAML\Locale\Translate::noop('{errors:descr_ARSPARAMS}'),
             'AUTHSOURCEERROR' => \SimpleSAML\Locale\Translate::noop('{errors:descr_AUTHSOURCEERROR}'),
@@ -109,7 +110,7 @@ class ErrorCodes
             'UNKNOWNCERT' => \SimpleSAML\Locale\Translate::noop('{errors:descr_UNKNOWNCERT}'),
             'USERABORTED' => \SimpleSAML\Locale\Translate::noop('{errors:descr_USERABORTED}'),
             'WRONGUSERPASS' => \SimpleSAML\Locale\Translate::noop('{errors:descr_WRONGUSERPASS}'),
-        );
+        ];
     }
 
     /**
@@ -117,7 +118,7 @@ class ErrorCodes
      *
      * Extend this to add error codes.
      *
-     * @return string A map from error code to error code description
+     * @return array A map from error code to error code description
      */
     public static function getAllErrorCodeDescriptions()
     {
@@ -134,10 +135,10 @@ class ErrorCodes
      */
     public static function getAllErrorCodeMessages()
     {
-        return array(
+        return [
             'title' => self::getAllErrorCodeTitles(),
             'descr' => self::getAllErrorCodeDescriptions(),
-        );
+        ];
     }
 
 
@@ -180,9 +181,9 @@ class ErrorCodes
      */
     public static function getErrorCodeMessage($errorCode)
     {
-        return array(
+        return [
             'title' => self::getErrorCodeTitle($errorCode),
             'descr' => self::getErrorCodeDescription($errorCode),
-        );
+        ];
     }
 }
diff --git a/lib/SimpleSAML/Error/Exception.php b/lib/SimpleSAML/Error/Exception.php
index 48d74cd2f6ef3159cbc3d8395e4611d5570b3586..5ab59f4821213500199c53e50b15968bc3e58124 100644
--- a/lib/SimpleSAML/Error/Exception.php
+++ b/lib/SimpleSAML/Error/Exception.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Error;
 
 /**
  * Base class for SimpleSAMLphp Exceptions
@@ -9,9 +10,9 @@
  * @author Thomas Graff <thomas.graff@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_Exception extends Exception
-{
 
+class Exception extends \Exception
+{
     /**
      * The backtrace for this exception.
      *
@@ -26,7 +27,7 @@ class SimpleSAML_Error_Exception extends Exception
     /**
      * The cause of this exception.
      *
-     * @var SimpleSAML_Error_Exception
+     * @var Exception
      */
     private $cause;
 
@@ -34,14 +35,14 @@ class SimpleSAML_Error_Exception extends Exception
     /**
      * Constructor for this error.
      *
-     * Note that the cause will be converted to a SimpleSAML_Error_UnserializableException unless it is a subclass of
-     * SimpleSAML_Error_Exception.
+     * Note that the cause will be converted to a SimpleSAML\Error\UnserializableException unless it is a subclass of
+     * SimpleSAML\Error\Exception.
      *
      * @param string         $message Exception message
      * @param int            $code Error code
-     * @param Exception|null $cause The cause of this exception.
+     * @param \Exception|null $cause The cause of this exception.
      */
-    public function __construct($message, $code = 0, Exception $cause = null)
+    public function __construct($message, $code = 0, \Exception $cause = null)
     {
         assert(is_string($message));
         assert(is_int($code));
@@ -51,43 +52,40 @@ class SimpleSAML_Error_Exception extends Exception
         $this->initBacktrace($this);
 
         if ($cause !== null) {
-            $this->cause = SimpleSAML_Error_Exception::fromException($cause);
+            $this->cause = Exception::fromException($cause);
         }
     }
 
 
     /**
-     * Convert any exception into a SimpleSAML_Error_Exception.
+     * Convert any exception into a \SimpleSAML\Error\Exception.
      *
-     * @param Exception $e The exception.
+     * @param \Exception $e The exception.
      *
-     * @return SimpleSAML_Error_Exception The new exception.
+     * @return Exception The new exception.
      */
-    public static function fromException(Exception $e)
+    public static function fromException(\Exception $e)
     {
-
-        if ($e instanceof SimpleSAML_Error_Exception) {
+        if ($e instanceof Exception) {
             return $e;
         }
-        return new SimpleSAML_Error_UnserializableException($e);
+        return new UnserializableException($e);
     }
 
 
     /**
      * Load the backtrace from the given exception.
      *
-     * @param Exception $exception The exception we should fetch the backtrace from.
+     * @param \Exception $exception The exception we should fetch the backtrace from.
      */
-    protected function initBacktrace(Exception $exception)
+    protected function initBacktrace(\Exception $exception)
     {
-
-        $this->backtrace = array();
+        $this->backtrace = [];
 
         // position in the top function on the stack
         $pos = $exception->getFile().':'.$exception->getLine();
 
         foreach ($exception->getTrace() as $t) {
-
             $function = $t['function'];
             if (array_key_exists('class', $t)) {
                 $function = $t['class'].'::'.$function;
@@ -120,7 +118,7 @@ class SimpleSAML_Error_Exception extends Exception
     /**
      * Retrieve the cause of this exception.
      *
-     * @return SimpleSAML_Error_Exception|null The cause of this exception.
+     * @return Exception|null The cause of this exception.
      */
     public function getCause()
     {
@@ -150,9 +148,9 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function format($anonymize = false)
     {
-        $ret = array(
+        $ret = [
             $this->getClass().': '.$this->getMessage(),
-        );
+        ];
         return array_merge($ret, $this->formatBacktrace($anonymize));
     }
 
@@ -168,8 +166,8 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function formatBacktrace($anonymize = false)
     {
-        $ret = array();
-        $basedir = SimpleSAML_Configuration::getInstance()->getBaseDir();
+        $ret = [];
+        $basedir = \SimpleSAML\Configuration::getInstance()->getBaseDir();
 
         $e = $this;
         do {
@@ -199,25 +197,26 @@ class SimpleSAML_Error_Exception extends Exception
     protected function logBacktrace($level = \SimpleSAML\Logger::DEBUG)
     {
         // see if debugging is enabled for backtraces
-        $debug = SimpleSAML_Configuration::getInstance()->getArrayize('debug', array('backtraces' => false));
+        $debug = \SimpleSAML\Configuration::getInstance()->getArrayize('debug', ['backtraces' => false]);
 
         if (!(in_array('backtraces', $debug, true) // implicitly enabled
-              || (array_key_exists('backtraces', $debug) && $debug['backtraces'] === true) // explicitly set
-              // TODO: deprecate the old style and remove it in 2.0
-              || (array_key_exists(0, $debug) && $debug[0] === true) // old style 'debug' configuration option
+            || (array_key_exists('backtraces', $debug) && $debug['backtraces'] === true)
+            // explicitly set
+            // TODO: deprecate the old style and remove it in 2.0
+            || (array_key_exists(0, $debug) && $debug[0] === true) // old style 'debug' configuration option
         )) {
             return;
         }
 
         $backtrace = $this->formatBacktrace();
 
-        $callback = array('\SimpleSAML\Logger');
-        $functions = array(
+        $callback = ['\SimpleSAML\Logger'];
+        $functions = [
             \SimpleSAML\Logger::ERR     => 'error',
             \SimpleSAML\Logger::WARNING => 'warning',
             \SimpleSAML\Logger::INFO    => 'info',
             \SimpleSAML\Logger::DEBUG   => 'debug',
-        );
+        ];
         $callback[] = $functions[$level];
 
         foreach ($backtrace as $line) {
@@ -235,13 +234,13 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function log($default_level)
     {
-        $fn = array(
-            SimpleSAML\Logger::ERR     => 'logError',
-            SimpleSAML\Logger::WARNING => 'logWarning',
-            SimpleSAML\Logger::INFO    => 'logInfo',
-            SimpleSAML\Logger::DEBUG   => 'logDebug',
-        );
-        call_user_func(array($this, $fn[$default_level]), $default_level);
+        $fn = [
+            \SimpleSAML\Logger::ERR     => 'logError',
+            \SimpleSAML\Logger::WARNING => 'logWarning',
+            \SimpleSAML\Logger::INFO    => 'logInfo',
+            \SimpleSAML\Logger::DEBUG   => 'logDebug',
+        ];
+        call_user_func([$this, $fn[$default_level]], $default_level);
     }
 
 
@@ -252,7 +251,7 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function logError()
     {
-        SimpleSAML\Logger::error($this->getClass().': '.$this->getMessage());
+        \SimpleSAML\Logger::error($this->getClass().': '.$this->getMessage());
         $this->logBacktrace(\SimpleSAML\Logger::ERR);
     }
 
@@ -264,7 +263,7 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function logWarning()
     {
-        SimpleSAML\Logger::warning($this->getClass().': '.$this->getMessage());
+        \SimpleSAML\Logger::warning($this->getClass().': '.$this->getMessage());
         $this->logBacktrace(\SimpleSAML\Logger::WARNING);
     }
 
@@ -276,7 +275,7 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function logInfo()
     {
-        SimpleSAML\Logger::info($this->getClass().': '.$this->getMessage());
+        \SimpleSAML\Logger::info($this->getClass().': '.$this->getMessage());
         $this->logBacktrace(\SimpleSAML\Logger::INFO);
     }
 
@@ -288,7 +287,7 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function logDebug()
     {
-        SimpleSAML\Logger::debug($this->getClass().': '.$this->getMessage());
+        \SimpleSAML\Logger::debug($this->getClass().': '.$this->getMessage());
         $this->logBacktrace(\SimpleSAML\Logger::DEBUG);
     }
 
@@ -303,7 +302,6 @@ class SimpleSAML_Error_Exception extends Exception
      */
     public function __sleep()
     {
-
         $ret = array_keys((array) $this);
 
         foreach ($ret as $i => $e) {
diff --git a/lib/SimpleSAML/Error/InvalidCredential.php b/lib/SimpleSAML/Error/InvalidCredential.php
index 5a3f7d8a4f15fd823a8a67159555d6bc81a6b1bc..98d3b85d7b993e0ea9d1e0816dd3778c56548f54 100644
--- a/lib/SimpleSAML/Error/InvalidCredential.php
+++ b/lib/SimpleSAML/Error/InvalidCredential.php
@@ -1,11 +1,15 @@
 <?php
+
+namespace SimpleSAML\Error;
+
 /**
  * Exception indicating wrong password given by user.
- * 
+ *
  * @author Thomas Graff <thomas.graff@uninett.no>
  * @package SimpleSAMLphp_base
  *
  */
-class SimpleSAML_Error_InvalidCredential extends SimpleSAML_Error_User{
-	
+
+class InvalidCredential extends User
+{
 }
diff --git a/lib/SimpleSAML/Error/MetadataNotFound.php b/lib/SimpleSAML/Error/MetadataNotFound.php
index 9fe5a498a6e7eb93812d908d8b9b4f9a98234c10..47636bc215e7029b885a330342cd31561cc56076 100644
--- a/lib/SimpleSAML/Error/MetadataNotFound.php
+++ b/lib/SimpleSAML/Error/MetadataNotFound.php
@@ -1,26 +1,28 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Error for missing metadata.
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_MetadataNotFound extends SimpleSAML_Error_Error {
-
-
-	/**
-	 * Create the error
-	 *
-	 * @param string $entityId  The entityID we were unable to locate.
-	 */
-	public function __construct($entityId) {
-		assert(is_string($entityId));
 
-		$this->includeTemplate = 'core:no_metadata.tpl.php';
-		parent::__construct(array(
-				'METADATANOTFOUND',
-				'%ENTITYID%' => htmlspecialchars(var_export($entityId, TRUE))
-		));
-	}
+class MetadataNotFound extends Error
+{
+    /**
+     * Create the error
+     *
+     * @param string $entityId  The entityID we were unable to locate.
+     */
+    public function __construct($entityId)
+    {
+        assert(is_string($entityId));
 
+        $this->includeTemplate = 'core:no_metadata.tpl.php';
+        parent::__construct([
+                'METADATANOTFOUND',
+                '%ENTITYID%' => htmlspecialchars(var_export($entityId, true))
+        ]);
+    }
 }
diff --git a/lib/SimpleSAML/Error/NoPassive.php b/lib/SimpleSAML/Error/NoPassive.php
index 8966dc8b527497999edea34fc9db2cc47451fa1e..43b42cf46b1110e3e4787adfdf5b36aa1e6668b0 100644
--- a/lib/SimpleSAML/Error/NoPassive.php
+++ b/lib/SimpleSAML/Error/NoPassive.php
@@ -1,14 +1,16 @@
 <?php
 
+namespace SimpleSAML\Error;
 
 /**
- * Class SimpleSAML_Error_NoPassive
+ * Class NoPassive
  *
  * @deprecated This class has been deprecated and will be removed in SimpleSAMLphp 2.0. Please use
- * SimpleSAML\Module\saml\Error\NoPassive instead.
+ * \SimpleSAML\Module\saml\Error\NoPassive instead.
  *
  * @see \SimpleSAML\Module\saml\Error\NoPassive
  */
-class SimpleSAML_Error_NoPassive extends SimpleSAML_Error_Exception {
 
+class NoPassive extends Exception
+{
 }
diff --git a/lib/SimpleSAML/Error/NoState.php b/lib/SimpleSAML/Error/NoState.php
index 1c92da92728a3d8086f484fb8f9f383903e58294..d0281beb01eb4d6bc0c2a8dcbb4255d042947adf 100644
--- a/lib/SimpleSAML/Error/NoState.php
+++ b/lib/SimpleSAML/Error/NoState.php
@@ -1,20 +1,22 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Exception which will show a page telling the user
  * that we don't know what to do.
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_NoState extends SimpleSAML_Error_Error {
-
-
-	/**
-	 * Create the error
-	 */
-	public function __construct() {
-		$this->includeTemplate = 'core:no_state.tpl.php';
-		parent::__construct('NOSTATE');
-	}
 
+class NoState extends Error
+{
+    /**
+     * Create the error
+     */
+    public function __construct()
+    {
+        $this->includeTemplate = 'core:no_state.tpl.php';
+        parent::__construct('NOSTATE');
+    }
 }
diff --git a/lib/SimpleSAML/Error/NotFound.php b/lib/SimpleSAML/Error/NotFound.php
index 0c1f460a3367d6f03c2d45b2d0a0bc40f07cb59a..0e618526962b0a596948e394b1f04abf046c1298 100644
--- a/lib/SimpleSAML/Error/NotFound.php
+++ b/lib/SimpleSAML/Error/NotFound.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Exception which will show a 404 Not Found error page.
  *
@@ -9,60 +11,62 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_NotFound extends SimpleSAML_Error_Error {
-
-
-	/**
-	 * Reason why the given page could not be found.
-	 */
-	private $reason;
 
+class NotFound extends Error
+{
+    /**
+     * Reason why the given page could not be found.
+     */
+    private $reason;
 
-	/**
-	 * Create a new NotFound error
-	 *
-	 * @param string $reason  Optional description of why the given page could not be found.
-	 */
-	public function __construct($reason = NULL) {
 
-		assert($reason === null || is_string($reason));
+    /**
+     * Create a new NotFound error
+     *
+     * @param string $reason  Optional description of why the given page could not be found.
+     */
+    public function __construct($reason = null)
+    {
+        assert($reason === null || is_string($reason));
 
-		$url = \SimpleSAML\Utils\HTTP::getSelfURL();
+        $url = \SimpleSAML\Utils\HTTP::getSelfURL();
 
-		if($reason === NULL) {
-			parent::__construct(array('NOTFOUND', '%URL%' => $url));
-			$this->message = "The requested page '$url' could not be found.";
-		} else {
-			parent::__construct(array('NOTFOUNDREASON', '%URL%' => $url, '%REASON%' => $reason));
-			$this->message = "The requested page '$url' could not be found. ".$reason;
-		}
+        if ($reason === null) {
+            parent::__construct(['NOTFOUND', '%URL%' => $url]);
+            $this->message = "The requested page '$url' could not be found.";
+        } else {
+            parent::__construct(['NOTFOUNDREASON', '%URL%' => $url, '%REASON%' => $reason]);
+            $this->message = "The requested page '$url' could not be found. ".$reason;
+        }
 
-		$this->reason = $reason;
-		$this->httpCode = 404;
-	}
+        $this->reason = $reason;
+        $this->httpCode = 404;
+    }
 
 
-	/**
-	 * Retrieve the reason why the given page could not be found.
-	 *
-	 * @return string|NULL  The reason why the page could not be found.
-	 */
-	public function getReason() {
-		return $this->reason;
-	}
+    /**
+     * Retrieve the reason why the given page could not be found.
+     *
+     * @return string|null  The reason why the page could not be found.
+     */
+    public function getReason()
+    {
+        return $this->reason;
+    }
 
 
-	/**
-	 * NotFound exceptions don't need to display a backtrace, as they are very simple and the trace is usually trivial,
-	 * so just log the message without any backtrace at all.
-	 *
-	 * @param bool $anonymize Whether to anonymize the trace or not.
-	 *
-	 * @return array
-	 */
-	public function format($anonymize = false) {
-		return array(
-			$this->getClass().': '.$this->getMessage(),
-		);
-	}
+    /**
+     * NotFound exceptions don't need to display a backtrace, as they are very simple and the trace is usually trivial,
+     * so just log the message without any backtrace at all.
+     *
+     * @param bool $anonymize Whether to anonymize the trace or not.
+     *
+     * @return array
+     */
+    public function format($anonymize = false)
+    {
+        return [
+            $this->getClass().': '.$this->getMessage(),
+        ];
+    }
 }
diff --git a/lib/SimpleSAML/Error/ProxyCountExceeded.php b/lib/SimpleSAML/Error/ProxyCountExceeded.php
index 0af64d51e740db277e523d89284290d6b16a3122..6b325f3b61a59d4d5ae6bd064e65ae46e13ab48c 100644
--- a/lib/SimpleSAML/Error/ProxyCountExceeded.php
+++ b/lib/SimpleSAML/Error/ProxyCountExceeded.php
@@ -1,14 +1,16 @@
 <?php
 
+namespace SimpleSAML\Error;
 
 /**
- * Class SimpleSAML_Error_ProxyCountExceeded
+ * Class ProxyCountExceeded
  *
  * @deprecated This class has been deprecated and will be removed in SimpleSAMLphp 2.0. Please use
- * SimpleSAML\Module\saml\Error\ProxyCountExceeded instead.
+ * \SimpleSAML\Module\saml\Error\ProxyCountExceeded instead.
  *
  * @see \SimpleSAML\Module\saml\Error\ProxyCountExceeded
  */
-class SimpleSAML_Error_ProxyCountExceeded extends SimpleSAML_Error_Exception {
 
+class ProxyCountExceeded extends Exception
+{
 }
diff --git a/lib/SimpleSAML/Error/UnserializableException.php b/lib/SimpleSAML/Error/UnserializableException.php
index 6c55bece1381dcc74eac1ada769fcf65d5333002..54f4eb34feb9a98d40aabc48e985e7687be37b94 100644
--- a/lib/SimpleSAML/Error/UnserializableException.php
+++ b/lib/SimpleSAML/Error/UnserializableException.php
@@ -1,55 +1,59 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Class for saving normal exceptions for serialization.
  *
- * This class is used by the SimpleSAML_Auth_State class when it needs
+ * This class is used by the \SimpleSAML\Auth\State class when it needs
  * to serialize an exception which doesn't subclass the
- * SimpleSAML_Error_Exception class.
+ * \SimpleSAML\Error\Exception class.
  *
  * It creates a new exception which contains the backtrace and message
  * of the original exception.
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_UnserializableException extends SimpleSAML_Error_Exception {
-
-	/**
-	 * The classname of the original exception.
-	 *
-	 * @var string
-	 */
-	private $class;
-
-
-	/**
-	 * Create a serializable exception representing an unserializable exception.
-	 *
-	 * @param Exception $original  The original exception.
-	 */
-	public function __construct(Exception $original) {
-
-		$this->class = get_class($original);
-		$msg = $original->getMessage();
-		$code = $original->getCode();
-
-		if (!is_int($code)) {
-			// PDOException uses a string as the code. Filter it out here.
-			$code = -1;
-		}
-
-		parent::__construct($msg, $code);
-		$this->initBacktrace($original);
-	}
-
-
-	/**
-	 * Retrieve the class of this exception.
-	 *
-	 * @return string  The classname.
-	 */
-	public function getClass() {
-		return $this->class;
-	}
 
+class UnserializableException extends Exception
+{
+    /**
+     * The classname of the original exception.
+     *
+     * @var string
+     */
+    private $class;
+
+
+    /**
+     * Create a serializable exception representing an unserializable exception.
+     *
+     * @param \Exception $original  The original exception.
+     */
+    public function __construct(\Exception $original)
+    {
+
+        $this->class = get_class($original);
+        $msg = $original->getMessage();
+        $code = $original->getCode();
+
+        if (!is_int($code)) {
+            // PDOException uses a string as the code. Filter it out here.
+            $code = -1;
+        }
+
+        parent::__construct($msg, $code);
+        $this->initBacktrace($original);
+    }
+
+
+    /**
+     * Retrieve the class of this exception.
+     *
+     * @return string  The classname.
+     */
+    public function getClass()
+    {
+        return $this->class;
+    }
 }
diff --git a/lib/SimpleSAML/Error/User.php b/lib/SimpleSAML/Error/User.php
index 2f674be18f97d6f59063810f5cde54820974a9dd..b2da0e47e1a644ba4df559616cc44d8b8829acc7 100644
--- a/lib/SimpleSAML/Error/User.php
+++ b/lib/SimpleSAML/Error/User.php
@@ -1,13 +1,16 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Baseclass for user error exceptions
- * 
- * 
+ *
+ *
  * @author Thomas Graff <thomas.graff@uninett.no>
  * @package SimpleSAMLphp_base
  *
  */
-class SimpleSAML_Error_User extends SimpleSAML_Error_Exception{
-	
+
+class User extends Exception
+{
 }
diff --git a/lib/SimpleSAML/Error/UserAborted.php b/lib/SimpleSAML/Error/UserAborted.php
index 6bd2762afae00d4b0aad0630092cb550683af820..7be00d20ee67a3ba621b8122b749ea11e2028c0f 100644
--- a/lib/SimpleSAML/Error/UserAborted.php
+++ b/lib/SimpleSAML/Error/UserAborted.php
@@ -1,19 +1,22 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Exception indicating user aborting the authentication process.
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Error_UserAborted extends SimpleSAML_Error_Error {
-
-	/**
-	 * Create the error
-	 *
-	 * @param Exception|NULL $cause  The exception that caused this error.
-	 */
-	public function __construct(Exception $cause = NULL) {
-		parent::__construct('USERABORTED', $cause);
-	}
 
+class UserAborted extends Error
+{
+    /**
+     * Create the error
+     *
+     * @param \Exception|null $cause  The exception that caused this error.
+     */
+    public function __construct(\Exception $cause = null)
+    {
+        parent::__construct('USERABORTED', $cause);
+    }
 }
diff --git a/lib/SimpleSAML/Error/UserNotFound.php b/lib/SimpleSAML/Error/UserNotFound.php
index c536f724301e96596e805ed63dcf828f488f2335..14e55078644b47719645733fff5b70e0b2a749cb 100644
--- a/lib/SimpleSAML/Error/UserNotFound.php
+++ b/lib/SimpleSAML/Error/UserNotFound.php
@@ -1,12 +1,15 @@
 <?php
 
+namespace SimpleSAML\Error;
+
 /**
  * Exception indicating user not found by authsource.
- * 
+ *
  * @author Thomas Graff <thomas.graff@uninett.no>
  * @package SimpleSAMLphp_base
  *
  */
-class SimpleSAML_Error_UserNotFound extends SimpleSAML_Error_User{
-	
+
+class UserNotFound extends User
+{
 }
diff --git a/lib/SimpleSAML/IdP.php b/lib/SimpleSAML/IdP.php
index 42a57ae9e385e2d470e5fa5870226982640740e0..70db63b4c4284b55ef2a02edc277d0b0fc4a5b1d 100644
--- a/lib/SimpleSAML/IdP.php
+++ b/lib/SimpleSAML/IdP.php
@@ -1,5 +1,9 @@
 <?php
 
+namespace SimpleSAML;
+
+use SimpleSAML\Error\Exception;
+
 /**
  * IdP class.
  *
@@ -7,14 +11,15 @@
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_IdP
+
+class IdP
 {
     /**
      * A cache for resolving IdP id's.
      *
      * @var array
      */
-    private static $idpCache = array();
+    private static $idpCache = [];
 
     /**
      * The identifier for this IdP.
@@ -36,14 +41,14 @@ class SimpleSAML_IdP
     /**
      * The configuration for this IdP.
      *
-     * @var SimpleSAML_Configuration
+     * @var Configuration
      */
     private $config;
 
     /**
      * Our authsource.
      *
-     * @var \SimpleSAML\Auth\Simple
+     * @var Auth\Simple
      */
     private $authSource;
 
@@ -52,7 +57,7 @@ class SimpleSAML_IdP
      *
      * @param string $id The identifier of this IdP.
      *
-     * @throws SimpleSAML_Error_Exception If the IdP is disabled or no such auth source was found.
+     * @throws Exception If the IdP is disabled or no such auth source was found.
      */
     private function __construct($id)
     {
@@ -60,22 +65,22 @@ class SimpleSAML_IdP
 
         $this->id = $id;
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
-        $globalConfig = SimpleSAML_Configuration::getInstance();
+        $metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
+        $globalConfig = Configuration::getInstance();
 
         if (substr($id, 0, 6) === 'saml2:') {
             if (!$globalConfig->getBoolean('enable.saml20-idp', false)) {
-                throw new SimpleSAML_Error_Exception('enable.saml20-idp disabled in config.php.');
+                throw new Exception('enable.saml20-idp disabled in config.php.');
             }
             $this->config = $metadata->getMetaDataConfig(substr($id, 6), 'saml20-idp-hosted');
         } elseif (substr($id, 0, 6) === 'saml1:') {
             if (!$globalConfig->getBoolean('enable.shib13-idp', false)) {
-                throw new SimpleSAML_Error_Exception('enable.shib13-idp disabled in config.php.');
+                throw new Exception('enable.shib13-idp disabled in config.php.');
             }
             $this->config = $metadata->getMetaDataConfig(substr($id, 6), 'shib13-idp-hosted');
         } elseif (substr($id, 0, 5) === 'adfs:') {
             if (!$globalConfig->getBoolean('enable.adfs-idp', false)) {
-                throw new SimpleSAML_Error_Exception('enable.adfs-idp disabled in config.php.');
+                throw new Exception('enable.adfs-idp disabled in config.php.');
             }
             $this->config = $metadata->getMetaDataConfig(substr($id, 5), 'adfs-idp-hosted');
 
@@ -83,7 +88,7 @@ class SimpleSAML_IdP
                 // this makes the ADFS IdP use the same SP associations as the SAML 2.0 IdP
                 $saml2EntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
                 $this->associationGroup = 'saml2:'.$saml2EntityId;
-            } catch (Exception $e) {
+            } catch (\Exception $e) {
                 // probably no SAML 2 IdP configured for this host. Ignore the error
             }
         } else {
@@ -95,10 +100,10 @@ class SimpleSAML_IdP
         }
 
         $auth = $this->config->getString('auth');
-        if (SimpleSAML_Auth_Source::getById($auth) !== null) {
-            $this->authSource = new \SimpleSAML\Auth\Simple($auth);
+        if (Auth\Source::getById($auth) !== null) {
+            $this->authSource = new Auth\Simple($auth);
         } else {
-            throw new SimpleSAML_Error_Exception('No such "'.$auth.'" auth source found.');
+            throw new Exception('No such "'.$auth.'" auth source found.');
         }
     }
 
@@ -119,7 +124,7 @@ class SimpleSAML_IdP
      *
      * @param string $id The identifier of the IdP.
      *
-     * @return SimpleSAML_IdP The IdP.
+     * @return IdP The IdP.
      */
     public static function getById($id)
     {
@@ -140,7 +145,7 @@ class SimpleSAML_IdP
      *
      * @param array &$state The state array.
      *
-     * @return SimpleSAML_IdP The IdP.
+     * @return IdP The IdP.
      */
     public static function getByState(array &$state)
     {
@@ -153,7 +158,7 @@ class SimpleSAML_IdP
     /**
      * Retrieve the configuration for this IdP.
      *
-     * @return SimpleSAML_Configuration The configuration object.
+     * @return Configuration The configuration object.
      */
     public function getConfig()
     {
@@ -174,15 +179,15 @@ class SimpleSAML_IdP
 
         $prefix = substr($assocId, 0, 4);
         $spEntityId = substr($assocId, strlen($prefix) + 1);
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = Metadata\MetaDataStorageHandler::getMetadataHandler();
 
         if ($prefix === 'saml') {
             try {
                 $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
-            } catch (Exception $e) {
+            } catch (\Exception $e) {
                 try {
                     $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'shib13-sp-remote');
-                } catch (Exception $e) {
+                } catch (\Exception $e) {
                     return null;
                 }
             }
@@ -199,7 +204,7 @@ class SimpleSAML_IdP
         } elseif ($spMetadata->hasValue('OrganizationDisplayName')) {
             return $spMetadata->getLocalizedString('OrganizationDisplayName');
         } else {
-            return array('en' => $spEntityId);
+            return ['en' => $spEntityId];
         }
     }
 
@@ -216,7 +221,7 @@ class SimpleSAML_IdP
 
         $association['core:IdP'] = $this->id;
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         $session->addAssociation($this->associationGroup, $association);
     }
 
@@ -228,7 +233,7 @@ class SimpleSAML_IdP
      */
     public function getAssociations()
     {
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         return $session->getAssociations($this->associationGroup);
     }
 
@@ -242,7 +247,7 @@ class SimpleSAML_IdP
     {
         assert(is_string($assocId));
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         $session->terminateAssociation($this->associationGroup, $assocId);
     }
 
@@ -268,12 +273,12 @@ class SimpleSAML_IdP
         assert(is_callable($state['Responder']));
 
         if (isset($state['core:SP'])) {
-            $session = SimpleSAML_Session::getSessionFromRequest();
+            $session = \SimpleSAML\Session::getSessionFromRequest();
             $session->setData(
                 'core:idp-ssotime',
                 $state['core:IdP'].';'.$state['core:SP'],
                 time(),
-                SimpleSAML_Session::DATA_TIMEOUT_SESSION_END
+                Session::DATA_TIMEOUT_SESSION_END
             );
         }
 
@@ -287,14 +292,14 @@ class SimpleSAML_IdP
      *
      * @param array $state The authentication request state array.
      *
-     * @throws SimpleSAML_Error_Exception If we are not authenticated.
+     * @throws Exception If we are not authenticated.
      */
     public static function postAuth(array $state)
     {
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = IdP::getByState($state);
 
         if (!$idp->isAuthenticated()) {
-            throw new SimpleSAML_Error_Exception('Not authenticated.');
+            throw new Exception('Not authenticated.');
         }
 
         $state['Attributes'] = $idp->authSource->getAttributes();
@@ -302,11 +307,11 @@ class SimpleSAML_IdP
         if (isset($state['SPMetadata'])) {
             $spMetadata = $state['SPMetadata'];
         } else {
-            $spMetadata = array();
+            $spMetadata = [];
         }
 
         if (isset($state['core:SP'])) {
-            $session = SimpleSAML_Session::getSessionFromRequest();
+            $session = Session::getSessionFromRequest();
             $previousSSOTime = $session->getData('core:idp-ssotime', $state['core:IdP'].';'.$state['core:SP']);
             if ($previousSSOTime !== null) {
                 $state['PreviousSSOTimestamp'] = $previousSSOTime;
@@ -315,9 +320,9 @@ class SimpleSAML_IdP
 
         $idpMetadata = $idp->getConfig()->toArray();
 
-        $pc = new SimpleSAML_Auth_ProcessingChain($idpMetadata, $spMetadata, 'idp');
+        $pc = new Auth\ProcessingChain($idpMetadata, $spMetadata, 'idp');
 
-        $state['ReturnCall'] = array('SimpleSAML_IdP', 'postAuthProc');
+        $state['ReturnCall'] = ['\SimpleSAML\IdP', 'postAuthProc'];
         $state['Destination'] = $spMetadata;
         $state['Source'] = $idpMetadata;
 
@@ -334,12 +339,12 @@ class SimpleSAML_IdP
      *
      * @param array &$state The authentication request state.
      *
-     * @throws \SimpleSAML\Module\saml\Error\NoPassive If we were asked to do passive authentication.
+     * @throws Module\saml\Error\NoPassive If we were asked to do passive authentication.
      */
     private function authenticate(array &$state)
     {
         if (isset($state['isPassive']) && (bool) $state['isPassive']) {
-            throw new \SimpleSAML\Module\saml\Error\NoPassive('Passive authentication not supported.');
+            throw new Module\saml\Error\NoPassive('Passive authentication not supported.');
         }
 
         $this->authSource->login($state);
@@ -356,13 +361,13 @@ class SimpleSAML_IdP
      *
      * @param array &$state The authentication request state.
      *
-     * @throws SimpleSAML_Error_Exception If there is no auth source defined for this IdP.
+     * @throws Exception If there is no auth source defined for this IdP.
      */
     private function reauthenticate(array &$state)
     {
         $sourceImpl = $this->authSource->getAuthSource();
         if ($sourceImpl === null) {
-            throw new SimpleSAML_Error_Exception('No such auth source defined.');
+            throw new Exception('No such auth source defined.');
         }
 
         $sourceImpl->reauthenticate($state);
@@ -398,7 +403,7 @@ class SimpleSAML_IdP
         }
 
         $state['IdPMetadata'] = $this->getConfig()->toArray();
-        $state['ReturnCallback'] = array('SimpleSAML_IdP', 'postAuth');
+        $state['ReturnCallback'] = ['\SimpleSAML\IdP', 'postAuth'];
 
         try {
             if ($needAuth) {
@@ -408,11 +413,11 @@ class SimpleSAML_IdP
                 $this->reauthenticate($state);
             }
             $this->postAuth($state);
-        } catch (SimpleSAML_Error_Exception $e) {
-            SimpleSAML_Auth_State::throwException($state, $e);
         } catch (Exception $e) {
-            $e = new SimpleSAML_Error_UnserializableException($e);
-            SimpleSAML_Auth_State::throwException($state, $e);
+            \SimpleSAML\Auth\State::throwException($state, $e);
+        } catch (\Exception $e) {
+            $e = new Error\UnserializableException($e);
+            Auth\State::throwException($state, $e);
         }
     }
 
@@ -420,9 +425,9 @@ class SimpleSAML_IdP
     /**
      * Find the logout handler of this IdP.
      *
-     * @return \SimpleSAML\IdP\LogoutHandlerInterface The logout handler class.
+     * @return IdP\LogoutHandlerInterface The logout handler class.
      *
-     * @throws SimpleSAML_Error_Exception If we cannot find a logout handler.
+     * @throws Exception If we cannot find a logout handler.
      */
     public function getLogoutHandler()
     {
@@ -430,13 +435,13 @@ class SimpleSAML_IdP
         $logouttype = $this->getConfig()->getString('logouttype', 'traditional');
         switch ($logouttype) {
             case 'traditional':
-                $handler = 'SimpleSAML\IdP\TraditionalLogoutHandler';
+                $handler = '\SimpleSAML\IdP\TraditionalLogoutHandler';
                 break;
             case 'iframe':
-                $handler = 'SimpleSAML\IdP\IFrameLogoutHandler';
+                $handler = '\SimpleSAML\IdP\IFrameLogoutHandler';
                 break;
             default:
-                throw new SimpleSAML_Error_Exception('Unknown logout handler: '.var_export($logouttype, true));
+                throw new Exception('Unknown logout handler: '.var_export($logouttype, true));
         }
 
         return new $handler($this);
@@ -454,7 +459,7 @@ class SimpleSAML_IdP
     {
         assert(isset($state['Responder']));
 
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = IdP::getByState($state);
         call_user_func($state['Responder'], $idp, $state);
         assert(false);
     }
@@ -479,13 +484,13 @@ class SimpleSAML_IdP
 
         if ($assocId !== null) {
             $this->terminateAssociation($assocId);
-            $session = SimpleSAML_Session::getSessionFromRequest();
-            $session->deleteData('core:idp-ssotime', $this->id.':'.$state['saml:SPEntityId']);
+            $session = Session::getSessionFromRequest();
+            $session->deleteData('core:idp-ssotime', $this->id.';'.$state['saml:SPEntityId']);
         }
 
         // terminate the local session
-        $id = SimpleSAML_Auth_State::saveState($state, 'core:Logout:afterbridge');
-        $returnTo = SimpleSAML\Module::getModuleURL('core/idp/resumelogout.php', array('id' => $id));
+        $id = Auth\State::saveState($state, 'core:Logout:afterbridge');
+        $returnTo = Module::getModuleURL('core/idp/resumelogout.php', ['id' => $id]);
 
         $this->authSource->logout($returnTo);
 
@@ -500,16 +505,16 @@ class SimpleSAML_IdP
      *
      * This function will never return.
      *
-     * @param string                          $assocId The association that is terminated.
-     * @param string|null                     $relayState The RelayState from the start of the logout.
-     * @param SimpleSAML_Error_Exception|null $error The error that occurred during session termination (if any).
+     * @param string                 $assocId The association that is terminated.
+     * @param string|null            $relayState The RelayState from the start of the logout.
+     * @param Exception|null $error  The error that occurred during session termination (if any).
      */
-    public function handleLogoutResponse($assocId, $relayState, SimpleSAML_Error_Exception $error = null)
+    public function handleLogoutResponse($assocId, $relayState, Exception $error = null)
     {
         assert(is_string($assocId));
         assert(is_string($relayState) || $relayState === null);
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         $session->deleteData('core:idp-ssotime', $this->id.';'.substr($assocId, strpos($assocId, ':') + 1));
 
         $handler = $this->getLogoutHandler();
@@ -530,10 +535,10 @@ class SimpleSAML_IdP
     {
         assert(is_string($url));
 
-        $state = array(
-            'Responder'       => array('SimpleSAML_IdP', 'finishLogoutRedirect'),
+        $state = [
+            'Responder'       => ['\SimpleSAML\IdP', 'finishLogoutRedirect'],
             'core:Logout:URL' => $url,
-        );
+        ];
 
         $this->handleLogoutRequest($state, null);
         assert(false);
@@ -545,14 +550,14 @@ class SimpleSAML_IdP
      *
      * This function never returns.
      *
-     * @param SimpleSAML_IdP $idp Deprecated. Will be removed.
-     * @param array          &$state The logout state from doLogoutRedirect().
+     * @param IdP      $idp Deprecated. Will be removed.
+     * @param array    &$state The logout state from doLogoutRedirect().
      */
-    public static function finishLogoutRedirect(SimpleSAML_IdP $idp, array $state)
+    public static function finishLogoutRedirect(IdP $idp, array $state)
     {
         assert(isset($state['core:Logout:URL']));
 
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($state['core:Logout:URL']);
+        Utils\HTTP::redirectTrustedURL($state['core:Logout:URL']);
         assert(false);
     }
 }
diff --git a/lib/SimpleSAML/IdP/IFrameLogoutHandler.php b/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
index 23a1daa85e8e7f506dd3f67a18ee67ff18f959f4..b2d808cc29363bc5e1f5f37add2264b9ea783f76 100644
--- a/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
+++ b/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
@@ -5,29 +5,27 @@ namespace SimpleSAML\IdP;
 use SimpleSAML\Module;
 use SimpleSAML\Utils\HTTP;
 
-
 /**
  * Class that handles iframe logout.
  *
  * @package SimpleSAMLphp
  */
+
 class IFrameLogoutHandler implements LogoutHandlerInterface
 {
-
     /**
      * The IdP we are logging out from.
      *
-     * @var \SimpleSAML_IdP
+     * @var \SimpleSAML\IdP
      */
     private $idp;
 
-
     /**
      * LogoutIFrame constructor.
      *
-     * @param \SimpleSAML_IdP $idp The IdP to log out from.
+     * @param \SimpleSAML\IdP $idp The IdP to log out from.
      */
-    public function __construct(\SimpleSAML_IdP $idp)
+    public function __construct(\SimpleSAML\IdP $idp)
     {
         $this->idp = $idp;
     }
@@ -49,7 +47,7 @@ class IFrameLogoutHandler implements LogoutHandlerInterface
         }
 
         foreach ($associations as $id => &$association) {
-            $idp = \SimpleSAML_IdP::getByState($association);
+            $idp = \SimpleSAML\IdP::getByState($association);
             $association['core:Logout-IFrame:Name'] = $idp->getSPName($id);
             $association['core:Logout-IFrame:State'] = 'onhold';
         }
@@ -58,7 +56,7 @@ class IFrameLogoutHandler implements LogoutHandlerInterface
         if (!is_null($assocId)) {
             $spName = $this->idp->getSPName($assocId);
             if ($spName === null) {
-                $spName = array('en' => $assocId);
+                $spName = ['en' => $assocId];
             }
 
             $state['core:Logout-IFrame:From'] = $spName;
@@ -66,9 +64,9 @@ class IFrameLogoutHandler implements LogoutHandlerInterface
             $state['core:Logout-IFrame:From'] = null;
         }
 
-        $params = array(
-            'id' => \SimpleSAML_Auth_State::saveState($state, 'core:Logout-IFrame'),
-        );
+        $params = [
+            'id' => \SimpleSAML\Auth\State::saveState($state, 'core:Logout-IFrame'),
+        ];
         if (isset($state['core:Logout-IFrame:InitType'])) {
             $params['type'] = $state['core:Logout-IFrame:InitType'];
         }
@@ -85,36 +83,22 @@ class IFrameLogoutHandler implements LogoutHandlerInterface
      *
      * @param string $assocId The association that is terminated.
      * @param string|null $relayState The RelayState from the start of the logout.
-     * @param \SimpleSAML_Error_Exception|null $error The error that occurred during session termination (if any).
+     * @param \SimpleSAML\Error\Exception|null $error The error that occurred during session termination (if any).
      */
-    public function onResponse($assocId, $relayState, \SimpleSAML_Error_Exception $error = null)
+    public function onResponse($assocId, $relayState, \SimpleSAML\Error\Exception $error = null)
     {
         assert(is_string($assocId));
 
-        $spId = sha1($assocId);
+        $config = \SimpleSAML\Configuration::getInstance();
         $this->idp->terminateAssociation($assocId);
 
-        $header = <<<HEADER
-<!DOCTYPE html>
-<html>
- <head>
-  <title>Logout response from %s</title>
-  <script>
-HEADER;
-        printf($header, htmlspecialchars(var_export($assocId, true)));
-        if ($error) {
-            $errorMsg = $error->getMessage();
-            echo('window.parent.logoutFailed("'.$spId.'", "'.addslashes($errorMsg).'");');
-        } else {
-            echo('window.parent.logoutCompleted("'.$spId.'");');
+        $t = new \SimpleSAML\XHTML\Template($config, 'IFrameLogoutHandler.twig');
+        $t->data['assocId'] = var_export($assocId, true);
+        $t->data['spId'] = sha1($assocId);
+        if (!is_null($error)) {
+            $t->data['errorMsg'] = $error->getMessage();
         }
-        echo <<<FOOTER
-  </script>
- </head>
- <body>
- </body>
-</html>
-FOOTER;
+        $t->show();
         exit(0);
     }
 }
diff --git a/lib/SimpleSAML/IdP/LogoutHandlerInterface.php b/lib/SimpleSAML/IdP/LogoutHandlerInterface.php
index 11589f3d0f56478e114f30b6fbac115fc67a13bb..773bda69470d21ac329985931c57df989e9da1da 100644
--- a/lib/SimpleSAML/IdP/LogoutHandlerInterface.php
+++ b/lib/SimpleSAML/IdP/LogoutHandlerInterface.php
@@ -2,22 +2,20 @@
 
 namespace SimpleSAML\IdP;
 
-
 /**
  * Interface that all logout handlers must implement.
  *
  * @package SimpleSAMLphp
  */
+
 interface LogoutHandlerInterface
 {
-
-
     /**
      * Initialize this logout handler.
      *
-     * @param \SimpleSAML_IdP $idp The IdP we are logging out from.
+     * @param \SimpleSAML\IdP $idp The IdP we are logging out from.
      */
-    public function __construct(\SimpleSAML_IdP $idp);
+    public function __construct(\SimpleSAML\IdP $idp);
 
 
     /**
@@ -38,7 +36,7 @@ interface LogoutHandlerInterface
      *
      * @param string $assocId The association that is terminated.
      * @param string|null $relayState The RelayState from the start of the logout.
-     * @param \SimpleSAML_Error_Exception|null $error The error that occurred during session termination (if any).
+     * @param \SimpleSAML\Error\Exception|null $error The error that occurred during session termination (if any).
      */
-    public function onResponse($assocId, $relayState, \SimpleSAML_Error_Exception $error = null);
+    public function onResponse($assocId, $relayState, \SimpleSAML\Error\Exception $error = null);
 }
diff --git a/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php b/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php
index 61756f32e55e55513b8938c9a68940653533e8d6..32652b5617a747437bc331e86870fbdc5a3a5f81 100644
--- a/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php
+++ b/lib/SimpleSAML/IdP/TraditionalLogoutHandler.php
@@ -5,19 +5,18 @@ namespace SimpleSAML\IdP;
 use SimpleSAML\Logger;
 use SimpleSAML\Utils\HTTP;
 
-
 /**
  * Class that handles traditional logout.
  *
  * @package SimpleSAMLphp
  */
+
 class TraditionalLogoutHandler implements LogoutHandlerInterface
 {
-
     /**
      * The IdP we are logging out from.
      *
-     * @var \SimpleSAML_IdP
+     * @var \SimpleSAML\IdP
      */
     private $idp;
 
@@ -25,9 +24,9 @@ class TraditionalLogoutHandler implements LogoutHandlerInterface
     /**
      * TraditionalLogout constructor.
      *
-     * @param \SimpleSAML_IdP $idp The IdP to log out from.
+     * @param \SimpleSAML\IdP $idp The IdP to log out from.
      */
-    public function __construct(\SimpleSAML_IdP $idp)
+    public function __construct(\SimpleSAML\IdP $idp)
     {
         $this->idp = $idp;
     }
@@ -47,14 +46,14 @@ class TraditionalLogoutHandler implements LogoutHandlerInterface
             $this->idp->finishLogout($state);
         }
 
-        $relayState = \SimpleSAML_Auth_State::saveState($state, 'core:LogoutTraditional', true);
+        $relayState = \SimpleSAML\Auth\State::saveState($state, 'core:LogoutTraditional', true);
 
         $id = $association['id'];
         Logger::info('Logging out of '.var_export($id, true).'.');
 
         try {
-            $idp = \SimpleSAML_IdP::getByState($association);
-            $url = call_user_func(array($association['Handler'], 'getLogoutURL'), $idp, $association, $relayState);
+            $idp = \SimpleSAML\IdP::getByState($association);
+            $url = call_user_func([$association['Handler'], 'getLogoutURL'], $idp, $association, $relayState);
             HTTP::redirectTrustedURL($url);
         } catch (\Exception $e) {
             Logger::warning('Unable to initialize logout to '.var_export($id, true).'.');
@@ -91,20 +90,20 @@ class TraditionalLogoutHandler implements LogoutHandlerInterface
      *
      * @param string $assocId The association that is terminated.
      * @param string|null $relayState The RelayState from the start of the logout.
-     * @param \SimpleSAML_Error_Exception|null $error The error that occurred during session termination (if any).
+     * @param \SimpleSAML\Error\Exception|null $error The error that occurred during session termination (if any).
      *
-     * @throws \SimpleSAML_Error_Exception If the RelayState was lost during logout.
+     * @throws \SimpleSAML\Error\Exception If the RelayState was lost during logout.
      */
-    public function onResponse($assocId, $relayState, \SimpleSAML_Error_Exception $error = null)
+    public function onResponse($assocId, $relayState, \SimpleSAML\Error\Exception $error = null)
     {
         assert(is_string($assocId));
         assert(is_string($relayState) || $relayState === null);
 
         if ($relayState === null) {
-            throw new \SimpleSAML_Error_Exception('RelayState lost during logout.');
+            throw new \SimpleSAML\Error\Exception('RelayState lost during logout.');
         }
 
-        $state = \SimpleSAML_Auth_State::loadState($relayState, 'core:LogoutTraditional');
+        $state = \SimpleSAML\Auth\State::loadState($relayState, 'core:LogoutTraditional');
 
         if ($error === null) {
             Logger::info('Logged out of '.var_export($assocId, true).'.');
diff --git a/lib/SimpleSAML/Locale/Language.php b/lib/SimpleSAML/Locale/Language.php
index 9e5696cec3a93b8290b36fbca28120c98e912d85..21dc94b7cf6a0f43539d147846bd45f6e8d2557a 100644
--- a/lib/SimpleSAML/Locale/Language.php
+++ b/lib/SimpleSAML/Locale/Language.php
@@ -18,12 +18,12 @@ class Language
     /**
      * This is the default language map. It is used to map languages codes from the user agent to other language codes.
      */
-    private static $defaultLanguageMap = array('nb' => 'no');
+    private static $defaultLanguageMap = ['nb' => 'no'];
 
     /**
      * The configuration to use.
      *
-     * @var \SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $configuration;
 
@@ -77,7 +77,7 @@ class Language
      *
      * @var array
      */
-    private $language_names = array(
+    private $language_names = [
         'no'    => 'BokmĂĄl', // Norwegian BokmĂĄl
         'nn'    => 'Nynorsk', // Norwegian Nynorsk
         'se'    => 'Sámegiella', // Northern Sami
@@ -88,6 +88,7 @@ class Language
         'sv'    => 'Svenska', // Swedish
         'fi'    => 'Suomeksi', // Finnish
         'es'    => 'Español', // Spanish
+        'ca'    => 'CatalĂ ', // Catalan
         'fr'    => 'Français', // French
         'it'    => 'Italiano', // Italian
         'nl'    => 'Nederlands', // Dutch
@@ -117,32 +118,32 @@ class Language
         'ro'    => 'Românește', // Romanian
         'eu'    => 'Euskara', // Basque
         'af'    => 'Afrikaans', // Afrikaans
-    );
+    ];
 
     /**
      * A mapping of SSP languages to locales
      *
      * @var array
      */
-    private $languagePosixMapping = array(
+    private $languagePosixMapping = [
         'no' => 'nb_NO',
         'nn' => 'nn_NO',
-    );
+    ];
 
 
     /**
      * Constructor
      *
-     * @param \SimpleSAML_Configuration $configuration Configuration object
+     * @param \SimpleSAML\Configuration $configuration Configuration object
      */
-    public function __construct(\SimpleSAML_Configuration $configuration)
+    public function __construct(\SimpleSAML\Configuration $configuration)
     {
         $this->configuration = $configuration;
         $this->availableLanguages = $this->getInstalledLanguages();
         $this->defaultLanguage = $this->configuration->getString('language.default', 'en');
         $this->languageParameterName = $this->configuration->getString('language.parameter.name', 'language');
         $this->customFunction = $this->configuration->getArray('language.get_language_function', null);
-        $this->rtlLanguages = $this->configuration->getArray('language.rtl', array());
+        $this->rtlLanguages = $this->configuration->getArray('language.rtl', []);
         if (isset($_GET[$this->languageParameterName])) {
             $this->setLanguage(
                 $_GET[$this->languageParameterName],
@@ -159,8 +160,8 @@ class Language
      */
     private function getInstalledLanguages()
     {
-        $configuredAvailableLanguages = $this->configuration->getArray('language.available', array('en'));
-        $availableLanguages = array();
+        $configuredAvailableLanguages = $this->configuration->getArray('language.available', ['en']);
+        $availableLanguages = [];
         foreach ($configuredAvailableLanguages as $code) {
             if (array_key_exists($code, $this->language_names) && isset($this->language_names[$code])) {
                 $availableLanguages[] = $code;
@@ -230,7 +231,7 @@ class Language
         }
 
         // language is provided in a stored cookie
-        $languageCookie = Language::getLanguageCookie();
+        $languageCookie = self::getLanguageCookie();
         if ($languageCookie !== null) {
             $this->language = $languageCookie;
             return $languageCookie;
@@ -376,8 +377,8 @@ class Language
      */
     public static function getLanguageCookie()
     {
-        $config = \SimpleSAML_Configuration::getInstance();
-        $availableLanguages = $config->getArray('language.available', array('en'));
+        $config = \SimpleSAML\Configuration::getInstance();
+        $availableLanguages = $config->getArray('language.available', ['en']);
         $name = $config->getString('language.cookie.name', 'language');
 
         if (isset($_COOKIE[$name])) {
@@ -402,21 +403,21 @@ class Language
         assert(is_string($language));
 
         $language = strtolower($language);
-        $config = \SimpleSAML_Configuration::getInstance();
-        $availableLanguages = $config->getArray('language.available', array('en'));
+        $config = \SimpleSAML\Configuration::getInstance();
+        $availableLanguages = $config->getArray('language.available', ['en']);
 
         if (!in_array($language, $availableLanguages, true) || headers_sent()) {
             return;
         }
 
         $name = $config->getString('language.cookie.name', 'language');
-        $params = array(
+        $params = [
             'lifetime' => ($config->getInteger('language.cookie.lifetime', 60 * 60 * 24 * 900)),
             'domain'   => ($config->getString('language.cookie.domain', null)),
             'path'     => ($config->getString('language.cookie.path', '/')),
             'secure'   => ($config->getBoolean('language.cookie.secure', false)),
             'httponly' => ($config->getBoolean('language.cookie.httponly', false)),
-        );
+        ];
 
         HTTP::setCookie($name, $language, $params, false);
     }
diff --git a/lib/SimpleSAML/Locale/Localization.php b/lib/SimpleSAML/Locale/Localization.php
index cbfc42c304b4dddd03e79622f88e0f2a6f4b538d..9a4543d37ae95fc21553d8653eaf39867440179d 100644
--- a/lib/SimpleSAML/Locale/Localization.php
+++ b/lib/SimpleSAML/Locale/Localization.php
@@ -17,62 +17,80 @@ class Localization
     /**
      * The configuration to use.
      *
-     * @var \SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $configuration;
 
     /**
      * The default gettext domain.
+     *
+     * @var string
      */
     const DEFAULT_DOMAIN = 'messages';
 
     /**
      * Old internationalization backend included in SimpleSAMLphp.
+     *
+     * @var string
      */
     const SSP_I18N_BACKEND = 'SimpleSAMLphp';
 
     /**
      * An internationalization backend implemented purely in PHP.
+     *
+     * @var string
      */
     const GETTEXT_I18N_BACKEND = 'gettext/gettext';
 
     /**
      * The default locale directory
+     *
+     * @var string
      */
     private $localeDir;
 
     /**
      * Where specific domains are stored
+     *
+     * @var array
      */
-    private $localeDomainMap = array();
+    private $localeDomainMap = [];
 
     /**
      * Pointer to currently active translator
+     *
+     * @var \Gettext\Translator
      */
     private $translator;
 
     /**
      * Pointer to current Language
+     *
+     * @var Language
      */
     private $language;
 
     /**
      * Language code representing the current Language
+     *
+     * @var string
      */
     private $langcode;
 
 
     /**
      * The language backend to use
+     *
+     * @var string
      */
     public $i18nBackend;
 
     /**
      * Constructor
      *
-     * @param \SimpleSAML_Configuration $configuration Configuration object
+     * @param \SimpleSAML\Configuration $configuration Configuration object
      */
-    public function __construct(\SimpleSAML_Configuration $configuration)
+    public function __construct(\SimpleSAML\Configuration $configuration)
     {
         $this->configuration = $configuration;
         $this->localeDir = $this->configuration->resolvePath('locales');
@@ -85,6 +103,8 @@ class Localization
 
     /**
      * Dump the default locale directory
+     *
+     * @return string
      */
     public function getLocaleDir()
     {
@@ -96,10 +116,12 @@ class Localization
      * Get the default locale dir for a specific module aka. domain
      *
      * @param string $domain Name of module/domain
+     *
+     * @return string
      */
     public function getDomainLocaleDir($domain)
     {
-        $localeDir = $this->configuration->resolvePath('modules') . '/' . $domain . '/locales';
+        $localeDir = $this->configuration->resolvePath('modules').'/'.$domain.'/locales';
         return $localeDir;
     }
 
@@ -139,6 +161,8 @@ class Localization
      *
      * @param string $domain Name of localization domain
      * @throws Exception If the path does not exist even for the default, fallback language
+     *
+     * @return string
      */
     public function getLangPath($domain = self::DEFAULT_DOMAIN)
     {
@@ -167,7 +191,7 @@ class Localization
         if (is_dir($langPath) && is_readable($langPath)) {
             // Report that the localization for the preferred language is missing
             $error = "Localization not found for langcode '$langcode' at '$langPath', falling back to langcode '".
-                     $defLangcode."'";
+                $defLangcode."'";
             \SimpleSAML\Logger::error($_SERVER['PHP_SELF'].' - '.$error);
             return $langPath;
         }
@@ -230,6 +254,8 @@ class Localization
      * Test to check if backend is set to default
      *
      * (if false: backend unset/there's an error)
+     *
+     * @return bool
      */
     public function isI18NBackendDefault()
     {
@@ -257,10 +283,11 @@ class Localization
 
     /**
      * Show which domains are registered
+     *
+     * @return array
      */
     public function getRegisteredDomains()
     {
         return $this->localeDomainMap;
     }
-
 }
diff --git a/lib/SimpleSAML/Locale/Translate.php b/lib/SimpleSAML/Locale/Translate.php
index 9cb0000bd8ebe9835a5ff2985e163a46aed44c5a..2b577fdc56a326a11ac249ed2c510c45672d2b64 100644
--- a/lib/SimpleSAML/Locale/Translate.php
+++ b/lib/SimpleSAML/Locale/Translate.php
@@ -12,23 +12,31 @@ namespace SimpleSAML\Locale;
 
 class Translate
 {
-
     /**
      * The configuration to be used for this translator.
      *
-     * @var \SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $configuration;
 
-    private $langtext = array();
+    /**
+     * Associative array of languages.
+     *
+     * @var array
+     */
+    private $langtext = [];
 
     /**
      * Associative array of dictionaries.
+     *
+     * @var array
      */
-    private $dictionaries = array();
+    private $dictionaries = [];
 
     /**
      * The default dictionary.
+     *
+     * @var string|null
      */
     private $defaultDictionary = null;
 
@@ -39,14 +47,13 @@ class Translate
      */
     private $language;
 
-
     /**
      * Constructor
      *
-     * @param \SimpleSAML_Configuration $configuration Configuration object
+     * @param \SimpleSAML\Configuration $configuration Configuration object
      * @param string|null               $defaultDictionary The default dictionary where tags will come from.
      */
-    public function __construct(\SimpleSAML_Configuration $configuration, $defaultDictionary = null)
+    public function __construct(\SimpleSAML\Configuration $configuration, $defaultDictionary = null)
     {
         $this->configuration = $configuration;
         $this->language = new Language($configuration);
@@ -67,7 +74,6 @@ class Translate
         }
     }
 
-
     /**
      * Return the internal language object used by this translator.
      *
@@ -78,7 +84,6 @@ class Translate
         return $this->language;
     }
 
-
     /**
      * This method retrieves a dictionary with the name given.
      *
@@ -108,7 +113,6 @@ class Translate
         return $this->dictionaries[$name];
     }
 
-
     /**
      * This method retrieves a tag as an array with language => string mappings.
      *
@@ -146,7 +150,6 @@ class Translate
         return $dictionary[$tag];
     }
 
-
     /**
      * Retrieve the preferred translation of a given text.
      *
@@ -187,7 +190,6 @@ class Translate
         throw new \Exception('Nothing to return from translation.');
     }
 
-
     /**
      * Translate the name of an attribute.
      *
@@ -199,7 +201,7 @@ class Translate
     {
         // normalize attribute name
         $normName = strtolower($name);
-        $normName = str_replace(":", "_", $normName);
+        $normName = str_replace([":", "-"], "_", $normName);
 
         // check for an extra dictionary
         $extraDict = $this->configuration->getString('attributes.extradictionary', null);
@@ -220,7 +222,6 @@ class Translate
         return $name;
     }
 
-
     /**
      * Mark a string for translation without translating it.
      *
@@ -233,7 +234,6 @@ class Translate
         return $tag;
     }
 
-
     /**
      * Translate a tag into the current language, with a fallback to english.
      *
@@ -258,17 +258,20 @@ class Translate
      */
     public function t(
         $tag,
-        $replacements = array(),
-        $fallbackdefault = true, // TODO: remove this for 2.0. Assume true
-        $oldreplacements = array(), // TODO: remove this for 2.0
-        $striptags = false // TODO: remove this for 2.0
+        $replacements = [],
+        // TODO: remove this for 2.0. Assume true
+        $fallbackdefault = true,
+        // TODO: remove this for 2.0
+        $oldreplacements = [],
+        // TODO: remove this for 2.0
+        $striptags = false
     ) {
         $backtrace = debug_backtrace();
         $where = $backtrace[0]['file'].':'.$backtrace[0]['line'];
         if (!$fallbackdefault) {
             \SimpleSAML\Logger::warning(
                 'Deprecated use of new SimpleSAML\Locale\Translate::t(...) at '.$where.
-                '. This parameter will go away, the fallback will become' .
+                '. This parameter will go away, the fallback will become'.
                 ' identical to the $tag in 2.0.'
             );
         }
@@ -319,7 +322,6 @@ class Translate
         return $translated;
     }
 
-
     /**
      * Return the string that should be used when no translation was found.
      *
@@ -338,10 +340,9 @@ class Translate
         }
     }
 
-
     /**
      * Include a translation inline instead of putting translations in dictionaries. This function is recommended to be
-     * used ONLU from variable data, or when the translation is already provided by an external source, as a database
+     * used ONLY for variable data, or when the translation is already provided by an external source, as a database
      * or in metadata.
      *
      * @param string       $tag The tag that has a translation
@@ -352,7 +353,7 @@ class Translate
     public function includeInlineTranslation($tag, $translation)
     {
         if (is_string($translation)) {
-            $translation = array('en' => $translation);
+            $translation = ['en' => $translation];
         } elseif (!is_array($translation)) {
             throw new \Exception("Inline translation should be string or array. Is ".gettype($translation)." now!");
         }
@@ -361,12 +362,11 @@ class Translate
         $this->langtext[$tag] = $translation;
     }
 
-
     /**
      * Include a language file from the dictionaries directory.
      *
      * @param string                         $file File name of dictionary to include
-     * @param \SimpleSAML_Configuration|null $otherConfig Optionally provide a different configuration object than the
+     * @param \SimpleSAML\Configuration|null $otherConfig Optionally provide a different configuration object than the
      * one provided in the constructor to be used to find the directory of the dictionary. This allows to combine
      * dictionaries inside the SimpleSAMLphp main code distribution together with external dictionaries. Defaults to
      * null.
@@ -384,7 +384,6 @@ class Translate
         $this->langtext = array_merge($this->langtext, $lang);
     }
 
-
     /**
      * Read a dictionary file in JSON format.
      *
@@ -402,7 +401,7 @@ class Translate
 
         if (empty($lang)) {
             \SimpleSAML\Logger::error('Invalid dictionary definition file ['.$definitionFile.']');
-            return array();
+            return [];
         }
 
         $translationFile = $filename.'.translation.json';
@@ -417,7 +416,6 @@ class Translate
         return $lang;
     }
 
-
     /**
      * Read a dictionary file in PHP format.
      *
@@ -436,10 +434,9 @@ class Translate
             return $lang;
         }
 
-        return array();
+        return [];
     }
 
-
     /**
      * Read a dictionary file.
      *
@@ -466,10 +463,16 @@ class Translate
         \SimpleSAML\Logger::error(
             $_SERVER['PHP_SELF'].' - Template: Could not find dictionary file at ['.$filename.']'
         );
-        return array();
+        return [];
     }
 
-
+    /**
+     * Translate a singular text.
+     *
+     * @param string $original The string before translation.
+     *
+     * @return string The translated string.
+     */
     public static function translateSingularGettext($original)
     {
         $text = \Gettext\BaseTranslator::$current->gettext($original);
@@ -483,7 +486,15 @@ class Translate
         return strtr($text, is_array($args[0]) ? $args[0] : $args);
     }
 
-
+    /**
+     * Translate a plural text.
+     *
+     * @param string $original The string before translation.
+     * @param string $plural
+     * @param string $value
+     *
+     * @return string The translated string.
+     */
     public static function translatePluralGettext($original, $plural, $value)
     {
         $text = \Gettext\BaseTranslator::$current->ngettext($original, $plural, $value);
@@ -497,7 +508,6 @@ class Translate
         return strtr($text, is_array($args[0]) ? $args[0] : $args);
     }
 
-
     /**
      * Pick a translation from a given array of translations for the current language.
      *
@@ -524,16 +534,18 @@ class Translate
         }
 
         // we don't have a translation for the current language, load alternative priorities
-        $sspcfg = \SimpleSAML_Configuration::getInstance();
+        $sspcfg = \SimpleSAML\Configuration::getInstance();
         $langcfg = $sspcfg->getConfigItem('language', null);
-        $priorities = array();
-        if ($langcfg instanceof \SimpleSAML_Configuration) {
-            $priorities = $langcfg->getArray('priorities', array());
+        $priorities = [];
+        if ($langcfg instanceof \SimpleSAML\Configuration) {
+            $priorities = $langcfg->getArray('priorities', []);
         }
 
-        foreach ($priorities[$context['currentLanguage']] as $lang) {
-            if (isset($translations[$lang])) {
-                return $translations[$lang];
+        if (!empty($priorities[$context['currentLanguage']])) {
+            foreach ($priorities[$context['currentLanguage']] as $lang) {
+                if (isset($translations[$lang])) {
+                    return $translations[$lang];
+                }
             }
         }
 
diff --git a/lib/SimpleSAML/Logger.php b/lib/SimpleSAML/Logger.php
index a383addbd76782bde5972fc6c32ed9895d2bdd3f..c18276ec04a58f081e16054c4b23ceca44090c1e 100644
--- a/lib/SimpleSAML/Logger.php
+++ b/lib/SimpleSAML/Logger.php
@@ -2,7 +2,6 @@
 
 namespace SimpleSAML;
 
-
 /**
  * The main logger class for SimpleSAMLphp.
  *
@@ -10,11 +9,9 @@ namespace SimpleSAML;
  * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no>
  * @package SimpleSAMLphp
- * @version $ID$
  */
 class Logger
 {
-
     /**
      * @var \SimpleSAML\Logger\LoggingHandlerInterface|false|null
      */
@@ -33,14 +30,14 @@ class Logger
     /**
      * @var array
      */
-    private static $capturedLog = array();
+    private static $capturedLog = [];
 
     /**
      * Array with messages logged before the logging handler was initialized.
      *
      * @var array
      */
-    private static $earlyLog = array();
+    private static $earlyLog = [];
 
     /**
      * List of log levels.
@@ -49,7 +46,7 @@ class Logger
      *
      * @var array
      */
-    private static $logLevelStack = array();
+    private static $logLevelStack = [];
 
     /**
      * The current mask of log levels disabled.
@@ -268,11 +265,11 @@ class Logger
     public static function flush()
     {
         try {
-            $s = \SimpleSAML_Session::getSessionFromRequest();
+            $s = Session::getSessionFromRequest();
         } catch (\Exception $e) {
             // loading session failed. We don't care why, at this point we have a transient session, so we use that
             self::error('Cannot load or create session: '.$e->getMessage());
-            $s = \SimpleSAML_Session::getSessionFromRequest();
+            $s = Session::getSessionFromRequest();
         }
         self::$trackid = $s->getTrackID();
 
@@ -308,7 +305,7 @@ class Logger
         assert(is_int($mask));
 
         $currentEnabled = error_reporting();
-        self::$logLevelStack[] = array($currentEnabled, self::$logMask);
+        self::$logLevelStack[] = [$currentEnabled, self::$logMask];
 
         $currentEnabled &= ~$mask;
         error_reporting($currentEnabled);
@@ -339,11 +336,11 @@ class Logger
     private static function defer($level, $message, $stats)
     {
         // save the message for later
-        self::$earlyLog[] = array('level' => $level, 'string' => $message, 'statsLog' => $stats);
+        self::$earlyLog[] = ['level' => $level, 'string' => $message, 'statsLog' => $stats];
 
         // register a shutdown handler if needed
         if (!self::$shutdownRegistered) {
-            register_shutdown_function(array('SimpleSAML\Logger', 'flush'));
+            register_shutdown_function(['SimpleSAML\Logger', 'flush']);
             self::$shutdownRegistered = true;
         }
     }
@@ -355,15 +352,15 @@ class Logger
         self::$loggingHandler = false;
 
         // a set of known logging handlers
-        $known_handlers = array(
+        $known_handlers = [
             'syslog'   => 'SimpleSAML\Logger\SyslogLoggingHandler',
             'file'     => 'SimpleSAML\Logger\FileLoggingHandler',
             'errorlog' => 'SimpleSAML\Logger\ErrorLogLoggingHandler',
-        );
+        ];
 
         // get the configuration
-        $config = \SimpleSAML_Configuration::getInstance();
-        assert($config instanceof \SimpleSAML_Configuration);
+        $config = Configuration::getInstance();
+        assert($config instanceof Configuration);
 
         // setting minimum log_level
         self::$logLevel = $config->getInteger('logging.level', self::INFO);
@@ -432,8 +429,8 @@ class Logger
                 $string = implode(",", $string);
             }
 
-            $formats = array('%trackid', '%msg', '%srcip', '%stat');
-            $replacements = array(self::$trackid, $string, $_SERVER['REMOTE_ADDR']);
+            $formats = ['%trackid', '%msg', '%srcip', '%stat'];
+            $replacements = [self::$trackid, $string, $_SERVER['REMOTE_ADDR']];
 
             $stat = '';
             if ($statsLog) {
diff --git a/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php b/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
index 845103cf2dc4c0f6108d81331c85e684ecc3aaf1..355fe24d1d262b0cefbf1c36b35a692701b107bc 100644
--- a/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/ErrorLogLoggingHandler.php
@@ -14,11 +14,10 @@ use SimpleSAML\Logger;
  */
 class ErrorLogLoggingHandler implements LoggingHandlerInterface
 {
-
     /**
      * This array contains the mappings from syslog log level to names.
      */
-    private static $levelNames = array(
+    private static $levelNames = [
         Logger::EMERG   => 'EMERG',
         Logger::ALERT   => 'ALERT',
         Logger::CRIT    => 'CRIT',
@@ -27,7 +26,7 @@ class ErrorLogLoggingHandler implements LoggingHandlerInterface
         Logger::NOTICE  => 'NOTICE',
         Logger::INFO    => 'INFO',
         Logger::DEBUG   => 'DEBUG',
-    );
+    ];
 
     /**
      * The name of this process.
@@ -40,9 +39,9 @@ class ErrorLogLoggingHandler implements LoggingHandlerInterface
     /**
      * ErrorLogLoggingHandler constructor.
      *
-     * @param \SimpleSAML_Configuration $config The configuration object for this handler.
+     * @param \SimpleSAML\Configuration $config The configuration object for this handler.
      */
-    public function __construct(\SimpleSAML_Configuration $config)
+    public function __construct(\SimpleSAML\Configuration $config)
     {
         $this->processname = $config->getString('logging.processname', 'SimpleSAMLphp');
     }
@@ -73,8 +72,8 @@ class ErrorLogLoggingHandler implements LoggingHandlerInterface
             $levelName = sprintf('UNKNOWN%d', $level);
         }
 
-        $formats = array('%process', '%level');
-        $replacements = array($this->processname, $levelName);
+        $formats = ['%process', '%level'];
+        $replacements = [$this->processname, $levelName];
         $string = str_replace($formats, $replacements, $string);
         $string = preg_replace('/%\w+(\{[^\}]+\})?/', '', $string);
         $string = trim($string);
diff --git a/lib/SimpleSAML/Logger/FileLoggingHandler.php b/lib/SimpleSAML/Logger/FileLoggingHandler.php
index 475541f1bfdd60bcbfa699dbe6d3305b28d0f2a0..8e9202f55d6b289c52c1129dcbb9c9fda008a97d 100644
--- a/lib/SimpleSAML/Logger/FileLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/FileLoggingHandler.php
@@ -25,7 +25,7 @@ class FileLoggingHandler implements LoggingHandlerInterface
      * This array contains the mappings from syslog log levels to names. Copied more or less directly from
      * SimpleSAML\Logger\ErrorLogLoggingHandler.
      */
-    private static $levelNames = array(
+    private static $levelNames = [
         Logger::EMERG   => 'EMERGENCY',
         Logger::ALERT   => 'ALERT',
         Logger::CRIT    => 'CRITICAL',
@@ -34,7 +34,7 @@ class FileLoggingHandler implements LoggingHandlerInterface
         Logger::NOTICE  => 'NOTICE',
         Logger::INFO    => 'INFO',
         Logger::DEBUG   => 'DEBUG',
-    );
+    ];
     protected $processname = null;
     protected $format;
 
@@ -42,7 +42,7 @@ class FileLoggingHandler implements LoggingHandlerInterface
     /**
      * Build a new logging handler based on files.
      */
-    public function __construct(\SimpleSAML_Configuration $config)
+    public function __construct(\SimpleSAML\Configuration $config)
     {
         // get the metadata handler option from the configuration
         $this->logFile = $config->getPathValue('loggingdir', 'log/').
@@ -92,10 +92,10 @@ class FileLoggingHandler implements LoggingHandlerInterface
                 $levelName = self::$levelNames[$level];
             }
 
-            $formats = array('%process', '%level');
-            $replacements = array($this->processname, $levelName);
+            $formats = ['%process', '%level'];
+            $replacements = [$this->processname, $levelName];
 
-            $matches = array();
+            $matches = [];
             if (preg_match('/%date(?:\{([^\}]+)\})?/', $this->format, $matches)) {
                 $format = "%b %d %H:%M:%S";
                 if (isset($matches[1])) {
@@ -107,7 +107,7 @@ class FileLoggingHandler implements LoggingHandlerInterface
             }
 
             $string = str_replace($formats, $replacements, $string);
-            file_put_contents($this->logFile, $string.PHP_EOL, FILE_APPEND);
+            file_put_contents($this->logFile, $string.\PHP_EOL, FILE_APPEND);
         }
     }
 }
diff --git a/lib/SimpleSAML/Logger/LoggingHandlerInterface.php b/lib/SimpleSAML/Logger/LoggingHandlerInterface.php
index c7b00eb01a125423972f195eeff8530471b80496..a9b939ddd0b7b2c6356766faa8634d8ec8164a2e 100644
--- a/lib/SimpleSAML/Logger/LoggingHandlerInterface.php
+++ b/lib/SimpleSAML/Logger/LoggingHandlerInterface.php
@@ -13,11 +13,11 @@ interface LoggingHandlerInterface
 {
 
     /**
-     * Constructor for log handlers. It must accept receiving a \SimpleSAML_Configuration object.
+     * Constructor for log handlers. It must accept receiving a \SimpleSAML\Configuration object.
      *
-     * @param \SimpleSAML_Configuration $config The configuration to use in this log handler.
+     * @param \SimpleSAML\Configuration $config The configuration to use in this log handler.
      */
-    public function __construct(\SimpleSAML_Configuration $config);
+    public function __construct(\SimpleSAML\Configuration $config);
 
 
     /**
diff --git a/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php b/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
index 0f35fcf54be79b4ceae982a94cc26b8e44aeec3a..3413e68cea3f4cb0e965c32e9ac899a8126aad57 100644
--- a/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/StandardErrorLoggingHandler.php
@@ -16,7 +16,7 @@ class StandardErrorLoggingHandler extends FileLoggingHandler
      *
      * It runs the parent constructor and sets the log file to be the standard error descriptor.
      */
-    public function __construct(\SimpleSAML_Configuration $config)
+    public function __construct(\SimpleSAML\Configuration $config)
     {
         $this->processname = $config->getString('logging.processname', 'SimpleSAMLphp');
         $this->logFile = 'php://stderr';
diff --git a/lib/SimpleSAML/Logger/SyslogLoggingHandler.php b/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
index ce2739798e3d1b74da2dabed99046be18cb37eb3..8d6e21a396fa899d3bd095adba6bece993fef95d 100644
--- a/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
+++ b/lib/SimpleSAML/Logger/SyslogLoggingHandler.php
@@ -20,7 +20,7 @@ class SyslogLoggingHandler implements LoggingHandlerInterface
     /**
      * Build a new logging handler based on syslog.
      */
-    public function __construct(\SimpleSAML_Configuration $config)
+    public function __construct(\SimpleSAML\Configuration $config)
     {
         $facility = $config->getInteger('logging.facility', defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER);
 
@@ -64,8 +64,8 @@ class SyslogLoggingHandler implements LoggingHandlerInterface
             }
         }
 
-        $formats = array('%process', '%level');
-        $replacements = array('', $level);
+        $formats = ['%process', '%level'];
+        $replacements = ['', $level];
         $string = str_replace($formats, $replacements, $string);
         $string = preg_replace('/%\w+(\{[^\}]+\})?/', '', $string);
         $string = trim($string);
diff --git a/lib/SimpleSAML/Memcache.php b/lib/SimpleSAML/Memcache.php
index 3d895755e78fd67ee18746cee4dbfa04d4698267..227022c201de7e5c42803353c83d12eb5e7f71e8 100644
--- a/lib/SimpleSAML/Memcache.php
+++ b/lib/SimpleSAML/Memcache.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML;
 
 /**
  * This file implements functions to read and write to a group of memcache
@@ -17,22 +18,22 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Memcache
-{
 
+class Memcache
+{
     /**
      * Cache of the memcache servers we are using.
      *
-     * @var Memcache[]|null
+     * @var \Memcache[]|null
      */
     private static $serverGroups = null;
 
 
-  /**
-   * The flavor of memcache PHP extension we are using.
-   *
-   * @var string
-   */
+    /**
+     * The flavor of memcache PHP extension we are using.
+     *
+     * @var string
+     */
     private static $extension = '';
 
 
@@ -45,7 +46,7 @@ class SimpleSAML_Memcache
      */
     public static function get($key)
     {
-        SimpleSAML\Logger::debug("loading key $key from memcache");
+        Logger::debug("loading key $key from memcache");
 
         $latestInfo = null;
         $latestTime = 0.0;
@@ -59,7 +60,7 @@ class SimpleSAML_Memcache
             if ($serializedInfo === false) {
                 // either the server is down, or we don't have the value stored on that server
                 $mustUpdate = true;
-                $up = $server->getstats();
+                $up = $server->getStats();
                 if ($up !== false) {
                     $allDown = false;
                 }
@@ -76,19 +77,19 @@ class SimpleSAML_Memcache
              * - 'data': The data.
              */
             if (!is_array($info)) {
-                SimpleSAML\Logger::warning(
+                Logger::warning(
                     'Retrieved invalid data from a memcache server. Data was not an array.'
                 );
                 continue;
             }
             if (!array_key_exists('timestamp', $info)) {
-                SimpleSAML\Logger::warning(
+                Logger::warning(
                     'Retrieved invalid data from a memcache server. Missing timestamp.'
                 );
                 continue;
             }
             if (!array_key_exists('data', $info)) {
-                SimpleSAML\Logger::warning(
+                Logger::warning(
                     'Retrieved invalid data from a memcache server. Missing data.'
                 );
                 continue;
@@ -121,17 +122,17 @@ class SimpleSAML_Memcache
         if ($latestData === null) {
             if ($allDown) {
                 // all servers are down, panic!
-                $e = new SimpleSAML_Error_Error('MEMCACHEDOWN', null, 503);
-                throw new SimpleSAML_Error_Exception('All memcache servers are down', 503, $e);
+                $e = new Error\Error('MEMCACHEDOWN', null, 503);
+                throw new Error\Exception('All memcache servers are down', 503, $e);
             }
             // we didn't find any data matching the key
-            SimpleSAML\Logger::debug("key $key not found in memcache");
+            Logger::debug("key $key not found in memcache");
             return null;
         }
 
         if ($mustUpdate) {
             // we found data matching the key, but some of the servers need updating
-            SimpleSAML\Logger::debug("Memcache servers out of sync for $key, forcing sync");
+            Logger::debug("Memcache servers out of sync for $key, forcing sync");
             self::set($key, $latestData);
         }
 
@@ -148,11 +149,11 @@ class SimpleSAML_Memcache
      */
     public static function set($key, $value, $expire = null)
     {
-        SimpleSAML\Logger::debug("saving key $key to memcache");
-        $savedInfo = array(
+        Logger::debug("saving key $key to memcache");
+        $savedInfo = [
             'timestamp' => microtime(true),
             'data'      => $value
-        );
+        ];
 
         if ($expire === null) {
             $expire = self::getExpireTime();
@@ -162,10 +163,9 @@ class SimpleSAML_Memcache
 
         // store this object to all groups of memcache servers
         foreach (self::getMemcacheServers() as $server) {
-            if (self::$extension === 'memcached') {
+            if (self::$extension === '\memcached') {
                 $server->set($key, $savedInfoSerialized, $expire);
-            }
-            else {
+            } else {
                 $server->set($key, $savedInfoSerialized, 0, $expire);
             }
         }
@@ -180,7 +180,7 @@ class SimpleSAML_Memcache
     public static function delete($key)
     {
         assert(is_string($key));
-        SimpleSAML\Logger::debug("deleting key $key from memcache");
+        Logger::debug("deleting key $key from memcache");
 
         // store this object to all groups of memcache servers
         foreach (self::getMemcacheServers() as $server) {
@@ -207,16 +207,16 @@ class SimpleSAML_Memcache
      *    The timeout for contacting this server, in seconds.
      *    The default value is 3 seconds.
      *
-     * @param Memcache $memcache The Memcache object we should add this server to.
+     * @param \Memcache $memcache The Memcache object we should add this server to.
      * @param array    $server An associative array with the configuration options for the server to add.
      *
-     * @throws Exception If any configuration option for the server is invalid.
+     * @throws \Exception If any configuration option for the server is invalid.
      */
     private static function addMemcacheServer($memcache, $server)
     {
         // the hostname option is required
         if (!array_key_exists('hostname', $server)) {
-            throw new Exception(
+            throw new \Exception(
                 "hostname setting missing from server in the 'memcache_store.servers' configuration option."
             );
         }
@@ -225,27 +225,21 @@ class SimpleSAML_Memcache
 
         // the hostname must be a valid string
         if (!is_string($hostname)) {
-            throw new Exception(
+            throw new \Exception(
                 "Invalid hostname for server in the 'memcache_store.servers' configuration option. The hostname is".
                 ' supposed to be a string.'
             );
         }
 
-        // check if we are told to use a socket
-        $socket = false;
-        if (strpos($hostname, 'unix:///') === 0) {
-            $socket = true;
-        }
-
         // check if the user has specified a port number
-        if ($socket) {
+        if (strpos($hostname, 'unix:///') === 0) {
             // force port to be 0 for sockets
             $port = 0;
         } elseif (array_key_exists('port', $server)) {
             // get the port number from the array, and validate it
             $port = (int) $server['port'];
             if (($port <= 0) || ($port > 65535)) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid port for server in the 'memcache_store.servers' configuration option. The port number".
                     ' is supposed to be an integer between 0 and 65535.'
                 );
@@ -264,7 +258,7 @@ class SimpleSAML_Memcache
             // get the weight and validate it
             $weight = (int) $server['weight'];
             if ($weight <= 0) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid weight for server in the 'memcache_store.servers' configuration option. The weight is".
                     ' supposed to be a positive integer.'
                 );
@@ -279,7 +273,7 @@ class SimpleSAML_Memcache
             // get the timeout and validate it
             $timeout = (int) $server['timeout'];
             if ($timeout <= 0) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid timeout for server in the 'memcache_store.servers' configuration option. The timeout is".
                     ' supposed to be a positive integer.'
                 );
@@ -290,7 +284,7 @@ class SimpleSAML_Memcache
         }
 
         // add this server to the Memcache object
-        if (self::$extension === 'memcached') {
+        if (self::$extension === '\memcached') {
             $memcache->addServer($hostname, $port);
         } else {
             $memcache->addServer($hostname, $port, true, $weight, $timeout, $timeout, true);
@@ -304,26 +298,28 @@ class SimpleSAML_Memcache
      *
      * @param array $group Array of servers which should be created as a group.
      *
-     * @return Memcache A Memcache object of the servers in the group
+     * @return \Memcache A Memcache object of the servers in the group
      *
-     * @throws Exception If the servers configuration is invalid.
+     * @throws \Exception If the servers configuration is invalid.
      */
     private static function loadMemcacheServerGroup(array $group)
     {
-        $class = class_exists('Memcache') ? 'Memcache' : (class_exists('Memcached') ? 'Memcached' : FALSE);
+        $class = class_exists('\Memcache') ? '\Memcache' : (class_exists('\Memcached') ? '\Memcached' : false);
         if (!$class) {
-            throw new Exception('Missing Memcached implementation. You must install either the Memcache or Memcached extension.');
+            throw new \Exception(
+                'Missing Memcached implementation. You must install either the Memcache or Memcached extension.'
+            );
         }
         self::$extension = strtolower($class);
 
-        // create the Memcache object
+        // create the \Memcache object
         $memcache = new $class();
 
         // iterate over all the servers in the group and add them to the Memcache object
         foreach ($group as $index => $server) {
             // make sure that we don't have an index. An index would be a sign of invalid configuration
             if (!is_int($index)) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid index on element in the 'memcache_store.servers' configuration option. Perhaps you".
                     ' have forgotten to add an array(...) around one of the server groups? The invalid index was: '.
                     $index
@@ -332,7 +328,7 @@ class SimpleSAML_Memcache
 
             // make sure that the server object is an array. Each server is an array with name-value pairs
             if (!is_array($server)) {
-                throw new Exception(
+                throw new \Exception(
                     'Invalid value for the server with index '.$index.
                     '. Remeber that the \'memcache_store.servers\' configuration option'.
                     ' contains an array of arrays of arrays.'
@@ -350,9 +346,9 @@ class SimpleSAML_Memcache
      * This function gets a list of all configured memcache servers. This list is initialized based
      * on the content of 'memcache_store.servers' in the configuration.
      *
-     * @return Memcache[] Array with Memcache objects.
+     * @return \Memcache[] Array with Memcache objects.
      *
-     * @throws Exception If the servers configuration is invalid.
+     * @throws \Exception If the servers configuration is invalid.
      */
     private static function getMemcacheServers()
     {
@@ -362,10 +358,10 @@ class SimpleSAML_Memcache
         }
 
         // initialize the servers-array
-        self::$serverGroups = array();
+        self::$serverGroups = [];
 
         // load the configuration
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
 
 
         $groups = $config->getArray('memcache_store.servers');
@@ -374,7 +370,7 @@ class SimpleSAML_Memcache
         foreach ($groups as $index => $group) {
             // make sure that the group doesn't have an index. An index would be a sign of invalid configuration
             if (!is_int($index)) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid index on element in the 'memcache_store.servers'".
                     ' configuration option. Perhaps you have forgotten to add an array(...)'.
                     ' around one of the server groups? The invalid index was: '.$index
@@ -386,7 +382,7 @@ class SimpleSAML_Memcache
              * an array of name => value pairs for that server.
              */
             if (!is_array($group)) {
-                throw new Exception(
+                throw new \Exception(
                     "Invalid value for the server with index ".$index.
                     ". Remeber that the 'memcache_store.servers' configuration option".
                     ' contains an array of arrays of arrays.'
@@ -411,20 +407,20 @@ class SimpleSAML_Memcache
      *
      * @return integer The value which should be passed in the set(...) calls to the memcache objects.
      *
-     * @throws Exception If the option 'memcache_store.expires' has a negative value.
+     * @throws \Exception If the option 'memcache_store.expires' has a negative value.
      */
     private static function getExpireTime()
     {
         // get the configuration instance
-        $config = SimpleSAML_Configuration::getInstance();
-        assert($config instanceof SimpleSAML_Configuration);
+        $config = Configuration::getInstance();
+        assert($config instanceof \SimpleSAML\Configuration);
 
         // get the expire-value from the configuration
         $expire = $config->getInteger('memcache_store.expires', 0);
 
         // it must be a positive integer
         if ($expire < 0) {
-            throw new Exception(
+            throw new \Exception(
                 "The value of 'memcache_store.expires' in the configuration can't be a negative integer."
             );
         }
@@ -439,9 +435,7 @@ class SimpleSAML_Memcache
         /* The expire option is given as the number of seconds into the future an item should expire. We convert this
          * to an actual timestamp.
          */
-        $expireTime = time() + $expire;
-
-        return $expireTime;
+        return (time() + $expire);
     }
 
 
@@ -450,21 +444,21 @@ class SimpleSAML_Memcache
      *
      * @return array Array with the names of each stat and an array with the value for each server group.
      *
-     * @throws Exception If memcache server status couldn't be retrieved.
+     * @throws \Exception If memcache server status couldn't be retrieved.
      */
     public static function getStats()
     {
-        $ret = array();
+        $ret = [];
 
         foreach (self::getMemcacheServers() as $sg) {
             $stats = method_exists($sg, 'getExtendedStats') ? $sg->getExtendedStats() : $sg->getStats();
             foreach ($stats as $server => $data) {
                 if ($data === false) {
-                    throw new Exception('Failed to get memcache server status.');
+                    throw new \Exception('Failed to get memcache server status.');
                 }
             }
 
-            $stats = SimpleSAML\Utils\Arrays::transpose($stats);
+            $stats = Utils\Arrays::transpose($stats);
 
             $ret = array_merge_recursive($ret, $stats);
         }
@@ -481,7 +475,7 @@ class SimpleSAML_Memcache
      */
     public static function getRawStats()
     {
-        $ret = array();
+        $ret = [];
 
         foreach (self::getMemcacheServers() as $sg) {
             $stats = method_exists($sg, 'getExtendedStats') ? $sg->getExtendedStats() : $sg->getStats();
@@ -490,5 +484,4 @@ class SimpleSAML_Memcache
 
         return $ret;
     }
-
 }
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
index 95f23244914728ffa8d9ab4ea5b801c108d0ba6f..f39c2c0478aa20531702b53795bc3293d855b317 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandler.php
@@ -1,5 +1,8 @@
 <?php
 
+namespace SimpleSAML\Metadata;
+
+use SimpleSAML\Utils\ClearableState;
 
 /**
  * This file defines a class for metadata handling.
@@ -7,16 +10,15 @@
  * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_MetaDataStorageHandler
-{
-
 
+class MetaDataStorageHandler implements ClearableState
+{
     /**
      * This static variable contains a reference to the current
      * instance of the metadata handler. This variable will be null if
      * we haven't instantiated a metadata handler yet.
      *
-     * @var SimpleSAML_Metadata_MetaDataStorageHandler
+     * @var MetaDataStorageHandler
      */
     private static $metadataHandler = null;
 
@@ -25,7 +27,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * This is a list of all the metadata sources we have in our metadata
      * chain. When we need metadata, we will look through this chain from start to end.
      *
-     * @var SimpleSAML_Metadata_MetaDataStorageSource[]
+     * @var MetaDataStorageSource[]
      */
     private $sources;
 
@@ -35,12 +37,12 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * The metadata handler will be instantiated if this is the first call
      * to this function.
      *
-     * @return SimpleSAML_Metadata_MetaDataStorageHandler The current metadata handler instance.
+     * @return MetaDataStorageHandler The current metadata handler instance.
      */
     public static function getMetadataHandler()
     {
         if (self::$metadataHandler === null) {
-            self::$metadataHandler = new SimpleSAML_Metadata_MetaDataStorageHandler();
+            self::$metadataHandler = new MetaDataStorageHandler();
         }
 
         return self::$metadataHandler;
@@ -53,20 +55,20 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      */
     protected function __construct()
     {
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = \SimpleSAML\Configuration::getInstance();
 
         $sourcesConfig = $config->getArray('metadata.sources', null);
 
         // for backwards compatibility, and to provide a default configuration
         if ($sourcesConfig === null) {
             $type = $config->getString('metadata.handler', 'flatfile');
-            $sourcesConfig = array(array('type' => $type));
+            $sourcesConfig = [['type' => $type]];
         }
 
         try {
-            $this->sources = SimpleSAML_Metadata_MetaDataStorageSource::parseSources($sourcesConfig);
-        } catch (Exception $e) {
-            throw new Exception(
+            $this->sources = MetaDataStorageSource::parseSources($sourcesConfig);
+        } catch (\Exception $e) {
+            throw new \Exception(
                 "Invalid configuration of the 'metadata.sources' configuration option: ".$e->getMessage()
             );
         }
@@ -80,7 +82,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * @param string $set The set we the property comes from.
      *
      * @return string The auto-generated metadata property.
-     * @throws Exception If the metadata cannot be generated automatically.
+     * @throws \Exception If the metadata cannot be generated automatically.
      */
     public function getGenerated($property, $set)
     {
@@ -90,13 +92,13 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
             if (array_key_exists($property, $metadataSet)) {
                 return $metadataSet[$property];
             }
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             // probably metadata wasn't found. In any case we continue by generating the metadata
         }
 
         // get the configuration
-        $config = SimpleSAML_Configuration::getInstance();
-        assert($config instanceof SimpleSAML_Configuration);
+        $config = \SimpleSAML\Configuration::getInstance();
+        assert($config instanceof \SimpleSAML\Configuration);
 
         $baseurl = \SimpleSAML\Utils\HTTP::getSelfURLHost().$config->getBasePath();
 
@@ -124,7 +126,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
             }
         }
 
-        throw new Exception('Could not generate metadata property '.$property.' for set '.$set.'.');
+        throw new \Exception('Could not generate metadata property '.$property.' for set '.$set.'.');
     }
 
 
@@ -140,7 +142,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
     {
         assert(is_string($set));
 
-        $result = array();
+        $result = [];
 
         foreach ($this->sources as $source) {
             $srcList = $source->getMetadataSet($set);
@@ -149,9 +151,9 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
                 if (array_key_exists('expire', $le)) {
                     if ($le['expire'] < time()) {
                         unset($srcList[$key]);
-                        SimpleSAML\Logger::warning(
+                        \SimpleSAML\Logger::warning(
                             "Dropping metadata entity ".var_export($key, true).", expired ".
-                            SimpleSAML\Utils\Time::generateTimestamp($le['expire'])."."
+                            \SimpleSAML\Utils\Time::generateTimestamp($le['expire'])."."
                         );
                     }
                 }
@@ -189,7 +191,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * @param string $type Do you want to return the metaindex or the entityID. [entityid|metaindex]
      *
      * @return string The entity id which is associated with the current hostname/path combination.
-     * @throws Exception If no default metadata can be found in the set for the current host.
+     * @throws \Exception If no default metadata can be found in the set for the current host.
      */
     public function getMetaDataCurrentEntityID($set, $type = 'entityid')
     {
@@ -224,7 +226,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
         }
 
         // we were unable to find the hostname/path in any metadata source
-        throw new Exception(
+        throw new \Exception(
             'Could not find any default metadata entities in set ['.$set.'] for host ['.$currenthost.' : '.
             $currenthostwithpath.']'
         );
@@ -263,8 +265,8 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * @param string $set The set of metadata we are looking up the entity id in.
      *
      * @return array The metadata array describing the specified entity.
-     * @throws Exception If metadata for the specified entity is expired.
-     * @throws SimpleSAML_Error_MetadataNotFound If no metadata for the entity specified can be found.
+     * @throws \Exception If metadata for the specified entity is expired.
+     * @throws \SimpleSAML\Error\MetadataNotFound If no metadata for the entity specified can be found.
      */
     public function getMetaData($index, $set)
     {
@@ -280,10 +282,9 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
             $metadata = $source->getMetaData($index, $set);
 
             if ($metadata !== null) {
-
                 if (array_key_exists('expire', $metadata)) {
                     if ($metadata['expire'] < time()) {
-                        throw new Exception(
+                        throw new \Exception(
                             'Metadata for the entity ['.$index.'] expired '.
                             (time() - $metadata['expire']).' seconds ago.'
                         );
@@ -297,7 +298,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
             }
         }
 
-        throw new SimpleSAML_Error_MetadataNotFound($index);
+        throw new \SimpleSAML\Error\MetadataNotFound($index);
     }
 
 
@@ -309,8 +310,8 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * @param string $entityId The entity ID we are looking up.
      * @param string $set The metadata set we are searching.
      *
-     * @return SimpleSAML_Configuration The configuration object representing the metadata.
-     * @throws SimpleSAML_Error_MetadataNotFound If no metadata for the entity specified can be found.
+     * @return \SimpleSAML\Configuration The configuration object representing the metadata.
+     * @throws \SimpleSAML\Error\MetadataNotFound If no metadata for the entity specified can be found.
      */
     public function getMetaDataConfig($entityId, $set)
     {
@@ -318,7 +319,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
         assert(is_string($set));
 
         $metadata = $this->getMetaData($entityId, $set);
-        return SimpleSAML_Configuration::loadFromArray($metadata, $set.'/'.var_export($entityId, true));
+        return \SimpleSAML\Configuration::loadFromArray($metadata, $set.'/'.var_export($entityId, true));
     }
 
 
@@ -328,7 +329,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
      * @param string $sha1 The SHA1 digest of the entity ID.
      * @param string $set The metadata set we are searching.
      *
-     * @return null|SimpleSAML_Configuration The metadata corresponding to the entity, or null if the entity cannot be
+     * @return null|\SimpleSAML\Configuration The metadata corresponding to the entity, or null if the entity cannot be
      * found.
      */
     public function getMetaDataConfigForSha1($sha1, $set)
@@ -336,7 +337,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
         assert(is_string($sha1));
         assert(is_string($set));
 
-        $result = array();
+        $result = [];
 
         foreach ($this->sources as $source) {
             $srcList = $source->getMetadataSet($set);
@@ -347,11 +348,10 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
             $result = array_merge($srcList, $result);
         }
         foreach ($result as $remote_provider) {
-
             if (sha1($remote_provider['entityid']) == $sha1) {
                 $remote_provider['metadata-set'] = $set;
 
-                return SimpleSAML_Configuration::loadFromArray(
+                return \SimpleSAML\Configuration::loadFromArray(
                     $remote_provider,
                     $set.'/'.var_export($remote_provider['entityid'], true)
                 );
@@ -360,4 +360,14 @@ class SimpleSAML_Metadata_MetaDataStorageHandler
 
         return null;
     }
+
+    /**
+     * Clear any metadata cached.
+     * Allows for metadata configuration to be changed and reloaded during a given request. Most useful
+     * when running phpunit tests and needing to alter config.php and metadata sources between test cases
+     */
+    public static function clearInternalState()
+    {
+        self::$metadataHandler = null;
+    }
 }
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
index 09ce8b2890c942f9cb8df5686e389f59f748d258..2d7883b8c96cfaefc228266581498b5115ca23d3 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerFlatFile.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * This file defines a flat file metadata source.
@@ -9,9 +10,9 @@
  * @author Andreas Ă…kre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Metadata_MetaDataStorageSource
-{
 
+class MetaDataStorageHandlerFlatFile extends MetaDataStorageSource
+{
     /**
      * This is the directory we will load metadata files from. The path will always end
      * with a '/'.
@@ -26,7 +27,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Meta
      *
      * @var array
      */
-    private $cachedMetadata = array();
+    private $cachedMetadata = [];
 
 
     /**
@@ -43,7 +44,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Meta
         assert(is_array($config));
 
         // get the configuration
-        $globalConfig = SimpleSAML_Configuration::getInstance();
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
 
         // find the path to the directory we should search for metadata in
         if (array_key_exists('directory', $config)) {
@@ -77,12 +78,12 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Meta
             return null;
         }
 
-        $metadata = array();
+        $metadata = [];
 
         include($metadatasetfile);
 
         if (!is_array($metadata)) {
-            throw new Exception('Could not load metadata set ['.$set.'] from file: '.$metadatasetfile);
+            throw new \Exception('Could not load metadata set ['.$set.'] from file: '.$metadatasetfile);
         }
 
         return $metadata;
@@ -106,7 +107,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Meta
 
         $metadataSet = $this->load($set);
         if ($metadataSet === null) {
-            $metadataSet = array();
+            $metadataSet = [];
         }
 
         // add the entity id of an entry to each entry in the metadata
@@ -138,7 +139,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile extends SimpleSAML_Meta
         } elseif ($set === 'adfs-idp-hosted') {
             return 'urn:federation:'.\SimpleSAML\Utils\HTTP::getSelfHost().':idp';
         } else {
-            throw new Exception('Can not generate dynamic EntityID for metadata of this type: ['.$set.']');
+            throw new \Exception('Can not generate dynamic EntityID for metadata of this type: ['.$set.']');
         }
     }
 }
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php
index 0e3720e8b0911d33962d097f2e70ff9ab5f263f5..0645a0bec5485e5fb918a6cbba22c5f327b7e3e6 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerPdo.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * Class for handling metadata files stored in a database.
@@ -8,12 +9,11 @@
  * mooknarf@gmail.com and patched to work with the latest version
  * of SimpleSAMLphp
  *
- * @author Tyler Antonio, University of Alberta <tantonio@ualberta.ca>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_MetaDataStorageSource
-{
 
+class MetaDataStorageHandlerPdo extends MetaDataStorageSource
+{
     /**
      * The PDO object
      */
@@ -27,12 +27,12 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
     /**
      * This is an associative array which stores the different metadata sets we have loaded.
      */
-    private $cachedMetadata = array();
+    private $cachedMetadata = [];
 
     /**
      * All the metadata sets supported by this MetaDataStorageHandler
      */
-    public $supportedSets = array(
+    public $supportedSets = [
         'adfs-idp-hosted',
         'adfs-sp-remote',
         'saml20-idp-hosted',
@@ -44,7 +44,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
         'shib13-sp-remote',
         'wsfed-idp-remote',
         'wsfed-sp-hosted'
-    );
+    ];
 
 
     /**
@@ -62,7 +62,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
     {
         assert(is_array($config));
 
-        $this->db = SimpleSAML\Database::getInstance();
+        $this->db = \SimpleSAML\Database::getInstance();
     }
 
 
@@ -76,7 +76,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
      *     given file.
      *
      * @throws Exception If a database error occurs.
-     * @throws SimpleSAML_Error_Exception If the metadata can be retrieved from the database, but cannot be decoded.
+     * @throws \SimpleSAML\Error\Exception If the metadata can be retrieved from the database, but cannot be decoded.
      */
     private function load($set)
     {
@@ -90,12 +90,12 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
 
         $stmt = $this->db->read("SELECT entity_id, entity_data FROM $tableName");
         if ($stmt->execute()) {
-            $metadata = array();
+            $metadata = [];
 
             while ($d = $stmt->fetch()) {
                 $data = json_decode($d['entity_data'], true);
                 if ($data === null) {
-                    throw new SimpleSAML_Error_Exception("Cannot decode metadata for entity '${d['entity_id']}'");
+                    throw new \SimpleSAML\Error\Exception("Cannot decode metadata for entity '${d['entity_id']}'");
                 }
                 if (!array_key_exists('entityid', $data)) {
                     $data['entityid'] = $d['entity_id'];
@@ -105,7 +105,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
 
             return $metadata;
         } else {
-            throw new Exception('PDO metadata handler: Database error: '.var_export($this->db->getLastError(), true));
+            throw new \Exception('PDO metadata handler: Database error: '.var_export($this->db->getLastError(), true));
         }
     }
 
@@ -127,7 +127,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
 
         $metadataSet = $this->load($set);
         if ($metadataSet === null) {
-            $metadataSet = array();
+            $metadataSet = [];
         }
 
         foreach ($metadataSet as $entityId => &$entry) {
@@ -142,6 +142,52 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
         return $metadataSet;
     }
 
+    /**
+     * Retrieve a metadata entry.
+     *
+     * @param string $entityId The entityId we are looking up.
+     * @param string $set The set we are looking for metadata in.
+     *
+     * @return array An associative array with metadata for the given entity, or NULL if we are unable to
+     *         locate the entity.
+     */
+    public function getMetaData($entityId, $set)
+    {
+        assert(is_string($entityId));
+        assert(is_string($set));
+
+        $tableName = $this->getTableName($set);
+
+        if (!in_array($set, $this->supportedSets, true)) {
+            return null;
+        }
+
+        $stmt = $this->db->read(
+            "SELECT entity_id, entity_data FROM $tableName WHERE entity_id=:entityId",
+            ['entityId' => $entityId]
+        );
+        if ($stmt->execute()) {
+            $rowCount = 0;
+            $data = null;
+
+            while ($d = $stmt->fetch()) {
+                if (++$rowCount > 1) {
+                    \SimpleSAML\Logger::warning("Duplicate match for $entityId in set $set");
+                    break;
+                }
+                $data = json_decode($d['entity_data'], true);
+                if ($data === null) {
+                    throw new \SimpleSAML\Error\Exception("Cannot decode metadata for entity '${d['entity_id']}'");
+                }
+                if (!array_key_exists('entityid', $data)) {
+                    $data['entityid'] = $d['entity_id'];
+                }
+            }
+            return $data;
+        } else {
+            throw new \Exception('PDO metadata handler: Database error: '.var_export($this->db->getLastError(), true));
+        }
+    }
 
     private function generateDynamicHostedEntityID($set)
     {
@@ -163,7 +209,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
         } elseif ($set === 'adfs-idp-hosted') {
             return 'urn:federation:'.\SimpleSAML\Utils\HTTP::getSelfHost().':idp';
         } else {
-            throw new Exception('Can not generate dynamic EntityID for metadata of this type: ['.$set.']');
+            throw new \Exception('Can not generate dynamic EntityID for metadata of this type: ['.$set.']');
         }
     }
 
@@ -191,17 +237,17 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
 
         $metadata = $this->db->read(
             "SELECT entity_id, entity_data FROM $tableName WHERE entity_id = :entity_id",
-            array(
+            [
                 'entity_id' => $index,
-            )
+            ]
         );
 
         $retrivedEntityIDs = $metadata->fetch();
 
-        $params = array(
+        $params = [
             'entity_id'   => $index,
             'entity_data' => json_encode($entityData),
-        );
+        ];
 
         if ($retrivedEntityIDs !== false && count($retrivedEntityIDs) > 0) {
             $rows = $this->db->write(
@@ -250,7 +296,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
                 "CREATE TABLE IF NOT EXISTS $tableName (entity_id VARCHAR(255) PRIMARY KEY NOT NULL, entity_data ".
                 "TEXT NOT NULL)"
             );
-            if ($rows === 0) {
+            if ($rows === false) {
                 $fine = false;
             } else {
                 $stmt += $rows;
@@ -261,5 +307,4 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerPdo extends SimpleSAML_Metadata_
         }
         return $stmt;
     }
-
 }
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
index a9ec6f3c41ae02382db0fcd54cd1218c7fc68b5b..8c050775678d401067097278739cb1e4915680ec 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerSerialize.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * Class for handling metadata files in serialized format.
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Metadata_MetaDataStorageSource
-{
 
+class MetaDataStorageHandlerSerialize extends MetaDataStorageSource
+{
     /**
      * The file extension we use for our metadata files.
      *
@@ -36,9 +37,9 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
     {
         assert(is_array($config));
 
-        $globalConfig = SimpleSAML_Configuration::getInstance();
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
 
-        $cfgHelp = SimpleSAML_Configuration::loadFromArray($config, 'serialize metadata source');
+        $cfgHelp = \SimpleSAML\Configuration::loadFromArray($config, 'serialize metadata source');
 
         $this->directory = $cfgHelp->getString('directory');
 
@@ -73,18 +74,17 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
      */
     public function getMetadataSets()
     {
-        $ret = array();
+        $ret = [];
 
         $dh = @opendir($this->directory);
         if ($dh === false) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Serialize metadata handler: Unable to open directory: '.var_export($this->directory, true)
             );
             return $ret;
         }
 
         while (($entry = readdir($dh)) !== false) {
-
             if ($entry[0] === '.') {
                 // skip '..', '.' and hidden files
                 continue;
@@ -93,7 +93,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
             $path = $this->directory.'/'.$entry;
 
             if (!is_dir($path)) {
-                SimpleSAML\Logger::warning(
+                \SimpleSAML\Logger::warning(
                     'Serialize metadata handler: Metadata directory contained a file where only directories should '.
                     'exist: '.var_export($path, true)
                 );
@@ -120,7 +120,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
     {
         assert(is_string($set));
 
-        $ret = array();
+        $ret = [];
 
         $dir = $this->directory.'/'.rawurlencode($set);
         if (!is_dir($dir)) {
@@ -130,7 +130,9 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
 
         $dh = @opendir($dir);
         if ($dh === false) {
-            SimpleSAML\Logger::warning('Serialize metadata handler: Unable to open directory: '.var_export($dir, true));
+            \SimpleSAML\Logger::warning(
+                'Serialize metadata handler: Unable to open directory: '.var_export($dir, true)
+            );
             return $ret;
         }
 
@@ -183,7 +185,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
         $data = @file_get_contents($filePath);
         if ($data === false) {
             $error = error_get_last();
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Error reading file '.$filePath.': '.$error['message']
             );
             return null;
@@ -191,7 +193,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
 
         $data = @unserialize($data);
         if ($data === false) {
-            SimpleSAML\Logger::warning('Error unserializing file: '.$filePath);
+            \SimpleSAML\Logger::warning('Error unserializing file: '.$filePath);
             return null;
         }
 
@@ -223,30 +225,30 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
 
         $dir = dirname($filePath);
         if (!is_dir($dir)) {
-            SimpleSAML\Logger::info('Creating directory: '.$dir);
+            \SimpleSAML\Logger::info('Creating directory: '.$dir);
             $res = @mkdir($dir, 0777, true);
             if ($res === false) {
                 $error = error_get_last();
-                SimpleSAML\Logger::error('Failed to create directory '.$dir.': '.$error['message']);
+                \SimpleSAML\Logger::error('Failed to create directory '.$dir.': '.$error['message']);
                 return false;
             }
         }
 
         $data = serialize($metadata);
 
-        SimpleSAML\Logger::debug('Writing: '.$newPath);
+        \SimpleSAML\Logger::debug('Writing: '.$newPath);
 
         $res = file_put_contents($newPath, $data);
         if ($res === false) {
             $error = error_get_last();
-            SimpleSAML\Logger::error('Error saving file '.$newPath.': '.$error['message']);
+            \SimpleSAML\Logger::error('Error saving file '.$newPath.': '.$error['message']);
             return false;
         }
 
         $res = rename($newPath, $filePath);
         if ($res === false) {
             $error = error_get_last();
-            SimpleSAML\Logger::error('Error renaming '.$newPath.' to '.$filePath.': '.$error['message']);
+            \SimpleSAML\Logger::error('Error renaming '.$newPath.' to '.$filePath.': '.$error['message']);
             return false;
         }
 
@@ -268,7 +270,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
         $filePath = $this->getMetadataPath($entityId, $set);
 
         if (!file_exists($filePath)) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Attempted to erase nonexistent metadata entry '.
                 var_export($entityId, true).' in set '.var_export($set, true).'.'
             );
@@ -278,7 +280,7 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerSerialize extends SimpleSAML_Met
         $res = unlink($filePath);
         if ($res === false) {
             $error = error_get_last();
-            SimpleSAML\Logger::error(
+            \SimpleSAML\Logger::error(
                 'Failed to delete file '.$filePath.
                 ': '.$error['message']
             );
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerXML.php b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerXML.php
index 44dba1fcfe357bf20979a1e7b341983e5778ecf3..9430781b6c1d02d2d6edbb451ec990183e8915f6 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageHandlerXML.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageHandlerXML.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * This class implements a metadata source which loads metadata from XML files.
@@ -8,7 +9,8 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_MetaDataStorageHandlerXML extends SimpleSAML_Metadata_MetaDataStorageSource
+
+class MetaDataStorageHandlerXML extends MetaDataStorageSource
 {
 
     /**
@@ -32,27 +34,34 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerXML extends SimpleSAML_Metadata_
      */
     protected function __construct($config)
     {
-        // get the configuration
-        $globalConfig = SimpleSAML_Configuration::getInstance();
-
+        $src = $srcXml = null;
         if (array_key_exists('file', $config)) {
+            // get the configuration
+            $globalConfig = \SimpleSAML\Configuration::getInstance();
             $src = $globalConfig->resolvePath($config['file']);
         } elseif (array_key_exists('url', $config)) {
             $src = $config['url'];
+        } elseif (array_key_exists('xml', $config)) {
+            $srcXml = $config['xml'];
         } else {
-            throw new Exception("Missing either 'file' or 'url' in XML metadata source configuration.");
+            throw new \Exception("Missing one of 'file', 'url' and 'xml' in XML metadata source configuration.");
         }
 
 
-        $SP1x = array();
-        $IdP1x = array();
-        $SP20 = array();
-        $IdP20 = array();
-        $AAD = array();
+        $SP1x = [];
+        $IdP1x = [];
+        $SP20 = [];
+        $IdP20 = [];
+        $AAD = [];
 
-        $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsFile($src);
+        if (isset($src)) {
+            $entities = SAMLParser::parseDescriptorsFile($src);
+        } elseif (isset($srcXml)) {
+            $entities = SAMLParser::parseDescriptorsString($srcXml);
+        } else {
+            throw new \Exception("Neither source file path/URI nor string data provided");
+        }
         foreach ($entities as $entityId => $entity) {
-
             $md = $entity->getMetadata1xSP();
             if ($md !== null) {
                 $SP1x[$entityId] = $md;
@@ -79,13 +88,13 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerXML extends SimpleSAML_Metadata_
             }
         }
 
-        $this->metadata = array(
+        $this->metadata = [
             'shib13-sp-remote'          => $SP1x,
             'shib13-idp-remote'         => $IdP1x,
             'saml20-sp-remote'          => $SP20,
             'saml20-idp-remote'         => $IdP20,
             'attributeauthority-remote' => $AAD,
-        );
+        ];
     }
 
 
@@ -104,6 +113,6 @@ class SimpleSAML_Metadata_MetaDataStorageHandlerXML extends SimpleSAML_Metadata_
         }
 
         // we don't have this metadata set
-        return array();
+        return [];
     }
 }
diff --git a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
index bc96feeec691e4dd4339ea455ab0f876931064ca..76aeabb635076f76ca54c640aea061331c20d866 100644
--- a/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
+++ b/lib/SimpleSAML/Metadata/MetaDataStorageSource.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * This abstract class defines an interface for metadata storage sources.
@@ -12,10 +13,9 @@
  * @author Andreas Aakre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-abstract class SimpleSAML_Metadata_MetaDataStorageSource
-{
-
 
+abstract class MetaDataStorageSource
+{
     /**
      * Parse array with metadata sources.
      *
@@ -26,17 +26,17 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
      *
      * @return array  Parsed metadata configuration.
      *
-     * @throws Exception If something is wrong in the configuration.
+     * @throws \Exception If something is wrong in the configuration.
      */
     public static function parseSources($sourcesConfig)
     {
         assert(is_array($sourcesConfig));
 
-        $sources = array();
+        $sources = [];
 
         foreach ($sourcesConfig as $sourceConfig) {
             if (!is_array($sourceConfig)) {
-                throw new Exception("Found an element in metadata source configuration which wasn't an array.");
+                throw new \Exception("Found an element in metadata source configuration which wasn't an array.");
             }
 
             $sources[] = self::getSource($sourceConfig);
@@ -55,7 +55,7 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
      *
      * @return mixed An instance of a metadata source with the given configuration.
      *
-     * @throws Exception If the metadata source type is invalid.
+     * @throws \Exception If the metadata source type is invalid.
      */
     public static function getSource($sourceConfig)
     {
@@ -69,26 +69,26 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
 
         switch ($type) {
             case 'flatfile':
-                return new SimpleSAML_Metadata_MetaDataStorageHandlerFlatFile($sourceConfig);
+                return new MetaDataStorageHandlerFlatFile($sourceConfig);
             case 'xml':
-                return new SimpleSAML_Metadata_MetaDataStorageHandlerXML($sourceConfig);
+                return new MetaDataStorageHandlerXML($sourceConfig);
             case 'serialize':
-                return new SimpleSAML_Metadata_MetaDataStorageHandlerSerialize($sourceConfig);
+                return new MetaDataStorageHandlerSerialize($sourceConfig);
             case 'mdx':
             case 'mdq':
-                return new \SimpleSAML\Metadata\Sources\MDQ($sourceConfig);
+                return new Sources\MDQ($sourceConfig);
             case 'pdo':
-                return new SimpleSAML_Metadata_MetaDataStorageHandlerPdo($sourceConfig);
+                return new MetaDataStorageHandlerPdo($sourceConfig);
             default:
                 // metadata store from module
                 try {
-                    $className = SimpleSAML\Module::resolveClass(
+                    $className = \SimpleSAML\Module::resolveClass(
                         $type,
                         'MetadataStore',
-                        'SimpleSAML_Metadata_MetaDataStorageSource'
+                        '\SimpleSAML\Metadata\MetaDataStorageSource'
                     );
-                } catch (Exception $e) {
-                    throw new SimpleSAML\Error\CriticalConfigurationError(
+                } catch (\Exception $e) {
+                    throw new \SimpleSAML\Error\CriticalConfigurationError(
                         "Invalid 'type' for metadata source. Cannot find store '$type'.",
                         null
                     );
@@ -111,7 +111,7 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
      */
     public function getMetadataSet($set)
     {
-        return array();
+        return [];
     }
 
 
@@ -139,7 +139,6 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
         }
 
         foreach ($metadataSet as $index => $entry) {
-
             if (!array_key_exists('host', $entry)) {
                 continue;
             }
@@ -159,7 +158,7 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
 
 
     /**
-     * This function will go through all the metadata, and check the hint.cidr
+     * This function will go through all the metadata, and check the DiscoHints->IPHint
      * parameter, which defines a network space (ip range) for each remote entry.
      * This function returns the entityID for any of the entities that have an
      * IP range which the IP falls within.
@@ -177,16 +176,27 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
         $metadataSet = $this->getMetadataSet($set);
 
         foreach ($metadataSet as $index => $entry) {
+            $cidrHints = [];
+            
+            // support hint.cidr for idp discovery
+            if (array_key_exists('hint.cidr', $entry) && is_array($entry['hint.cidr'])) {
+                $cidrHints = $entry['hint.cidr'];
+            }
 
-            if (!array_key_exists('hint.cidr', $entry)) {
-                continue;
+            // support discohints in idp metadata for idp discovery
+            if (array_key_exists('DiscoHints', $entry)
+                && array_key_exists('IPHint', $entry['DiscoHints'])
+                && is_array($entry['DiscoHints']['IPHint'])) {
+                // merge with hints derived from discohints, but prioritize hint.cidr in case it is used
+                $cidrHints = array_merge($entry['DiscoHints']['IPHint'], $cidrHints);
             }
-            if (!is_array($entry['hint.cidr'])) {
+
+            if (empty($cidrHints)) {
                 continue;
             }
 
-            foreach ($entry['hint.cidr'] as $hint_entry) {
-                if (SimpleSAML\Utils\Net::ipCIDRcheck($hint_entry, $ip)) {
+            foreach ($cidrHints as $hint_entry) {
+                if (\SimpleSAML\Utils\Net::ipCIDRcheck($hint_entry, $ip)) {
                     if ($type === 'entityid') {
                         return $entry['entityid'];
                     } else {
@@ -262,5 +272,4 @@ abstract class SimpleSAML_Metadata_MetaDataStorageSource
 
         return null;
     }
-
 }
diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php
index c21df33a5dbfd1bcfc526cdfa6dab355cd642805..2e56c1bfde365f323287d41531753a6456ba74d7 100644
--- a/lib/SimpleSAML/Metadata/SAMLBuilder.php
+++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Metadata;
 
 /**
  * Class for generating SAML 2.0 metadata from SimpleSAMLphp metadata arrays.
@@ -8,10 +9,9 @@
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_SAMLBuilder
-{
-
 
+class SAMLBuilder
+{
     /**
      * The EntityDescriptor we are building.
      *
@@ -76,7 +76,7 @@ class SimpleSAML_Metadata_SAMLBuilder
     /**
      * Retrieve the EntityDescriptor element which is generated for this entity.
      *
-     * @return DOMElement The EntityDescriptor element of this entity.
+     * @return \DOMElement The EntityDescriptor element of this entity.
      */
     public function getEntityDescriptor()
     {
@@ -102,7 +102,7 @@ class SimpleSAML_Metadata_SAMLBuilder
 
         $xml = $this->getEntityDescriptor();
         if ($formatted) {
-            SimpleSAML\Utils\XML::formatDOMElement($xml);
+            \SimpleSAML\Utils\XML::formatDOMElement($xml);
         }
 
         return $xml->ownerDocument->saveXML();
@@ -120,9 +120,9 @@ class SimpleSAML_Metadata_SAMLBuilder
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
         $defaultEndpoint = $metadata->getDefaultEndpoint('SingleSignOnService');
-        $e = new sspmod_adfs_SAML2_XML_fed_SecurityTokenServiceType();
+        $e = new \SimpleSAML\Module\adfs\SAML2\XML\fed\SecurityTokenServiceType();
         $e->Location = $defaultEndpoint['Location'];
 
         $this->addCertificate($e, $metadata);
@@ -134,10 +134,10 @@ class SimpleSAML_Metadata_SAMLBuilder
     /**
      * Add extensions to the metadata.
      *
-     * @param SimpleSAML_Configuration    $metadata The metadata to get extensions from.
+     * @param \SimpleSAML\Configuration    $metadata The metadata to get extensions from.
      * @param \SAML2\XML\md\RoleDescriptor $e Reference to the element where the Extensions element should be included.
      */
-    private function addExtensions(SimpleSAML_Configuration $metadata, \SAML2\XML\md\RoleDescriptor $e)
+    private function addExtensions(\SimpleSAML\Configuration $metadata, \SAML2\XML\md\RoleDescriptor $e)
     {
         if ($metadata->hasValue('tags')) {
             $a = new \SAML2\XML\saml\Attribute();
@@ -299,8 +299,7 @@ class SimpleSAML_Metadata_SAMLBuilder
      */
     public function addOrganizationInfo(array $metadata)
     {
-        if (
-            empty($metadata['OrganizationName']) ||
+        if (empty($metadata['OrganizationName']) ||
             empty($metadata['OrganizationDisplayName']) ||
             empty($metadata['OrganizationURL'])
         ) {
@@ -308,9 +307,9 @@ class SimpleSAML_Metadata_SAMLBuilder
             return;
         }
 
-        $orgName = SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationName'], 'en');
-        $orgDisplayName = SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationDisplayName'], 'en');
-        $orgURL = SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationURL'], 'en');
+        $orgName = \SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationName'], 'en');
+        $orgDisplayName = \SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationDisplayName'], 'en');
+        $orgURL = \SimpleSAML\Utils\Arrays::arrayize($metadata['OrganizationURL'], 'en');
 
         $this->addOrganization($orgName, $orgDisplayName, $orgURL);
     }
@@ -322,13 +321,14 @@ class SimpleSAML_Metadata_SAMLBuilder
      * @param array $endpoints The endpoints.
      * @param bool  $indexed Whether the endpoints should be indexed.
      *
-     * @return array An array of endpoint objects, either \SAML2\XML\md\EndpointType or \SAML2\XML\md\IndexedEndpointType.
+     * @return array An array of endpoint objects,
+     *     either \SAML2\XML\md\EndpointType or \SAML2\XML\md\IndexedEndpointType.
      */
     private static function createEndpoints(array $endpoints, $indexed)
     {
         assert(is_bool($indexed));
 
-        $ret = array();
+        $ret = [];
 
         foreach ($endpoints as &$ep) {
             if ($indexed) {
@@ -381,13 +381,13 @@ class SimpleSAML_Metadata_SAMLBuilder
      * Add an AttributeConsumingService element to the metadata.
      *
      * @param \SAML2\XML\md\SPSSODescriptor $spDesc The SPSSODescriptor element.
-     * @param SimpleSAML_Configuration     $metadata The metadata.
+     * @param \SimpleSAML\Configuration     $metadata The metadata.
      */
     private function addAttributeConsumingService(
         \SAML2\XML\md\SPSSODescriptor $spDesc,
-        SimpleSAML_Configuration $metadata
+        \SimpleSAML\Configuration $metadata
     ) {
-        $attributes = $metadata->getArray('attributes', array());
+        $attributes = $metadata->getArray('attributes', []);
         $name = $metadata->getLocalizedString('name', null);
 
         if ($name === null || count($attributes) == 0) {
@@ -395,7 +395,7 @@ class SimpleSAML_Metadata_SAMLBuilder
             return;
         }
 
-        $attributesrequired = $metadata->getArray('attributes.required', array());
+        $attributesrequired = $metadata->getArray('attributes.required', []);
 
         /*
          * Add an AttributeConsumingService element with information as name and description and list
@@ -403,10 +403,14 @@ class SimpleSAML_Metadata_SAMLBuilder
          */
         $attributeconsumer = new \SAML2\XML\md\AttributeConsumingService();
 
-        $attributeconsumer->index = 0;
+        $attributeconsumer->index = $metadata->getInteger('attributes.index', 0);
+
+        if ($metadata->hasValue('attributes.isDefault')) {
+            $attributeconsumer->isDefault = $metadata->getBoolean('attributes.isDefault', false);
+        }
 
         $attributeconsumer->ServiceName = $name;
-        $attributeconsumer->ServiceDescription = $metadata->getLocalizedString('description', array());
+        $attributeconsumer->ServiceDescription = $metadata->getLocalizedString('description', []);
 
         $nameFormat = $metadata->getString('attributes.NameFormat', \SAML2\Constants::NAMEFORMAT_UNSPECIFIED);
         foreach ($attributes as $friendlyName => $attribute) {
@@ -458,7 +462,7 @@ class SimpleSAML_Metadata_SAMLBuilder
                 $this->addAttributeAuthority($metadata);
                 break;
             default:
-                SimpleSAML\Logger::warning('Unable to generate metadata for unknown type \''.$set.'\'.');
+                \SimpleSAML\Logger::warning('Unable to generate metadata for unknown type \''.$set.'\'.');
         }
     }
 
@@ -469,14 +473,14 @@ class SimpleSAML_Metadata_SAMLBuilder
      * @param array $metadata The metadata.
      * @param array $protocols The protocols supported. Defaults to \SAML2\Constants::NS_SAMLP.
      */
-    public function addMetadataSP20($metadata, $protocols = array(\SAML2\Constants::NS_SAMLP))
+    public function addMetadataSP20($metadata, $protocols = [\SAML2\Constants::NS_SAMLP])
     {
         assert(is_array($metadata));
         assert(is_array($protocols));
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
 
         $e = new \SAML2\XML\md\SPSSODescriptor();
         $e->protocolSupportEnumeration = $protocols;
@@ -497,14 +501,14 @@ class SimpleSAML_Metadata_SAMLBuilder
 
         $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService'), false);
 
-        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', array());
+        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', []);
 
         $endpoints = $metadata->getEndpoints('AssertionConsumerService');
-        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', array()) as $acs) {
-            $endpoints[] = array(
+        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', []) as $acs) {
+            $endpoints[] = [
                 'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
                 'Location' => $acs,
-            );
+            ];
         }
         $e->AssertionConsumerService = self::createEndpoints($endpoints, true);
 
@@ -512,7 +516,7 @@ class SimpleSAML_Metadata_SAMLBuilder
 
         $this->entityDescriptor->RoleDescriptor[] = $e;
 
-        foreach ($metadata->getArray('contacts', array()) as $contact) {
+        foreach ($metadata->getArray('contacts', []) as $contact) {
             if (array_key_exists('contactType', $contact) && array_key_exists('emailAddress', $contact)) {
                 $this->addContact($contact['contactType'], \SimpleSAML\Utils\Config\Metadata::getContact($contact));
             }
@@ -531,7 +535,7 @@ class SimpleSAML_Metadata_SAMLBuilder
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
 
         $e = new \SAML2\XML\md\IDPSSODescriptor();
         $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:2.0:protocol';
@@ -555,13 +559,13 @@ class SimpleSAML_Metadata_SAMLBuilder
 
         $e->SingleLogoutService = self::createEndpoints($metadata->getEndpoints('SingleLogoutService'), false);
 
-        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', array());
+        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', []);
 
         $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService'), false);
 
         $this->entityDescriptor->RoleDescriptor[] = $e;
 
-        foreach ($metadata->getArray('contacts', array()) as $contact) {
+        foreach ($metadata->getArray('contacts', []) as $contact) {
             if (array_key_exists('contactType', $contact) && array_key_exists('emailAddress', $contact)) {
                 $this->addContact($contact['contactType'], \SimpleSAML\Utils\Config\Metadata::getContact($contact));
             }
@@ -580,21 +584,21 @@ class SimpleSAML_Metadata_SAMLBuilder
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
 
         $e = new \SAML2\XML\md\SPSSODescriptor();
         $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
 
         $this->addCertificate($e, $metadata);
 
-        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', array());
+        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', []);
 
         $endpoints = $metadata->getEndpoints('AssertionConsumerService');
-        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', array()) as $acs) {
-            $endpoints[] = array(
+        foreach ($metadata->getArrayizeString('AssertionConsumerService.artifact', []) as $acs) {
+            $endpoints[] = [
                 'Binding'  => 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01',
                 'Location' => $acs,
-            );
+            ];
         }
         $e->AssertionConsumerService = self::createEndpoints($endpoints, true);
 
@@ -615,7 +619,7 @@ class SimpleSAML_Metadata_SAMLBuilder
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
 
         $e = new \SAML2\XML\md\IDPSSODescriptor();
         $e->protocolSupportEnumeration[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
@@ -623,7 +627,7 @@ class SimpleSAML_Metadata_SAMLBuilder
 
         $this->addCertificate($e, $metadata);
 
-        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', array());
+        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', []);
 
         $e->SingleSignOnService = self::createEndpoints($metadata->getEndpoints('SingleSignOnService'), false);
 
@@ -635,7 +639,7 @@ class SimpleSAML_Metadata_SAMLBuilder
      * Add metadata of a SAML attribute authority.
      *
      * @param array $metadata The AttributeAuthorityDescriptor, in the format returned by
-     * SimpleSAML_Metadata_SAMLParser.
+     * \SimpleSAML\Metadata\SAMLParser.
      */
     public function addAttributeAuthority(array $metadata)
     {
@@ -643,10 +647,10 @@ class SimpleSAML_Metadata_SAMLBuilder
         assert(isset($metadata['entityid']));
         assert(isset($metadata['metadata-set']));
 
-        $metadata = SimpleSAML_Configuration::loadFromArray($metadata, $metadata['entityid']);
+        $metadata = \SimpleSAML\Configuration::loadFromArray($metadata, $metadata['entityid']);
 
         $e = new \SAML2\XML\md\AttributeAuthorityDescriptor();
-        $e->protocolSupportEnumeration = $metadata->getArray('protocols', array(\SAML2\Constants::NS_SAMLP));
+        $e->protocolSupportEnumeration = $metadata->getArray('protocols', [\SAML2\Constants::NS_SAMLP]);
 
         $this->addExtensions($metadata, $e);
         $this->addCertificate($e, $metadata);
@@ -657,7 +661,7 @@ class SimpleSAML_Metadata_SAMLBuilder
             false
         );
 
-        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', array());
+        $e->NameIDFormat = $metadata->getArrayizeString('NameIDFormat', []);
 
         $this->entityDescriptor->RoleDescriptor[] = $e;
     }
@@ -680,7 +684,7 @@ class SimpleSAML_Metadata_SAMLBuilder
     {
         assert(is_string($type));
         assert(is_array($details));
-        assert(in_array($type, array('technical', 'support', 'administrative', 'billing', 'other'), true));
+        assert(in_array($type, ['technical', 'support', 'administrative', 'billing', 'other'], true));
 
         // TODO: remove this check as soon as getContact() is called always before calling this function
         $details = \SimpleSAML\Utils\Config\Metadata::getContact($details);
@@ -705,7 +709,7 @@ class SimpleSAML_Metadata_SAMLBuilder
         if (isset($details['emailAddress'])) {
             $eas = $details['emailAddress'];
             if (!is_array($eas)) {
-                $eas = array($eas);
+                $eas = [$eas];
             }
             foreach ($eas as $ea) {
                 $e->EmailAddress[] = $ea;
@@ -715,7 +719,7 @@ class SimpleSAML_Metadata_SAMLBuilder
         if (isset($details['telephoneNumber'])) {
             $tlfNrs = $details['telephoneNumber'];
             if (!is_array($tlfNrs)) {
-                $tlfNrs = array($tlfNrs);
+                $tlfNrs = [$tlfNrs];
             }
             foreach ($tlfNrs as $tlfNr) {
                 $e->TelephoneNumber[] = $tlfNr;
@@ -735,7 +739,7 @@ class SimpleSAML_Metadata_SAMLBuilder
      */
     private function addX509KeyDescriptor(\SAML2\XML\md\RoleDescriptor $rd, $use, $x509data)
     {
-        assert(in_array($use, array('encryption', 'signing'), true));
+        assert(in_array($use, ['encryption', 'signing'], true));
         assert(is_string($x509data));
 
         $keyDescriptor = \SAML2\Utils::createKeyDescriptor($x509data);
@@ -750,9 +754,9 @@ class SimpleSAML_Metadata_SAMLBuilder
      * Helper function for adding a certificate to the metadata.
      *
      * @param \SAML2\XML\md\RoleDescriptor $rd The RoleDescriptor the certificate should be added to.
-     * @param SimpleSAML_Configuration    $metadata The metadata of the entity.
+     * @param \SimpleSAML\Configuration    $metadata The metadata of the entity.
      */
-    private function addCertificate(\SAML2\XML\md\RoleDescriptor $rd, SimpleSAML_Configuration $metadata)
+    private function addCertificate(\SAML2\XML\md\RoleDescriptor $rd, \SimpleSAML\Configuration $metadata)
     {
         $keys = $metadata->getPublicKeys();
         foreach ($keys as $key) {
diff --git a/lib/SimpleSAML/Metadata/SAMLParser.php b/lib/SimpleSAML/Metadata/SAMLParser.php
index 4ee7cdda0735571fae7b5b8bb0e6b6fecfeb2aac..bd8725198b1d6388ef626c915bee42aca96212a0 100644
--- a/lib/SimpleSAML/Metadata/SAMLParser.php
+++ b/lib/SimpleSAML/Metadata/SAMLParser.php
@@ -1,10 +1,14 @@
 <?php
 
+namespace SimpleSAML\Metadata;
+
+use RobRichards\XMLSecLibs\XMLSecurityKey;
+
 /**
  * This is class for parsing of SAML 1.x and SAML 2.0 metadata.
  *
  * Metadata is loaded by calling the static methods parseFile, parseString or parseElement.
- * These functions returns an instance of SimpleSAML_Metadata_SAMLParser. To get metadata
+ * These functions returns an instance of SAMLParser. To get metadata
  * from this object, use the methods getMetadata1xSP or getMetadata20SP.
  *
  * To parse a file which can contain a collection of EntityDescriptor or EntitiesDescriptor elements, use the
@@ -12,26 +16,26 @@
  * an array of SAMLParser elements where each element represents an EntityDescriptor-element.
  */
 
-class SimpleSAML_Metadata_SAMLParser
+class SAMLParser
 {
     /**
      * This is the list of SAML 1.x protocols.
      *
      * @var string[]
      */
-    private static $SAML1xProtocols = array(
+    private static $SAML1xProtocols = [
         'urn:oasis:names:tc:SAML:1.0:protocol',
         'urn:oasis:names:tc:SAML:1.1:protocol',
-    );
+    ];
 
     /**
      * This is the list with the SAML 2.0 protocol.
      *
      * @var string[]
      */
-    private static $SAML20Protocols = array(
+    private static $SAML20Protocols = [
         'urn:oasis:names:tc:SAML:2.0:protocol',
-    );
+    ];
 
     /**
      * This is the entity id we find in the metadata.
@@ -67,7 +71,7 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @var array
      */
-    private $attributeAuthorityDescriptors = array();
+    private $attributeAuthorityDescriptors = [];
 
     /**
      * This is an associative array with the organization name for this entity. The key of
@@ -76,7 +80,7 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @var string[]
      */
-    private $organizationName = array();
+    private $organizationName = [];
 
     /**
      * This is an associative array with the organization display name for this entity. The key of
@@ -85,7 +89,7 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @var string[]
      */
-    private $organizationDisplayName = array();
+    private $organizationDisplayName = [];
 
     /**
      * This is an associative array with the organization URI for this entity. The key of
@@ -93,14 +97,14 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @var string[]
      */
-    private $organizationURL = array();
+    private $organizationURL = [];
 
     /**
      * This is an array of the Contact Persons of this entity.
      *
      * @var array[]
      */
-    private $contacts = array();
+    private $contacts = [];
 
     /**
      * @var array
@@ -128,7 +132,7 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @var \SAML2\SignedElementHelper[]
      */
-    private $validators = array();
+    private $validators = [];
 
     /**
      * The original EntityDescriptor element for this entity, as a base64 encoded string.
@@ -149,13 +153,13 @@ class SimpleSAML_Metadata_SAMLParser
     private function __construct(
         \SAML2\XML\md\EntityDescriptor $entityElement,
         $maxExpireTime,
-        array $validators = array(),
-        array $parentExtensions = array()
+        array $validators = [],
+        array $parentExtensions = []
     ) {
         assert($maxExpireTime === null || is_int($maxExpireTime));
 
-        $this->spDescriptors = array();
-        $this->idpDescriptors = array();
+        $this->spDescriptors = [];
+        $this->idpDescriptors = [];
 
         $e = $entityElement->toXML();
         $e = $e->ownerDocument->saveXML($e);
@@ -202,7 +206,7 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param string $file The path to the file which contains the metadata.
      *
-     * @return SimpleSAML_Metadata_SAMLParser An instance of this class with the metadata loaded.
+     * @return SAMLParser An instance of this class with the metadata loaded.
      * @throws Exception If the file does not parse as XML.
      */
     public static function parseFile($file)
@@ -211,8 +215,8 @@ class SimpleSAML_Metadata_SAMLParser
 
         try {
             $doc = \SAML2\DOMDocumentFactory::fromString($data);
-        } catch(\Exception $e) {
-            throw new Exception('Failed to read XML from file: '.$file);
+        } catch (\Exception $e) {
+            throw new \Exception('Failed to read XML from file: '.$file);
         }
 
         return self::parseDocument($doc);
@@ -224,15 +228,15 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param string $metadata A string which contains XML encoded metadata.
      *
-     * @return SimpleSAML_Metadata_SAMLParser An instance of this class with the metadata loaded.
+     * @return SAMLParser An instance of this class with the metadata loaded.
      * @throws Exception If the string does not parse as XML.
      */
     public static function parseString($metadata)
     {
         try {
             $doc = \SAML2\DOMDocumentFactory::fromString($metadata);
-        } catch(\Exception $e) {
-            throw new Exception('Failed to parse XML string.');
+        } catch (\Exception $e) {
+            throw new \Exception('Failed to parse XML string.');
         }
 
         return self::parseDocument($doc);
@@ -240,15 +244,15 @@ class SimpleSAML_Metadata_SAMLParser
 
 
     /**
-     * This function parses a DOMDocument which is assumed to contain a single EntityDescriptor element.
+     * This function parses a \DOMDocument which is assumed to contain a single EntityDescriptor element.
      *
-     * @param DOMDocument $document The DOMDocument which contains the EntityDescriptor element.
+     * @param \DOMDocument $document The \DOMDocument which contains the EntityDescriptor element.
      *
-     * @return SimpleSAML_Metadata_SAMLParser An instance of this class with the metadata loaded.
+     * @return SAMLParser An instance of this class with the metadata loaded.
      */
     public static function parseDocument($document)
     {
-        assert($document instanceof DOMDocument);
+        assert($document instanceof \DOMDocument);
 
         $entityElement = self::findEntityDescriptor($document);
 
@@ -262,12 +266,12 @@ class SimpleSAML_Metadata_SAMLParser
      * @param \SAML2\XML\md\EntityDescriptor $entityElement A \SAML2\XML\md\EntityDescriptor object which represents a
      *     EntityDescriptor element.
      *
-     * @return SimpleSAML_Metadata_SAMLParser An instance of this class with the metadata loaded.
+     * @return SAMLParser An instance of this class with the metadata loaded.
      */
     public static function parseElement($entityElement)
     {
         assert($entityElement instanceof \SAML2\XML\md\EntityDescriptor);
-        return new SimpleSAML_Metadata_SAMLParser($entityElement, null, array());
+        return new SAMLParser($entityElement, null, []);
     }
 
 
@@ -279,25 +283,25 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param string $file The path to the file which contains the EntityDescriptor or EntitiesDescriptor element.
      *
-     * @return SimpleSAML_Metadata_SAMLParser[] An array of SAMLParser instances.
-     * @throws Exception If the file does not parse as XML.
+     * @return SAMLParser[] An array of SAMLParser instances.
+     * @throws \Exception If the file does not parse as XML.
      */
     public static function parseDescriptorsFile($file)
     {
         if ($file === null) {
-            throw new Exception('Cannot open file NULL. File name not specified.');
+            throw new \Exception('Cannot open file NULL. File name not specified.');
         }
 
         $data = \SimpleSAML\Utils\HTTP::fetch($file);
 
         try {
             $doc = \SAML2\DOMDocumentFactory::fromString($data);
-        } catch(\Exception $e) {
-            throw new Exception('Failed to read XML from file: '.$file);
+        } catch (\Exception $e) {
+            throw new \Exception('Failed to read XML from file: '.$file);
         }
 
         if ($doc->documentElement === null) {
-            throw new Exception('Opened file is not an XML document: '.$file);
+            throw new \Exception('Opened file is not an XML document: '.$file);
         }
 
         return self::parseDescriptorsElement($doc->documentElement);
@@ -311,16 +315,16 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param string $string The string with XML data.
      *
-     * @return SimpleSAML_Metadata_SAMLParser[] An associative array of SAMLParser instances. The key of the array will
+     * @return SAMLParser[] An associative array of SAMLParser instances. The key of the array will
      *     be the entity id.
-     * @throws Exception If the string does not parse as XML.
+     * @throws \Exception If the string does not parse as XML.
      */
     public static function parseDescriptorsString($string)
     {
         try {
             $doc = \SAML2\DOMDocumentFactory::fromString($string);
-        } catch(\Exception $e) {
-            throw new Exception('Failed to parse XML string.');
+        } catch (\Exception $e) {
+            throw new \Exception('Failed to parse XML string.');
         }
 
         return self::parseDescriptorsElement($doc->documentElement);
@@ -331,25 +335,25 @@ class SimpleSAML_Metadata_SAMLParser
      * This function parses a DOMElement which represents either an EntityDescriptor element or an
      * EntitiesDescriptor element. It will return an associative array of SAMLParser instances in both cases.
      *
-     * @param DOMElement|NULL $element The DOMElement which contains the EntityDescriptor element or the
+     * @param \DOMElement|NULL $element The DOMElement which contains the EntityDescriptor element or the
      *     EntitiesDescriptor element.
      *
-     * @return SimpleSAML_Metadata_SAMLParser[] An associative array of SAMLParser instances. The key of the array will
+     * @return SAMLParser[] An associative array of SAMLParser instances. The key of the array will
      *     be the entity id.
-     * @throws Exception if the document is empty or the root is an unexpected node.
+     * @throws \Exception if the document is empty or the root is an unexpected node.
      */
-    public static function parseDescriptorsElement(DOMElement $element = null)
+    public static function parseDescriptorsElement(\DOMElement $element = null)
     {
         if ($element === null) {
-            throw new Exception('Document was empty.');
+            throw new \Exception('Document was empty.');
         }
 
-        if (SimpleSAML\Utils\XML::isDOMNodeOfType($element, 'EntityDescriptor', '@md') === true) {
+        if (\SimpleSAML\Utils\XML::isDOMNodeOfType($element, 'EntityDescriptor', '@md') === true) {
             return self::processDescriptorsElement(new \SAML2\XML\md\EntityDescriptor($element));
-        } elseif (SimpleSAML\Utils\XML::isDOMNodeOfType($element, 'EntitiesDescriptor', '@md') === true) {
+        } elseif (\SimpleSAML\Utils\XML::isDOMNodeOfType($element, 'EntitiesDescriptor', '@md') === true) {
             return self::processDescriptorsElement(new \SAML2\XML\md\EntitiesDescriptor($element));
         } else {
-            throw new Exception('Unexpected root node: ['.$element->namespaceURI.']:'.$element->localName);
+            throw new \Exception('Unexpected root node: ['.$element->namespaceURI.']:'.$element->localName);
         }
     }
 
@@ -364,20 +368,20 @@ class SimpleSAML_Metadata_SAMLParser
      * @param array                                                         $parentExtensions An optional array of
      *     extensions from the parent element.
      *
-     * @return SimpleSAML_Metadata_SAMLParser[] Array of SAMLParser instances.
+     * @return SAMLParser[] Array of SAMLParser instances.
      */
     private static function processDescriptorsElement(
         $element,
         $maxExpireTime = null,
-        array $validators = array(),
-        array $parentExtensions = array()
+        array $validators = [],
+        array $parentExtensions = []
     ) {
         assert($maxExpireTime === null || is_int($maxExpireTime));
 
         if ($element instanceof \SAML2\XML\md\EntityDescriptor) {
-            $ret = new SimpleSAML_Metadata_SAMLParser($element, $maxExpireTime, $validators, $parentExtensions);
-            $ret = array($ret->getEntityId() => $ret);
-            /** @var SimpleSAML_Metadata_SAMLParser[] $ret */
+            $ret = new SAMLParser($element, $maxExpireTime, $validators, $parentExtensions);
+            $ret = [$ret->getEntityId() => $ret];
+            /** @var SAMLParser[] $ret */
             return $ret;
         }
 
@@ -388,7 +392,7 @@ class SimpleSAML_Metadata_SAMLParser
 
         $validators[] = $element;
 
-        $ret = array();
+        $ret = [];
         foreach ($element->children as $child) {
             $ret += self::processDescriptorsElement($child, $expTime, $validators, $extensions);
         }
@@ -435,7 +439,7 @@ class SimpleSAML_Metadata_SAMLParser
 
     private function getMetadataCommon()
     {
-        $ret = array();
+        $ret = [];
         $ret['entityid'] = $this->entityId;
         $ret['entityDescriptor'] = $this->entityDescriptor;
 
@@ -490,7 +494,7 @@ class SimpleSAML_Metadata_SAMLParser
             $metadata['EntityAttributes'] = $this->entityAttributes;
 
             // check for entity categories
-            if (SimpleSAML\Utils\Config\Metadata::isHiddenFromDiscovery($metadata)) {
+            if (\SimpleSAML\Utils\Config\Metadata::isHiddenFromDiscovery($metadata)) {
                 $metadata['hide.from.discovery'] = true;
             }
         }
@@ -690,6 +694,12 @@ class SimpleSAML_Metadata_SAMLParser
         if (array_key_exists('attributes.NameFormat', $spd)) {
             $ret['attributes.NameFormat'] = $spd['attributes.NameFormat'];
         }
+        if (array_key_exists('attributes.index', $spd)) {
+            $ret['attributes.index'] = $spd['attributes.index'];
+        }
+        if (array_key_exists('attributes.isDefault', $spd)) {
+            $ret['attributes.isDefault'] = $spd['attributes.isDefault'];
+        }
 
         // add name & description
         if (array_key_exists('name', $spd)) {
@@ -826,7 +836,7 @@ class SimpleSAML_Metadata_SAMLParser
     {
         assert($expireTime === null || is_int($expireTime));
 
-        $ret = array();
+        $ret = [];
 
         $expireTime = self::getExpireTime($element, $expireTime);
 
@@ -838,7 +848,7 @@ class SimpleSAML_Metadata_SAMLParser
         $ret['protocols'] = $element->protocolSupportEnumeration;
 
         // process KeyDescriptor elements
-        $ret['keys'] = array();
+        $ret['keys'] = [];
         foreach ($element->KeyDescriptor as $kd) {
             $key = self::parseKeyDescriptor($kd);
             if ($key !== null) {
@@ -989,16 +999,16 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @return array An associative array with the extensions parsed.
      */
-    private static function processExtensions($element, $parentExtensions = array())
+    private static function processExtensions($element, $parentExtensions = [])
     {
-        $ret = array(
-            'scope'            => array(),
-            'tags'             => array(),
-            'EntityAttributes' => array(),
-            'RegistrationInfo' => array(),
-            'UIInfo'           => array(),
-            'DiscoHints'       => array(),
-        );
+        $ret = [
+            'scope'            => [],
+            'tags'             => [],
+            'EntityAttributes' => [],
+            'RegistrationInfo' => [],
+            'UIInfo'           => [],
+            'DiscoHints'       => [],
+        ];
 
         // Some extensions may get inherited from a parent element
         if (($element instanceof \SAML2\XML\md\EntityDescriptor || $element instanceof \SAML2\XML\md\EntitiesDescriptor)
@@ -1007,7 +1017,6 @@ class SimpleSAML_Metadata_SAMLParser
         }
 
         foreach ($element->Extensions as $e) {
-
             if ($e instanceof \SAML2\XML\shibmd\Scope) {
                 $ret['scope'][] = $e->scope;
                 continue;
@@ -1016,14 +1025,12 @@ class SimpleSAML_Metadata_SAMLParser
             // Entity Attributes are only allowed at entity level extensions and not at RoleDescriptor level
             if ($element instanceof \SAML2\XML\md\EntityDescriptor ||
                 $element instanceof \SAML2\XML\md\EntitiesDescriptor) {
-
-
                 if ($e instanceof \SAML2\XML\mdrpi\RegistrationInfo) {
                     // Registration Authority cannot be overridden (warn only if override attempts to change the value)
                     if (isset($ret['RegistrationInfo']['registrationAuthority'])
                         && $ret['RegistrationInfo']['registrationAuthority'] !== $e->registrationAuthority) {
-                        SimpleSAML\Logger::warning('Invalid attempt to override registrationAuthority \''
-                          . $ret['RegistrationInfo']['registrationAuthority'] . "' with '{$e->registrationAuthority}'");
+                        \SimpleSAML\Logger::warning('Invalid attempt to override registrationAuthority \''.
+                            $ret['RegistrationInfo']['registrationAuthority']."' with '{$e->registrationAuthority}'");
                     } else {
                         $ret['RegistrationInfo']['registrationAuthority'] = $e->registrationAuthority;
                     }
@@ -1045,7 +1052,7 @@ class SimpleSAML_Metadata_SAMLParser
                                 $name = '{'.$attr->NameFormat.'}'.$attr->Name;
                             }
 
-                            $values = array();
+                            $values = [];
                             foreach ($attr->AttributeValue as $attrvalue) {
                                 $values[] = $attrvalue->getString();
                             }
@@ -1059,7 +1066,6 @@ class SimpleSAML_Metadata_SAMLParser
             // UIInfo elements are only allowed at RoleDescriptor level extensions
             if ($element instanceof \SAML2\XML\md\RoleDescriptor) {
                 if ($e instanceof \SAML2\XML\mdui\UIInfo) {
-
                     $ret['UIInfo']['DisplayName'] = $e->DisplayName;
                     $ret['UIInfo']['Description'] = $e->Description;
                     $ret['UIInfo']['InformationURL'] = $e->InformationURL;
@@ -1082,11 +1088,11 @@ class SimpleSAML_Metadata_SAMLParser
                         ) {
                             continue;
                         }
-                        $logo = array(
+                        $logo = [
                             'url'    => $uiItem->url,
                             'height' => $uiItem->height,
                             'width'  => $uiItem->width,
-                        );
+                        ];
                         if (!empty($uiItem->lang)) {
                             $logo['lang'] = $uiItem->lang;
                         }
@@ -1097,7 +1103,6 @@ class SimpleSAML_Metadata_SAMLParser
 
             // DiscoHints elements are only allowed at IDPSSODescriptor level extensions
             if ($element instanceof \SAML2\XML\md\IDPSSODescriptor) {
-
                 if ($e instanceof \SAML2\XML\mdui\DiscoHints) {
                     $ret['DiscoHints']['IPHint'] = $e->IPHint;
                     $ret['DiscoHints']['DomainHint'] = $e->DomainHint;
@@ -1114,8 +1119,8 @@ class SimpleSAML_Metadata_SAMLParser
 
                 $name = $attribute->getAttribute('Name');
                 $values = array_map(
-                    array('SimpleSAML\Utils\XML', 'getDOMText'),
-                    SimpleSAML\Utils\XML::getDOMChildren($attribute, 'AttributeValue', '@saml2')
+                    ['\SimpleSAML\Utils\XML', 'getDOMText'],
+                    \SimpleSAML\Utils\XML::getDOMChildren($attribute, 'AttributeValue', '@saml2')
                 );
 
                 if ($name === 'tags') {
@@ -1152,7 +1157,7 @@ class SimpleSAML_Metadata_SAMLParser
 
     private function processContactPerson(\SAML2\XML\md\ContactPerson $element)
     {
-        $contactPerson = array();
+        $contactPerson = [];
         if (!empty($element->contactType)) {
             $contactPerson['contactType'] = $element->contactType;
         }
@@ -1191,8 +1196,8 @@ class SimpleSAML_Metadata_SAMLParser
         $sp['description'] = $element->ServiceDescription;
 
         $format = null;
-        $sp['attributes'] = array();
-        $sp['attributes.required'] = array();
+        $sp['attributes'] = [];
+        $sp['attributes.required'] = [];
         foreach ($element->RequestedAttribute as $child) {
             $attrname = $child->Name;
             $sp['attributes'][] = $attrname;
@@ -1244,7 +1249,7 @@ class SimpleSAML_Metadata_SAMLParser
      */
     private static function parseGenericEndpoint(\SAML2\XML\md\EndpointType $element)
     {
-        $ep = array();
+        $ep = [];
 
         $ep['Binding'] = $element->Binding;
         $ep['Location'] = $element->Location;
@@ -1274,7 +1279,7 @@ class SimpleSAML_Metadata_SAMLParser
      */
     private static function extractEndpoints(array $endpoints)
     {
-        $ret = array();
+        $ret = [];
         foreach ($endpoints as $ep) {
             $ret[] = self::parseGenericEndpoint($ep);
         }
@@ -1299,7 +1304,7 @@ class SimpleSAML_Metadata_SAMLParser
      */
     private static function parseKeyDescriptor(\SAML2\XML\md\KeyDescriptor $kd)
     {
-        $r = array();
+        $r = [];
 
         if ($kd->use === 'encryption') {
             $r['encryption'] = true;
@@ -1335,13 +1340,13 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param $protocols Array with the protocols we accept.
      *
-     * @return Array with SP descriptors which supports one of the given protocols.
+     * @return array with SP descriptors which supports one of the given protocols.
      */
     private function getSPDescriptors($protocols)
     {
         assert(is_array($protocols));
 
-        $ret = array();
+        $ret = [];
 
         foreach ($this->spDescriptors as $spd) {
             $sharedProtocols = array_intersect($protocols, $spd['protocols']);
@@ -1359,13 +1364,13 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * @param $protocols Array with the protocols we accept.
      *
-     * @return Array with IdP descriptors which supports one of the given protocols.
+     * @return array with IdP descriptors which supports one of the given protocols.
      */
     private function getIdPDescriptors($protocols)
     {
         assert(is_array($protocols));
 
-        $ret = array();
+        $ret = [];
 
         foreach ($this->idpDescriptors as $idpd) {
             $sharedProtocols = array_intersect($protocols, $idpd['protocols']);
@@ -1384,24 +1389,24 @@ class SimpleSAML_Metadata_SAMLParser
      *
      * This function will throw an exception if it is unable to locate the node.
      *
-     * @param DOMDocument $doc The DOMDocument where we should find the EntityDescriptor node.
+     * @param \DOMDocument $doc The \DOMDocument where we should find the EntityDescriptor node.
      *
-     * @return \SAML2\XML\md\EntityDescriptor The DOMEntity which represents the EntityDescriptor.
-     * @throws Exception If the document is empty or the first element is not an EntityDescriptor element.
+     * @return \SAML2\XML\md\EntityDescriptor The \DOMEntity which represents the EntityDescriptor.
+     * @throws \Exception If the document is empty or the first element is not an EntityDescriptor element.
      */
     private static function findEntityDescriptor($doc)
     {
-        assert($doc instanceof DOMDocument);
+        assert($doc instanceof \DOMDocument);
 
         // find the EntityDescriptor DOMElement. This should be the first (and only) child of the DOMDocument
         $ed = $doc->documentElement;
 
         if ($ed === null) {
-            throw new Exception('Failed to load SAML metadata from empty XML document.');
+            throw new \Exception('Failed to load SAML metadata from empty XML document.');
         }
 
-        if (SimpleSAML\Utils\XML::isDOMNodeOfType($ed, 'EntityDescriptor', '@md') === false) {
-            throw new Exception('Expected first element in the metadata document to be an EntityDescriptor element.');
+        if (\SimpleSAML\Utils\XML::isDOMNodeOfType($ed, 'EntityDescriptor', '@md') === false) {
+            throw new \Exception('Expected first element in the metadata document to be an EntityDescriptor element.');
         }
 
         return new \SAML2\XML\md\EntityDescriptor($ed);
@@ -1423,25 +1428,25 @@ class SimpleSAML_Metadata_SAMLParser
             assert(is_string($cert));
             $certFile = \SimpleSAML\Utils\Config::getCertPath($cert);
             if (!file_exists($certFile)) {
-                throw new Exception(
+                throw new \Exception(
                     'Could not find certificate file ['.$certFile.'], which is needed to validate signature'
                 );
             }
             $certData = file_get_contents($certFile);
 
             foreach ($this->validators as $validator) {
-                $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
+                $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'public']);
                 $key->loadKey($certData);
                 try {
                     if ($validator->validate($key)) {
                         return true;
                     }
-                } catch (Exception $e) {
+                } catch (\Exception $e) {
                     // this certificate did not sign this element, skip
                 }
             }
         }
-        SimpleSAML\Logger::debug('Could not validate signature');
+        \SimpleSAML\Logger::debug('Could not validate signature');
         return false;
     }
 
@@ -1461,10 +1466,9 @@ class SimpleSAML_Metadata_SAMLParser
 
         $fingerprint = strtolower(str_replace(":", "", $fingerprint));
 
-        $candidates = array();
+        $candidates = [];
         foreach ($this->validators as $validator) {
             foreach ($validator->getValidatingCertificates() as $cert) {
-
                 $fp = strtolower(sha1(base64_decode($cert)));
                 $candidates[] = $fp;
                 if ($fp === $fingerprint) {
@@ -1472,7 +1476,7 @@ class SimpleSAML_Metadata_SAMLParser
                 }
             }
         }
-        SimpleSAML\Logger::debug('Fingerprint was ['.$fingerprint.'] not one of ['.join(', ', $candidates).']');
+        \SimpleSAML\Logger::debug('Fingerprint was ['.$fingerprint.'] not one of ['.join(', ', $candidates).']');
         return false;
     }
 }
diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php
index 3d3f2eaf9601f7b4235029799076ac5d78afc76e..98806d56211f41baa0de73066681e07c8623549b 100644
--- a/lib/SimpleSAML/Metadata/Signer.php
+++ b/lib/SimpleSAML/Metadata/Signer.php
@@ -1,5 +1,9 @@
 <?php
 
+namespace SimpleSAML\Metadata;
+
+use RobRichards\XMLSecLibs\XMLSecurityKey;
+use RobRichards\XMLSecLibs\XMLSecurityDSig;
 
 /**
  * This class implements a helper function for signing of metadata.
@@ -7,16 +11,16 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Metadata_Signer
-{
 
+class Signer
+{
     /**
      * This functions finds what key & certificate files should be used to sign the metadata
      * for the given entity.
      *
-     * @param SimpleSAML_Configuration $config Our SimpleSAML_Configuration instance.
-     * @param array                    $entityMetadata The metadata of the entity.
-     * @param string                   $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or
+     * @param \SimpleSAML\Configuration $config Our \SimpleSAML\Configuration instance.
+     * @param array                     $entityMetadata The metadata of the entity.
+     * @param string                    $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or
      *     'Shib 1.3 SP'.
      *
      * @return array An associative array with the keys 'privatekey', 'certificate', and optionally 'privatekey_pass'.
@@ -28,12 +32,10 @@ class SimpleSAML_Metadata_Signer
         if (array_key_exists('metadata.sign.privatekey', $entityMetadata)
             || array_key_exists('metadata.sign.certificate', $entityMetadata)
         ) {
-
             if (!array_key_exists('metadata.sign.privatekey', $entityMetadata)
                 || !array_key_exists('metadata.sign.certificate', $entityMetadata)
             ) {
-
-                throw new Exception(
+                throw new \Exception(
                     'Missing either the "metadata.sign.privatekey" or the'.
                     ' "metadata.sign.certificate" configuration option in the metadata for'.
                     ' the '.$type.' "'.$entityMetadata['entityid'].'". If one of'.
@@ -41,10 +43,10 @@ class SimpleSAML_Metadata_Signer
                 );
             }
 
-            $ret = array(
+            $ret = [
                 'privatekey'  => $entityMetadata['metadata.sign.privatekey'],
                 'certificate' => $entityMetadata['metadata.sign.certificate']
-            );
+            ];
 
             if (array_key_exists('metadata.sign.privatekey_pass', $entityMetadata)) {
                 $ret['privatekey_pass'] = $entityMetadata['metadata.sign.privatekey_pass'];
@@ -58,14 +60,14 @@ class SimpleSAML_Metadata_Signer
         $certificate = $config->getString('metadata.sign.certificate', null);
         if ($privatekey !== null || $certificate !== null) {
             if ($privatekey === null || $certificate === null) {
-                throw new Exception(
+                throw new \Exception(
                     'Missing either the "metadata.sign.privatekey" or the'.
                     ' "metadata.sign.certificate" configuration option in the global'.
                     ' configuration. If one of these options is specified, then the other'.
                     ' must also be specified.'
                 );
             }
-            $ret = array('privatekey' => $privatekey, 'certificate' => $certificate);
+            $ret = ['privatekey' => $privatekey, 'certificate' => $certificate];
 
             $privatekey_pass = $config->getString('metadata.sign.privatekey_pass', null);
             if ($privatekey_pass !== null) {
@@ -79,11 +81,10 @@ class SimpleSAML_Metadata_Signer
         if (array_key_exists('privatekey', $entityMetadata)
             || array_key_exists('certificate', $entityMetadata)
         ) {
-
             if (!array_key_exists('privatekey', $entityMetadata)
                 || !array_key_exists('certificate', $entityMetadata)
             ) {
-                throw new Exception(
+                throw new \Exception(
                     'Both the "privatekey" and the "certificate" option must'.
                     ' be set in the metadata for the '.$type.' "'.
                     $entityMetadata['entityid'].'" before it is possible to sign metadata'.
@@ -91,10 +92,10 @@ class SimpleSAML_Metadata_Signer
                 );
             }
 
-            $ret = array(
+            $ret = [
                 'privatekey'  => $entityMetadata['privatekey'],
                 'certificate' => $entityMetadata['certificate']
-            );
+            ];
 
             if (array_key_exists('privatekey_pass', $entityMetadata)) {
                 $ret['privatekey_pass'] = $entityMetadata['privatekey_pass'];
@@ -103,7 +104,7 @@ class SimpleSAML_Metadata_Signer
             return $ret;
         }
 
-        throw new Exception(
+        throw new \Exception(
             'Could not find what key & certificate should be used to sign the metadata'.
             ' for the '.$type.' "'.$entityMetadata['entityid'].'".'
         );
@@ -113,20 +114,20 @@ class SimpleSAML_Metadata_Signer
     /**
      * Determine whether metadata signing is enabled for the given metadata.
      *
-     * @param SimpleSAML_Configuration $config Our SimpleSAML_Configuration instance.
-     * @param array                    $entityMetadata The metadata of the entity.
-     * @param string                   $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or
+     * @param \SimpleSAML\Configuration $config Our \SimpleSAML\Configuration instance.
+     * @param array                     $entityMetadata The metadata of the entity.
+     * @param string                    $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or
      *     'Shib 1.3 SP'.
      *
      * @return boolean True if metadata signing is enabled, false otherwise.
-     * @throws Exception If the value of the 'metadata.sign.enable' option is not a boolean.
+     * @throws \Exception If the value of the 'metadata.sign.enable' option is not a boolean.
      */
     private static function isMetadataSigningEnabled($config, $entityMetadata, $type)
     {
         // first check the metadata for the entity
         if (array_key_exists('metadata.sign.enable', $entityMetadata)) {
             if (!is_bool($entityMetadata['metadata.sign.enable'])) {
-                throw new Exception(
+                throw new \Exception(
                     'Invalid value for the "metadata.sign.enable" configuration option for'.
                     ' the '.$type.' "'.$entityMetadata['entityid'].'". This option'.
                     ' should be a boolean.'
@@ -148,7 +149,7 @@ class SimpleSAML_Metadata_Signer
      * This method will look for the 'metadata.sign.algorithm' key in the $entityMetadata array, or look for such
      * a configuration option in the $config object.
      *
-     * @param SimpleSAML_Configuration $config The global configuration.
+     * @param \SimpleSAML\Configuration $config The global configuration.
      * @param array $entityMetadata An array containing the metadata related to this entity.
      * @param string $type A string describing the type of entity. E.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
      *
@@ -156,8 +157,6 @@ class SimpleSAML_Metadata_Signer
      * algorithms to use, respectively.
      *
      * @throws \SimpleSAML\Error\CriticalConfigurationError
-     *
-     * @todo change to SHA256 by default.
      */
     private static function getMetadataSigningAlgorithm($config, $entityMetadata, $type)
     {
@@ -171,15 +170,15 @@ class SimpleSAML_Metadata_Signer
             }
             $alg = $entityMetadata['metadata.sign.algorithm'];
         } else {
-            $alg = $config->getString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA1);
+            $alg = $config->getString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA256);
         }
 
-        $supported_algs = array(
+        $supported_algs = [
             XMLSecurityKey::RSA_SHA1,
             XMLSecurityKey::RSA_SHA256,
             XMLSecurityKey::RSA_SHA384,
             XMLSecurityKey::RSA_SHA512,
-        );
+        ];
 
         if (!in_array($alg, $supported_algs, true)) {
             throw new \SimpleSAML\Error\CriticalConfigurationError("Unknown signature algorithm '$alg'");
@@ -199,10 +198,10 @@ class SimpleSAML_Metadata_Signer
                 $digest = XMLSecurityDSig::SHA1;
         }
 
-        return array(
+        return [
             'algorithm' => $alg,
             'digest' => $digest,
-        );
+        ];
     }
 
 
@@ -214,11 +213,11 @@ class SimpleSAML_Metadata_Signer
      * @param string $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
      *
      * @return string The $metadataString with the signature embedded.
-     * @throws Exception If the certificate or private key cannot be loaded, or the metadata doesn't parse properly.
+     * @throws \Exception If the certificate or private key cannot be loaded, or the metadata doesn't parse properly.
      */
     public static function sign($metadataString, $entityMetadata, $type)
     {
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = \SimpleSAML\Configuration::getInstance();
 
         // check if metadata signing is enabled
         if (!self::isMetadataSigningEnabled($config, $entityMetadata, $type)) {
@@ -230,13 +229,15 @@ class SimpleSAML_Metadata_Signer
 
         $keyFile = \SimpleSAML\Utils\Config::getCertPath($keyCertFiles['privatekey']);
         if (!file_exists($keyFile)) {
-            throw new Exception('Could not find private key file ['.$keyFile.'], which is needed to sign the metadata');
+            throw new \Exception(
+                'Could not find private key file ['.$keyFile.'], which is needed to sign the metadata'
+            );
         }
         $keyData = file_get_contents($keyFile);
 
         $certFile = \SimpleSAML\Utils\Config::getCertPath($keyCertFiles['certificate']);
         if (!file_exists($certFile)) {
-            throw new Exception(
+            throw new \Exception(
                 'Could not find certificate file ['.$certFile.'], which is needed to sign the metadata'
             );
         }
@@ -246,14 +247,14 @@ class SimpleSAML_Metadata_Signer
         // convert the metadata to a DOM tree
         try {
             $xml = \SAML2\DOMDocumentFactory::fromString($metadataString);
-        } catch(Exception $e) {
-            throw new Exception('Error parsing self-generated metadata.');
+        } catch (\Exception $e) {
+            throw new \Exception('Error parsing self-generated metadata.');
         }
 
         $signature_cf = self::getMetadataSigningAlgorithm($config, $entityMetadata, $type);
 
         // load the private key
-        $objKey = new XMLSecurityKey($signature_cf['algorithm'], array('type' => 'private'));
+        $objKey = new XMLSecurityKey($signature_cf['algorithm'], ['type' => 'private']);
         if (array_key_exists('privatekey_pass', $keyCertFiles)) {
             $objKey->passphrase = $keyCertFiles['privatekey_pass'];
         }
@@ -268,10 +269,10 @@ class SimpleSAML_Metadata_Signer
         $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
 
         $objXMLSecDSig->addReferenceList(
-            array($rootNode),
+            [$rootNode],
             $signature_cf['digest'],
-            array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
-            array('id_name' => 'ID')
+            ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N],
+            ['id_name' => 'ID']
         );
 
         $objXMLSecDSig->sign($objKey);
diff --git a/lib/SimpleSAML/Metadata/Sources/MDQ.php b/lib/SimpleSAML/Metadata/Sources/MDQ.php
index 975f79246690ff581b83b376ca4d874ef2fe6aa7..413846427709d87e28bfeebec1b4148ba0b85fb9 100644
--- a/lib/SimpleSAML/Metadata/Sources/MDQ.php
+++ b/lib/SimpleSAML/Metadata/Sources/MDQ.php
@@ -13,9 +13,9 @@ use SimpleSAML\Utils\HTTP;
  * @author Tamas Frank, NIIFI
  * @package SimpleSAMLphp
  */
-class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
-{
 
+class MDQ extends \SimpleSAML\Metadata\MetaDataStorageSource
+{
     /**
      * The URL of MDQ server (url:port)
      *
@@ -80,7 +80,7 @@ class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
         }
 
         if (array_key_exists('cachedir', $config)) {
-            $globalConfig = \SimpleSAML_Configuration::getInstance();
+            $globalConfig = \SimpleSAML\Configuration::getInstance();
             $this->cacheDir = $globalConfig->resolvePath($config['cachedir']);
         } else {
             $this->cacheDir = null;
@@ -104,7 +104,7 @@ class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
     public function getMetadataSet($set)
     {
         // we don't have this metadata set
-        return array();
+        return [];
     }
 
 
@@ -216,13 +216,13 @@ class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
     /**
      * Retrieve metadata for the correct set from a SAML2Parser.
      *
-     * @param \SimpleSAML_Metadata_SAMLParser $entity A SAML2Parser representing an entity.
+     * @param \SimpleSAML\Metadata\SAMLParser $entity A SAML2Parser representing an entity.
      * @param string                         $set The metadata set we are looking for.
      *
      * @return array|NULL  The associative array with the metadata, or NULL if no metadata for
      *                     the given set was found.
      */
-    private static function getParsedSet(\SimpleSAML_Metadata_SAMLParser $entity, $set)
+    private static function getParsedSet(\SimpleSAML\Metadata\SAMLParser $entity, $set)
     {
         assert(is_string($set));
 
@@ -248,7 +248,7 @@ class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
 
 
     /**
-     * Overriding this function from the superclass SimpleSAML_Metadata_MetaDataStorageSource.
+     * Overriding this function from the superclass \SimpleSAML\Metadata\MetaDataStorageSource.
      *
      * This function retrieves metadata for the given entity id in the given set of metadata.
      * It will return NULL if it is unable to locate the metadata.
@@ -311,7 +311,7 @@ class MDQ extends \SimpleSAML_Metadata_MetaDataStorageSource
         }
 
         /** @var string $xmldata */
-        $entity = \SimpleSAML_Metadata_SAMLParser::parseString($xmldata);
+        $entity = \SimpleSAML\Metadata\SAMLParser::parseString($xmldata);
         Logger::debug(__CLASS__.': completed parsing of ['.$mdq_url.']');
 
         if ($this->validateFingerprint !== null) {
diff --git a/lib/SimpleSAML/Module.php b/lib/SimpleSAML/Module.php
index 6c9b3c6e0e9f7052f1ce9ea2105ee7fa2e5364fb..9668a367306afef04e8a10f8cd7561d925456fdc 100644
--- a/lib/SimpleSAML/Module.php
+++ b/lib/SimpleSAML/Module.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace SimpleSAML;
 
 /**
@@ -11,20 +12,19 @@ namespace SimpleSAML;
  */
 class Module
 {
-
     /**
      * A list containing the modules currently installed.
      *
      * @var array
      */
-    public static $modules = array();
+    public static $modules = [];
 
     /**
      * A cache containing specific information for modules, like whether they are enabled or not, or their hooks.
      *
      * @var array
      */
-    public static $module_info = array();
+    public static $module_info = [];
 
 
     /**
@@ -58,8 +58,8 @@ class Module
      */
     public static function isModuleEnabled($module)
     {
-        $config = \SimpleSAML_Configuration::getOptionalConfig();
-        return self::isModuleEnabledWithConf($module, $config->getArray('module.enable', array()));
+        $config = Configuration::getOptionalConfig();
+        return self::isModuleEnabledWithConf($module, $config->getArray('module.enable', []));
     }
 
 
@@ -152,7 +152,7 @@ class Module
      *
      * This function takes a string on the form "<module>:<class>" and converts it to a class
      * name. It can also check that the given class is a subclass of a specific class. The
-     * resolved classname will be "sspmod_<module>_<$type>_<class>.
+     * resolved classname will be "\SimleSAML\Module\<module>\<$type>\<class>.
      *
      * It is also possible to specify a full classname instead of <module>:<class>.
      *
@@ -173,12 +173,14 @@ class Module
         assert(is_string($subclass) || $subclass === null);
 
         $tmp = explode(':', $id, 2);
-        if (count($tmp) === 1) { // no module involved
+        if (count($tmp) === 1) {
+            // no module involved
             $className = $tmp[0];
             if (!class_exists($className)) {
                 throw new \Exception("Could not resolve '$id': no class named '$className'.");
             }
-        } else { // should be a module
+        } else {
+            // should be a module
             // make sure empty types are handled correctly
             $type = (empty($type)) ? '_' : '_'.$type.'_';
 
@@ -217,7 +219,7 @@ class Module
      *
      * @return string The absolute URL to the given resource.
      */
-    public static function getModuleURL($resource, array $parameters = array())
+    public static function getModuleURL($resource, array $parameters = [])
     {
         assert(is_string($resource));
         assert($resource[0] !== '/');
@@ -247,10 +249,10 @@ class Module
 
         $hook_dir = self::getModuleDir($module).'/hooks';
         if (!is_dir($hook_dir)) {
-            return array();
+            return [];
         }
 
-        $hooks = array();
+        $hooks = [];
         $files = scandir($hook_dir);
         foreach ($files as $file) {
             if ($file[0] === '.') {
@@ -262,7 +264,7 @@ class Module
             }
             $hook_name = $matches[1];
             $hook_func = $module.'_hook_'.$hook_name;
-            $hooks[$hook_name] = array('file' => $hook_dir.'/'.$file, 'func' => $hook_func);
+            $hooks[$hook_name] = ['file' => $hook_dir.'/'.$file, 'func' => $hook_func];
         }
         return $hooks;
     }
@@ -276,14 +278,14 @@ class Module
      * @param string $hook The name of the hook.
      * @param mixed  &$data The data which should be passed to each hook. Will be passed as a reference.
      *
-     * @throws \SimpleSAML_Error_Exception If an invalid hook is found in a module.
+     * @throws \SimpleSAML\Error\Exception If an invalid hook is found in a module.
      */
     public static function callHooks($hook, &$data = null)
     {
         assert(is_string($hook));
 
         $modules = self::getModules();
-        $config = \SimpleSAML_Configuration::getOptionalConfig()->getArray('module.enable', array());
+        $config = Configuration::getOptionalConfig()->getArray('module.enable', []);
         sort($modules);
         foreach ($modules as $module) {
             if (!self::isModuleEnabledWithConf($module, $config)) {
@@ -301,7 +303,7 @@ class Module
             require_once(self::$module_info[$module]['hooks'][$hook]['file']);
 
             if (!is_callable(self::$module_info[$module]['hooks'][$hook]['func'])) {
-                throw new \SimpleSAML_Error_Exception('Invalid hook \''.$hook.'\' for module \''.$module.'\'.');
+                throw new \SimpleSAML\Error\Exception('Invalid hook \''.$hook.'\' for module \''.$module.'\'.');
             }
 
             $fn = self::$module_info[$module]['hooks'][$hook]['func'];
diff --git a/lib/SimpleSAML/Session.php b/lib/SimpleSAML/Session.php
index f7bb281fb39fda37305476d8e132b2c0f03b5969..518f16294ade68b796b2141ac54186ac85fae9e3 100644
--- a/lib/SimpleSAML/Session.php
+++ b/lib/SimpleSAML/Session.php
@@ -1,4 +1,9 @@
 <?php
+
+namespace SimpleSAML;
+
+use SimpleSAML\Error;
+
 /**
  * The Session class holds information about a user session, and everything attached to it.
  *
@@ -16,9 +21,9 @@
  * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Session implements Serializable
-{
 
+class Session implements \Serializable
+{
     /**
      * This is a timeout value for setData, which indicates that the data
      * should never be deleted, i.e. lasts the whole session lifetime.
@@ -33,17 +38,16 @@ class SimpleSAML_Session implements Serializable
      *
      * @var array
      */
-    private static $sessions = array();
+    private static $sessions = [];
 
 
     /**
      * This variable holds the instance of the session - Singleton approach.
      *
-     * Warning: do not set the instance manually, call SimpleSAML_Session::load() instead.
+     * Warning: do not set the instance manually, call Session::load() instead.
      */
     private static $instance = null;
 
-
     /**
      * The session ID of this session.
      *
@@ -51,7 +55,6 @@ class SimpleSAML_Session implements Serializable
      */
     private $sessionId;
 
-
     /**
      * Transient session flag.
      *
@@ -59,7 +62,6 @@ class SimpleSAML_Session implements Serializable
      */
     private $transient = false;
 
-
     /**
      * The track id is a new random unique identifier that is generated for each session.
      * This is used in the debug logs and error messages to easily track more information
@@ -69,10 +71,11 @@ class SimpleSAML_Session implements Serializable
      */
     private $trackid = null;
 
-
+    /**
+     * @var integer|null
+     */
     private $rememberMeExpire = null;
 
-
     /**
      * Marks a session as modified, and therefore needs to be saved before destroying
      * this object.
@@ -81,7 +84,6 @@ class SimpleSAML_Session implements Serializable
      */
     private $dirty = false;
 
-
     /**
      * Tells the session object that the save callback has been registered and there's no need to register it again.
      *
@@ -89,7 +91,6 @@ class SimpleSAML_Session implements Serializable
      */
     private $callback_registered = false;
 
-
     /**
      * This is an array of objects which will expire automatically after a set time. It is used
      * where one needs to store some information - for example a logout request, but doesn't
@@ -100,8 +101,7 @@ class SimpleSAML_Session implements Serializable
      *
      * @var array
      */
-    private $dataStore = null;
-
+    private $dataStore = [];
 
     /**
      * The list of IdP-SP associations.
@@ -111,8 +111,7 @@ class SimpleSAML_Session implements Serializable
      *
      * @var array
      */
-    private $associations = array();
-
+    private $associations = [];
 
     /**
      * The authentication token.
@@ -123,7 +122,6 @@ class SimpleSAML_Session implements Serializable
      */
     private $authToken;
 
-
     /**
      * Authentication data.
      *
@@ -131,8 +129,7 @@ class SimpleSAML_Session implements Serializable
      *
      * @var array  Associative array of associative arrays.
      */
-    private $authData = array();
-
+    private $authData = [];
 
     /**
      * Private constructor that restricts instantiation to either getSessionFromRequest() for the current session or
@@ -144,15 +141,16 @@ class SimpleSAML_Session implements Serializable
     {
         if (php_sapi_name() === 'cli' || defined('STDIN')) {
             $this->trackid = 'CL'.bin2hex(openssl_random_pseudo_bytes(4));
-            SimpleSAML\Logger::setTrackId($this->trackid);
+            Logger::setTrackId($this->trackid);
             $this->transient = $transient;
             return;
         }
 
-        if ($transient) { // transient session
-            $sh = \SimpleSAML\SessionHandler::getSessionHandler();
+        if ($transient) {
+            // transient session
+            $sh = SessionHandler::getSessionHandler();
             $this->trackid = 'TR'.bin2hex(openssl_random_pseudo_bytes(4));
-            SimpleSAML\Logger::setTrackId($this->trackid);
+            Logger::setTrackId($this->trackid);
             $this->transient = true;
 
             /*
@@ -163,19 +161,20 @@ class SimpleSAML_Session implements Serializable
             if ($this->sessionId === null) {
                 $this->sessionId = $sh->newSessionId();
             }
-        } else { // regular session
-            $sh = \SimpleSAML\SessionHandler::getSessionHandler();
+        } else {
+            // regular session
+            $sh = SessionHandler::getSessionHandler();
             $this->sessionId = $sh->newSessionId();
             $sh->setCookie($sh->getSessionCookieName(), $this->sessionId, $sh->getCookieParams());
 
 
             $this->trackid = bin2hex(openssl_random_pseudo_bytes(5));
-            SimpleSAML\Logger::setTrackId($this->trackid);
+            Logger::setTrackId($this->trackid);
 
             $this->markDirty();
 
             // initialize data for session check function if defined
-            $globalConfig = SimpleSAML_Configuration::getInstance();
+            $globalConfig = Configuration::getInstance();
             $checkFunction = $globalConfig->getArray('session.check_function', null);
             if (isset($checkFunction)) {
                 assert(is_callable($checkFunction));
@@ -184,7 +183,6 @@ class SimpleSAML_Session implements Serializable
         }
     }
 
-
     /**
      * Serialize this session object.
      *
@@ -198,7 +196,6 @@ class SimpleSAML_Session implements Serializable
         return $serialized;
     }
 
-
     /**
      * Unserialize a session object and load it..
      *
@@ -223,7 +220,8 @@ class SimpleSAML_Session implements Serializable
             }
 
             foreach ($parameters['RawAttributes'] as $attribute => $values) {
-                foreach ($values as $idx => $value) { // this should be originally a DOMNodeList
+                foreach ($values as $idx => $value) {
+                    // this should be originally a DOMNodeList
                     /* @var \SAML2\XML\saml\AttributeValue $value */
                     $this->authData[$authority]['Attributes'][$attribute][$idx] = $value->element->childNodes;
                 }
@@ -231,12 +229,11 @@ class SimpleSAML_Session implements Serializable
         }
     }
 
-
     /**
      * Retrieves the current session. Creates a new session if there's not one.
      *
-     * @return SimpleSAML_Session The current session.
-     * @throws Exception When session couldn't be initialized and the session fallback is disabled by configuration.
+     * @return Session The current session.
+     * @throws \Exception When session couldn't be initialized and the session fallback is disabled by configuration.
      */
     public static function getSessionFromRequest()
     {
@@ -246,21 +243,20 @@ class SimpleSAML_Session implements Serializable
         }
 
         // check if we have stored a session stored with the session handler
-        $session = null;
         try {
             $session = self::getSession();
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             /*
              * For some reason, we were unable to initialize this session. Note that this error might be temporary, and
              * it's possible that we can recover from it in subsequent requests, so we should not try to create a new
              * session here. Therefore, use just a transient session and throw the exception for someone else to handle
              * it.
              */
-            SimpleSAML\Logger::error('Error loading session: '.$e->getMessage());
+            Logger::error('Error loading session: '.$e->getMessage());
             self::useTransientSession();
-            if ($e instanceof SimpleSAML_Error_Exception) {
+            if ($e instanceof Error\Exception) {
                 $cause = $e->getCause();
-                if ($cause instanceof Exception) {
+                if ($cause instanceof \Exception) {
                     throw $cause;
                 }
             }
@@ -268,7 +264,7 @@ class SimpleSAML_Session implements Serializable
         }
 
         // if getSession() found it, use it
-        if ($session instanceof SimpleSAML_Session) {
+        if ($session instanceof Session) {
             return self::load($session);
         }
 
@@ -284,20 +280,20 @@ class SimpleSAML_Session implements Serializable
 
         // try to create a new session
         try {
-            self::load(new SimpleSAML_Session());
-        } catch (\SimpleSAML\Error\CannotSetCookie $e) {
+            self::load(new Session());
+        } catch (Error\CannotSetCookie $e) {
             // can't create a regular session because we can't set cookies. Use transient.
-            $c = SimpleSAML_Configuration::getInstance();
+            $c = Configuration::getInstance();
             self::useTransientSession();
 
-            if ($e->getCode() === \SimpleSAML\Error\CannotSetCookie::SECURE_COOKIE) {
-                throw new \SimpleSAML\Error\CriticalConfigurationError(
+            if ($e->getCode() === Error\CannotSetCookie::SECURE_COOKIE) {
+                throw new Error\CriticalConfigurationError(
                     $e->getMessage(),
                     null,
                     $c->toArray()
                 );
             }
-            SimpleSAML\Logger::error('Error creating session: '.$e->getMessage());
+            Logger::error('Error creating session: '.$e->getMessage());
         }
 
         // we must have a session now, either regular or transient
@@ -309,14 +305,14 @@ class SimpleSAML_Session implements Serializable
      *
      * @param string|null $sessionId The session we should get, or null to get the current session.
      *
-     * @return SimpleSAML_Session|null The session that is stored in the session handler, or null if the session wasn't
+     * @return Session|null The session that is stored in the session handler, or null if the session wasn't
      * found.
      */
     public static function getSession($sessionId = null)
     {
         assert(is_string($sessionId) || $sessionId === null);
 
-        $sh = \SimpleSAML\SessionHandler::getSessionHandler();
+        $sh = SessionHandler::getSessionHandler();
 
         if ($sessionId === null) {
             $checkToken = true;
@@ -340,7 +336,7 @@ class SimpleSAML_Session implements Serializable
         assert($session instanceof self);
 
         if ($checkToken) {
-            $globalConfig = SimpleSAML_Configuration::getInstance();
+            $globalConfig = Configuration::getInstance();
 
             if ($session->authToken !== null) {
                 $authTokenCookieName = $globalConfig->getString(
@@ -348,11 +344,11 @@ class SimpleSAML_Session implements Serializable
                     'SimpleSAMLAuthToken'
                 );
                 if (!isset($_COOKIE[$authTokenCookieName])) {
-                    SimpleSAML\Logger::warning('Missing AuthToken cookie.');
+                    Logger::warning('Missing AuthToken cookie.');
                     return null;
                 }
-                if (!SimpleSAML\Utils\Crypto::secureCompare($session->authToken, $_COOKIE[$authTokenCookieName])) {
-                    SimpleSAML\Logger::warning('Invalid AuthToken cookie.');
+                if (!Utils\Crypto::secureCompare($session->authToken, $_COOKIE[$authTokenCookieName])) {
+                    Logger::warning('Invalid AuthToken cookie.');
                     return null;
                 }
             }
@@ -363,7 +359,7 @@ class SimpleSAML_Session implements Serializable
                 assert(is_callable($checkFunction));
                 $check = call_user_func($checkFunction, $session);
                 if ($check !== true) {
-                    SimpleSAML\Logger::warning('Session did not pass check function.');
+                    Logger::warning('Session did not pass check function.');
                     return null;
                 }
             }
@@ -374,7 +370,6 @@ class SimpleSAML_Session implements Serializable
         return $session;
     }
 
-
     /**
      * Load a given session as the current one.
      *
@@ -382,12 +377,12 @@ class SimpleSAML_Session implements Serializable
      *
      * Warning: never set self::$instance yourself, call this method instead.
      *
-     * @param SimpleSAML_Session $session The session to load.
-     * @return SimpleSAML_Session The session we just loaded, just for convenience.
+     * @param Session $session The session to load.
+     * @return Session The session we just loaded, just for convenience.
      */
-    private static function load(SimpleSAML_Session $session)
+    private static function load(Session $session)
     {
-        SimpleSAML\Logger::setTrackId($session->getTrackID());
+        Logger::setTrackId($session->getTrackID());
         self::$instance = $session;
         return self::$instance;
     }
@@ -405,7 +400,7 @@ class SimpleSAML_Session implements Serializable
             return;
         }
 
-        self::load(new SimpleSAML_Session(true));
+        self::load(new Session(true));
     }
 
     /**
@@ -437,20 +432,19 @@ class SimpleSAML_Session implements Serializable
         $this->dirty = false;
         $this->callback_registered = false;
 
-        $sh = \SimpleSAML\SessionHandler::getSessionHandler();
+        $sh = SessionHandler::getSessionHandler();
 
         try {
             $sh->saveSession($this);
-        } catch (Exception $e) {
-            if (!($e instanceof SimpleSAML_Error_Exception)) {
-                $e = new SimpleSAML_Error_UnserializableException($e);
+        } catch (\Exception $e) {
+            if (!($e instanceof Error\Exception)) {
+                $e = new Error\UnserializableException($e);
             }
-            SimpleSAML\Logger::error('Unable to save session.');
+            Logger::error('Unable to save session.');
             $e->logError();
         }
     }
 
-
     /**
      * Save the current session and clean any left overs that could interfere with the normal application behaviour.
      *
@@ -460,13 +454,12 @@ class SimpleSAML_Session implements Serializable
     public function cleanup()
     {
         $this->save();
-        $sh = \SimpleSAML\SessionHandler::getSessionHandler();
-        if ($sh instanceof \SimpleSAML\SessionHandlerPHP) {
+        $sh = SessionHandler::getSessionHandler();
+        if ($sh instanceof SessionHandlerPHP) {
             $sh->restorePrevious();
         }
     }
 
-
     /**
      * Mark this session as dirty.
      *
@@ -484,10 +477,9 @@ class SimpleSAML_Session implements Serializable
             // we already have a shutdown callback registered for this object, no need to add another one
             return;
         }
-        $this->callback_registered = header_register_callback(array($this, 'save'));
+        $this->callback_registered = header_register_callback([$this, 'save']);
     }
 
-
     /**
      * Destroy the session.
      *
@@ -550,12 +542,12 @@ class SimpleSAML_Session implements Serializable
         assert(is_int($expire) || $expire === null);
 
         if ($expire === null) {
-            $globalConfig = SimpleSAML_Configuration::getInstance();
+            $globalConfig = Configuration::getInstance();
             $expire = time() + $globalConfig->getInteger('session.rememberme.lifetime', 14 * 86400);
         }
         $this->rememberMeExpire = $expire;
 
-        $cookieParams = array('expire' => $this->rememberMeExpire);
+        $cookieParams = ['expire' => $this->rememberMeExpire];
         $this->updateSessionCookies($cookieParams);
     }
 
@@ -567,14 +559,14 @@ class SimpleSAML_Session implements Serializable
      * @param string     $authority The authority the user logged in with.
      * @param array|null $data The authentication data for this authority.
      *
-     * @throws \SimpleSAML\Error\CannotSetCookie If the authentication token cannot be set for some reason.
+     * @throws Error\CannotSetCookie If the authentication token cannot be set for some reason.
      */
     public function doLogin($authority, array $data = null)
     {
         assert(is_string($authority));
         assert(is_array($data) || $data === null);
 
-        SimpleSAML\Logger::debug('Session: doLogin("'.$authority.'")');
+        Logger::debug('Session: doLogin("'.$authority.'")');
 
         $this->markDirty();
 
@@ -584,12 +576,12 @@ class SimpleSAML_Session implements Serializable
         }
 
         if ($data === null) {
-            $data = array();
+            $data = [];
         }
 
         $data['Authority'] = $authority;
 
-        $globalConfig = SimpleSAML_Configuration::getInstance();
+        $globalConfig = Configuration::getInstance();
         if (!isset($data['AuthnInstant'])) {
             $data['AuthnInstant'] = time();
         }
@@ -625,22 +617,21 @@ class SimpleSAML_Session implements Serializable
 
         $this->authData[$authority] = $data;
 
-        $this->authToken = SimpleSAML\Utils\Random::generateID();
-        $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+        $this->authToken = Utils\Random::generateID();
+        $sessionHandler = SessionHandler::getSessionHandler();
 
         if (!$this->transient && (!empty($data['RememberMe']) || $this->rememberMeExpire) &&
             $globalConfig->getBoolean('session.rememberme.enable', false)
         ) {
-
             $this->setRememberMeExpire();
         } else {
             try {
-                SimpleSAML\Utils\HTTP::setCookie(
+                Utils\HTTP::setCookie(
                     $globalConfig->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
                     $this->authToken,
                     $sessionHandler->getCookieParams()
                 );
-            } catch (SimpleSAML\Error\CannotSetCookie $e) {
+            } catch (Error\CannotSetCookie $e) {
                 /*
                  * Something went wrong when setting the auth token. We cannot recover from this, so we better log a
                  * message and throw an exception. The user is not properly logged in anyway, so clear all login
@@ -648,7 +639,7 @@ class SimpleSAML_Session implements Serializable
                  */
                 unset($this->authToken);
                 unset($this->authData[$authority]);
-                \SimpleSAML\Logger::error('Cannot set authentication token cookie: '.$e->getMessage());
+                Logger::error('Cannot set authentication token cookie: '.$e->getMessage());
                 throw $e;
             }
         }
@@ -663,10 +654,10 @@ class SimpleSAML_Session implements Serializable
      */
     public function doLogout($authority)
     {
-        SimpleSAML\Logger::debug('Session: doLogout('.var_export($authority, true).')');
+        Logger::debug('Session: doLogout('.var_export($authority, true).')');
 
         if (!isset($this->authData[$authority])) {
-            SimpleSAML\Logger::debug('Session: Already logged out of '.$authority.'.');
+            Logger::debug('Session: Already logged out of '.$authority.'.');
             return;
         }
 
@@ -686,7 +677,7 @@ class SimpleSAML_Session implements Serializable
      *
      * @param string $authority The authentication source we are logging out from.
      *
-     * @throws Exception If the handler is not a valid function or method.
+     * @throws \Exception If the handler is not a valid function or method.
      */
     private function callLogoutHandlers($authority)
     {
@@ -702,7 +693,7 @@ class SimpleSAML_Session implements Serializable
                 $classname = $handler[0];
                 $functionname = $handler[1];
 
-                throw new Exception(
+                throw new \Exception(
                     'Logout handler is not a valid function: '.$classname.'::'.
                     $functionname
                 );
@@ -722,14 +713,14 @@ class SimpleSAML_Session implements Serializable
      *
      * @param string $authority The authentication source that the user should be authenticated with.
      *
-     * @return true if the user has a valid session, false if not.
+     * @return bool True if the user has a valid session, false if not.
      */
     public function isValid($authority)
     {
         assert(is_string($authority));
 
         if (!isset($this->authData[$authority])) {
-            SimpleSAML\Logger::debug(
+            Logger::debug(
                 'Session: '.var_export($authority, true).
                 ' not valid because we are not authenticated.'
             );
@@ -737,11 +728,11 @@ class SimpleSAML_Session implements Serializable
         }
 
         if ($this->authData[$authority]['Expire'] <= time()) {
-            SimpleSAML\Logger::debug('Session: '.var_export($authority, true).' not valid because it is expired.');
+            Logger::debug('Session: '.var_export($authority, true).' not valid because it is expired.');
             return false;
         }
 
-        SimpleSAML\Logger::debug('Session: Valid session found with '.var_export($authority, true).'.');
+        Logger::debug('Session: Valid session found with '.var_export($authority, true).'.');
 
         return true;
     }
@@ -753,15 +744,19 @@ class SimpleSAML_Session implements Serializable
      */
     public function updateSessionCookies($params = null)
     {
-        $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+        assert(is_null($params) || is_array($params));
+
+        $sessionHandler = SessionHandler::getSessionHandler();
 
         if ($this->sessionId !== null) {
             $sessionHandler->setCookie($sessionHandler->getSessionCookieName(), $this->sessionId, $params);
         }
 
+        $params = array_merge($sessionHandler->getCookieParams(), is_array($params) ? $params : []);
+
         if ($this->authToken !== null) {
-            $globalConfig = SimpleSAML_Configuration::getInstance();
-            \SimpleSAML\Utils\HTTP::setCookie(
+            $globalConfig = Configuration::getInstance();
+            Utils\HTTP::setCookie(
                 $globalConfig->getString('session.authtoken.cookiename', 'SimpleSAMLAuthToken'),
                 $this->authToken,
                 $params
@@ -783,7 +778,7 @@ class SimpleSAML_Session implements Serializable
         $this->markDirty();
 
         if ($expire === null) {
-            $globalConfig = SimpleSAML_Configuration::getInstance();
+            $globalConfig = Configuration::getInstance();
             $expire = time() + $globalConfig->getInteger('session.duration', 8 * 60 * 60);
         }
 
@@ -797,17 +792,17 @@ class SimpleSAML_Session implements Serializable
      * @param string $classname The class which contains the logout handler.
      * @param string $functionname The logout handler function.
      *
-     * @throws Exception If the handler is not a valid function or method.
+     * @throws \Exception If the handler is not a valid function or method.
      */
     public function registerLogoutHandler($authority, $classname, $functionname)
     {
         assert(isset($this->authData[$authority]));
 
-        $logout_handler = array($classname, $functionname);
+        $logout_handler = [$classname, $functionname];
 
         if (!is_callable($logout_handler)) {
-            throw new Exception(
-                'Logout handler is not a vaild function: '.$classname.'::'.
+            throw new \Exception(
+                'Logout handler is not a valid function: '.$classname.'::'.
                 $functionname
             );
         }
@@ -829,10 +824,6 @@ class SimpleSAML_Session implements Serializable
         assert(is_string($type));
         assert(is_string($id));
 
-        if (!is_array($this->dataStore)) {
-            return;
-        }
-
         if (!array_key_exists($type, $this->dataStore)) {
             return;
         }
@@ -844,17 +835,17 @@ class SimpleSAML_Session implements Serializable
     /**
      * This function stores data in the data store.
      *
-     * The timeout value can be SimpleSAML_Session::DATA_TIMEOUT_SESSION_END, which indicates
+     * The timeout value can be Session::DATA_TIMEOUT_SESSION_END, which indicates
      * that the data should never be deleted.
      *
      * @param string   $type The type of the data. This is checked when retrieving data from the store.
      * @param string   $id The identifier of the data.
      * @param mixed    $data The data.
-     * @param int|null $timeout The number of seconds this data should be stored after its last access.
+     * @param int|string|null $timeout The number of seconds this data should be stored after its last access.
      * This parameter is optional. The default value is set in 'session.datastore.timeout',
      * and the default is 4 hours.
      *
-     * @throws Exception If the data couldn't be stored.
+     * @throws \Exception If the data couldn't be stored.
      *
      */
     public function setData($type, $id, $data, $timeout = null)
@@ -868,12 +859,12 @@ class SimpleSAML_Session implements Serializable
 
         if ($timeout === null) {
             // use the default timeout
-            $configuration = SimpleSAML_Configuration::getInstance();
+            $configuration = Configuration::getInstance();
 
             $timeout = $configuration->getInteger('session.datastore.timeout', null);
             if ($timeout !== null) {
                 if ($timeout <= 0) {
-                    throw new Exception(
+                    throw new \Exception(
                         'The value of the session.datastore.timeout'.
                         ' configuration option should be a positive integer.'
                     );
@@ -887,18 +878,14 @@ class SimpleSAML_Session implements Serializable
             $expires = time() + $timeout;
         }
 
-        $dataInfo = array(
+        $dataInfo = [
             'expires' => $expires,
             'timeout' => $timeout,
             'data'    => $data
-        );
-
-        if (!is_array($this->dataStore)) {
-            $this->dataStore = array();
-        }
+        ];
 
         if (!array_key_exists($type, $this->dataStore)) {
-            $this->dataStore[$type] = array();
+            $this->dataStore[$type] = [];
         }
 
         $this->dataStore[$type][$id] = $dataInfo;
@@ -915,10 +902,6 @@ class SimpleSAML_Session implements Serializable
      */
     private function expireData()
     {
-        if (!is_array($this->dataStore)) {
-            return;
-        }
-
         $ct = time();
 
         foreach ($this->dataStore as &$typedData) {
@@ -957,10 +940,6 @@ class SimpleSAML_Session implements Serializable
 
         $this->expireData();
 
-        if (!is_array($this->dataStore)) {
-            return null;
-        }
-
         if (!array_key_exists($type, $this->dataStore)) {
             return null;
         }
@@ -989,15 +968,11 @@ class SimpleSAML_Session implements Serializable
     {
         assert(is_string($type));
 
-        if (!is_array($this->dataStore)) {
-            return array();
-        }
-
         if (!array_key_exists($type, $this->dataStore)) {
-            return array();
+            return [];
         }
 
-        $ret = array();
+        $ret = [];
         foreach ($this->dataStore[$type] as $id => $info) {
             $ret[$id] = $info['data'];
         }
@@ -1023,7 +998,6 @@ class SimpleSAML_Session implements Serializable
         return $this->authData[$authority];
     }
 
-
     /**
      * Check whether the session cookie is set.
      *
@@ -1033,15 +1007,14 @@ class SimpleSAML_Session implements Serializable
      */
     public function hasSessionCookie()
     {
-        $sh = \SimpleSAML\SessionHandler::getSessionHandler();
+        $sh = SessionHandler::getSessionHandler();
         return $sh->hasSessionCookie();
     }
 
-
     /**
      * Add an SP association for an IdP.
      *
-     * This function is only for use by the SimpleSAML_IdP class.
+     * This function is only for use by the IdP class.
      *
      * @param string $idp The IdP id.
      * @param array  $association The association we should add.
@@ -1053,11 +1026,11 @@ class SimpleSAML_Session implements Serializable
         assert(isset($association['Handler']));
 
         if (!isset($this->associations)) {
-            $this->associations = array();
+            $this->associations = [];
         }
 
         if (!isset($this->associations[$idp])) {
-            $this->associations[$idp] = array();
+            $this->associations[$idp] = [];
         }
 
         $this->associations[$idp][$association['id']] = $association;
@@ -1065,11 +1038,10 @@ class SimpleSAML_Session implements Serializable
         $this->markDirty();
     }
 
-
     /**
      * Retrieve the associations for an IdP.
      *
-     * This function is only for use by the SimpleSAML_IdP class.
+     * This function is only for use by the IdP class.
      *
      * @param string $idp The IdP id.
      *
@@ -1080,11 +1052,11 @@ class SimpleSAML_Session implements Serializable
         assert(is_string($idp));
 
         if (!isset($this->associations)) {
-            $this->associations = array();
+            $this->associations = [];
         }
 
         if (!isset($this->associations[$idp])) {
-            return array();
+            return [];
         }
 
         foreach ($this->associations[$idp] as $id => $assoc) {
@@ -1101,11 +1073,10 @@ class SimpleSAML_Session implements Serializable
         return $this->associations[$idp];
     }
 
-
     /**
      * Remove an SP association for an IdP.
      *
-     * This function is only for use by the SimpleSAML_IdP class.
+     * This function is only for use by the IdP class.
      *
      * @param string $idp The IdP id.
      * @param string $associationId The id of the association.
@@ -1128,7 +1099,6 @@ class SimpleSAML_Session implements Serializable
         $this->markDirty();
     }
 
-
     /**
      * Retrieve authentication data.
      *
@@ -1148,7 +1118,6 @@ class SimpleSAML_Session implements Serializable
         return $this->authData[$authority][$name];
     }
 
-
     /**
      * Retrieve a list of authorities (authentication sources) that are currently valid within
      * this session.
@@ -1157,7 +1126,7 @@ class SimpleSAML_Session implements Serializable
      */
     public function getAuthorities()
     {
-        $authorities = array();
+        $authorities = [];
         foreach (array_keys($this->authData) as $authority) {
             if ($this->isValid($authority)) {
                 $authorities[] = $authority;
diff --git a/lib/SimpleSAML/SessionHandler.php b/lib/SimpleSAML/SessionHandler.php
index a8d4ad0efb00042a03ebd54aa084f4afa4d14d43..f8e0236f5b887a13970fccb338aab6a716e21b7b 100644
--- a/lib/SimpleSAML/SessionHandler.php
+++ b/lib/SimpleSAML/SessionHandler.php
@@ -82,9 +82,9 @@ abstract class SessionHandler
     /**
      * Save the session.
      *
-     * @param \SimpleSAML_Session $session The session object we should save.
+     * @param \SimpleSAML\Session $session The session object we should save.
      */
-    abstract public function saveSession(\SimpleSAML_Session $session);
+    abstract public function saveSession(Session $session);
 
 
     /**
@@ -92,7 +92,7 @@ abstract class SessionHandler
      *
      * @param string|null $sessionId The ID of the session we should load, or null to use the default.
      *
-     * @return \SimpleSAML_Session|null The session object, or null if it doesn't exist.
+     * @return \SimpleSAML\Session|null The session object, or null if it doesn't exist.
      */
     abstract public function loadSession($sessionId = null);
 
@@ -123,13 +123,13 @@ abstract class SessionHandler
      * Initialize the session handler.
      *
      * This function creates an instance of the session handler which is
-     * selected in the 'session.handler' configuration directive. If no
+     * selected in the 'store.type' configuration directive. If no
      * session handler is selected, then we will fall back to the default
      * PHP session handler.
      */
     private static function createSessionHandler()
     {
-        $store = \SimpleSAML\Store::getInstance();
+        $store = Store::getInstance();
         if ($store === false) {
             self::$sessionHandler = new SessionHandlerPHP();
         } else {
@@ -147,14 +147,14 @@ abstract class SessionHandler
      */
     public function getCookieParams()
     {
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
 
-        return array(
+        return [
             'lifetime' => $config->getInteger('session.cookie.lifetime', 0),
             'path'     => $config->getString('session.cookie.path', '/'),
             'domain'   => $config->getString('session.cookie.domain', null),
             'secure'   => $config->getBoolean('session.cookie.secure', false),
             'httponly' => true,
-        );
+        ];
     }
 }
diff --git a/lib/SimpleSAML/SessionHandlerCookie.php b/lib/SimpleSAML/SessionHandlerCookie.php
index b94e8f716e1b993093c80ee2592b884da31c5778..7eea4656d94cafb5b760fde23b29136054826d49 100644
--- a/lib/SimpleSAML/SessionHandlerCookie.php
+++ b/lib/SimpleSAML/SessionHandlerCookie.php
@@ -44,7 +44,7 @@ abstract class SessionHandlerCookie extends SessionHandler
         // call the constructor in the base class in case it should become necessary in the future
         parent::__construct();
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
         $this->cookie_name = $config->getString('session.cookie.name', 'SimpleSAMLSessionID');
     }
 
@@ -57,7 +57,7 @@ abstract class SessionHandlerCookie extends SessionHandler
     public function newSessionId()
     {
         $this->session_id = self::createSessionID();
-        \SimpleSAML_Session::createSession($this->session_id);
+        Session::createSession($this->session_id);
 
         return $this->session_id;
     }
@@ -71,7 +71,7 @@ abstract class SessionHandlerCookie extends SessionHandler
     public function getCookieSessionId()
     {
         if ($this->session_id === null) {
-            if (self::hasSessionCookie()) {
+            if ($this->hasSessionCookie()) {
                 // attempt to retrieve the session id from the cookie
                 $this->session_id = $_COOKIE[$this->cookie_name];
             }
diff --git a/lib/SimpleSAML/SessionHandlerPHP.php b/lib/SimpleSAML/SessionHandlerPHP.php
index 067c384d050d683bea83ace4144558eedd76f4ba..554605b98737957d27e7790e6a21ec29dc084401 100644
--- a/lib/SimpleSAML/SessionHandlerPHP.php
+++ b/lib/SimpleSAML/SessionHandlerPHP.php
@@ -34,7 +34,7 @@ class SessionHandlerPHP extends SessionHandler
      *
      * @var array
      */
-    private $previous_session = array();
+    private $previous_session = [];
 
 
     /**
@@ -46,7 +46,7 @@ class SessionHandlerPHP extends SessionHandler
         // call the parent constructor in case it should become necessary in the future
         parent::__construct();
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
         $this->cookie_name = $config->getString('session.phpsession.cookiename', null);
 
         if (session_status() === PHP_SESSION_ACTIVE) {
@@ -76,13 +76,15 @@ class SessionHandlerPHP extends SessionHandler
 
         $params = $this->getCookieParams();
 
-        session_set_cookie_params(
-            $params['lifetime'],
-            $params['path'],
-            $params['domain'],
-            $params['secure'],
-            $params['httponly']
-        );
+        if (!headers_sent()) {
+            session_set_cookie_params(
+                $params['lifetime'],
+                $params['path'],
+                $params['domain'],
+                $params['secure'],
+                $params['httponly']
+            );
+        }
 
         $savepath = $config->getString('session.phpsession.savepath', null);
         if (!empty($savepath)) {
@@ -112,8 +114,8 @@ class SessionHandlerPHP extends SessionHandler
              */
             session_cache_limiter('');
         }
-        @session_start();
         session_cache_limiter($cacheLimiter);
+        @session_start();
     }
 
 
@@ -123,7 +125,7 @@ class SessionHandlerPHP extends SessionHandler
      * Use this method to restore a previous PHP session existing before SimpleSAMLphp initialized its own session.
      *
      * WARNING: do not use this method directly, unless you know what you are doing. Calling this method directly,
-     * outside of SimpleSAML_Session, could cause SimpleSAMLphp's session to be lost or mess the application's one. The
+     * outside of \SimpleSAML\Session, could cause SimpleSAMLphp's session to be lost or mess the application's one. The
      * session must always be saved properly before calling this method. If you don't understand what this is about,
      * don't use this method.
      */
@@ -145,7 +147,7 @@ class SessionHandlerPHP extends SessionHandler
             $this->previous_session['cookie_params']['httponly']
         );
         session_id($this->previous_session['id']);
-        $this->previous_session = array();
+        $this->previous_session = [];
         $this->sessionStart();
 
         /*
@@ -166,7 +168,7 @@ class SessionHandlerPHP extends SessionHandler
     {
         // generate new (secure) session id
         $sessionId = bin2hex(openssl_random_pseudo_bytes(16));
-        \SimpleSAML_Session::createSession($sessionId);
+        Session::createSession($sessionId);
 
         return $sessionId;
     }
@@ -177,11 +179,11 @@ class SessionHandlerPHP extends SessionHandler
      *
      * @return string|null The session id saved in the cookie or null if no session cookie was set.
      *
-     * @throws \SimpleSAML_Error_Exception If the cookie is marked as secure but we are not using HTTPS.
+     * @throws \SimpleSAML\Error\Exception If the cookie is marked as secure but we are not using HTTPS.
      */
     public function getCookieSessionId()
     {
-        if (!self::hasSessionCookie()) {
+        if (!$this->hasSessionCookie()) {
             return null; // there's no session cookie, can't return ID
         }
 
@@ -191,7 +193,7 @@ class SessionHandlerPHP extends SessionHandler
         $session_cookie_params = session_get_cookie_params();
 
         if ($session_cookie_params['secure'] && !HTTP::isHTTPS()) {
-            throw new \SimpleSAML_Error_Exception('Session start with secure cookie not allowed on http.');
+            throw new \SimpleSAML\Error\Exception('Session start with secure cookie not allowed on http.');
         }
 
         $this->sessionStart();
@@ -213,9 +215,9 @@ class SessionHandlerPHP extends SessionHandler
     /**
      * Save the current session to the PHP session array.
      *
-     * @param \SimpleSAML_Session $session The session object we should save.
+     * @param \SimpleSAML\Session $session The session object we should save.
      */
-    public function saveSession(\SimpleSAML_Session $session)
+    public function saveSession(\SimpleSAML\Session $session)
     {
         $_SESSION['SimpleSAMLphp_SESSION'] = serialize($session);
     }
@@ -226,9 +228,9 @@ class SessionHandlerPHP extends SessionHandler
      *
      * @param string|null $sessionId The ID of the session we should load, or null to use the default.
      *
-     * @return \SimpleSAML_Session|null The session object, or null if it doesn't exist.
+     * @return \SimpleSAML\Session|null The session object, or null if it doesn't exist.
      *
-     * @throws \SimpleSAML_Error_Exception If it wasn't possible to disable session cookies or we are trying to load a
+     * @throws \SimpleSAML\Error\Exception If it wasn't possible to disable session cookies or we are trying to load a
      * PHP session with a specific identifier and it doesn't match with the current session identifier.
      */
     public function loadSession($sessionId = null)
@@ -240,16 +242,16 @@ class SessionHandlerPHP extends SessionHandler
                 // session not initiated with getCookieSessionId(), start session without setting cookie
                 $ret = ini_set('session.use_cookies', '0');
                 if ($ret === false) {
-                    throw new \SimpleSAML_Error_Exception('Disabling PHP option session.use_cookies failed.');
+                    throw new \SimpleSAML\Error\Exception('Disabling PHP option session.use_cookies failed.');
                 }
 
                 session_id($sessionId);
                 $this->sessionStart();
             } elseif ($sessionId !== session_id()) {
-                throw new \SimpleSAML_Error_Exception('Cannot load PHP session with a specific ID.');
+                throw new \SimpleSAML\Error\Exception('Cannot load PHP session with a specific ID.');
             }
         } elseif (session_id() === '') {
-            self::getCookieSessionId();
+            $this->getCookieSessionId();
         }
 
         if (!isset($_SESSION['SimpleSAMLphp_SESSION'])) {
@@ -286,17 +288,17 @@ class SessionHandlerPHP extends SessionHandler
      * @return array The cookie parameters for our sessions.
      * @link http://www.php.net/manual/en/function.session-get-cookie-params.php
      *
-     * @throws \SimpleSAML_Error_Exception If both 'session.phpsession.limitedpath' and 'session.cookie.path' options
+     * @throws \SimpleSAML\Error\Exception If both 'session.phpsession.limitedpath' and 'session.cookie.path' options
      * are set at the same time in the configuration.
      */
     public function getCookieParams()
     {
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
 
         $ret = parent::getCookieParams();
 
         if ($config->hasValue('session.phpsession.limitedpath') && $config->hasValue('session.cookie.path')) {
-            throw new \SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'You cannot set both the session.phpsession.limitedpath and session.cookie.path options.'
             );
         } elseif ($config->hasValue('session.phpsession.limitedpath')) {
@@ -341,6 +343,11 @@ class SessionHandlerPHP extends SessionHandler
             );
         }
 
+        if (session_id() !== '') {
+            // session already started, close it
+            session_write_close();
+        }
+
         session_set_cookie_params(
             $cookieParams['lifetime'],
             $cookieParams['path'],
@@ -349,11 +356,6 @@ class SessionHandlerPHP extends SessionHandler
             $cookieParams['httponly']
         );
 
-        if (session_id() !== '') {
-            // session already started, close it
-            session_write_close();
-        }
-
         session_id($sessionID);
         $this->sessionStart();
     }
diff --git a/lib/SimpleSAML/SessionHandlerStore.php b/lib/SimpleSAML/SessionHandlerStore.php
index 328654249eccfcc1564be9b706feb944b02b56be..f40b9eb958c6c1871c4fbbc2629412876c30a006 100644
--- a/lib/SimpleSAML/SessionHandlerStore.php
+++ b/lib/SimpleSAML/SessionHandlerStore.php
@@ -38,7 +38,7 @@ class SessionHandlerStore extends SessionHandlerCookie
      *
      * @param string|null $sessionId The ID of the session we should load, or null to use the default.
      *
-     * @return \SimpleSAML_Session|null The session object, or null if it doesn't exist.
+     * @return \SimpleSAML\Session|null The session object, or null if it doesn't exist.
      */
     public function loadSession($sessionId = null)
     {
@@ -54,7 +54,7 @@ class SessionHandlerStore extends SessionHandlerCookie
 
         $session = $this->store->get('session', $sessionId);
         if ($session !== null) {
-            assert($session instanceof \SimpleSAML_Session);
+            assert($session instanceof Session);
             return $session;
         }
 
@@ -65,13 +65,13 @@ class SessionHandlerStore extends SessionHandlerCookie
     /**
      * Save a session to the data store.
      *
-     * @param \SimpleSAML_Session $session The session object we should save.
+     * @param \SimpleSAML\Session $session The session object we should save.
      */
-    public function saveSession(\SimpleSAML_Session $session)
+    public function saveSession(Session $session)
     {
         $sessionId = $session->getSessionId();
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
         $sessionDuration = $config->getInteger('session.duration', 8 * 60 * 60);
         $expire = time() + $sessionDuration;
 
diff --git a/lib/SimpleSAML/Stats.php b/lib/SimpleSAML/Stats.php
index e710a373ef1c31e59a49bf3d1a8d7919e76d1712..8c2987c828d08ffb09d18075fcc5cc41ad3b2e14 100644
--- a/lib/SimpleSAML/Stats.php
+++ b/lib/SimpleSAML/Stats.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML;
 
 /**
  * Statistics handler class.
@@ -8,9 +9,9 @@
  *
  * @package SimpleSAMLphp
  */
-class SimpleSAML_Stats
-{
 
+class Stats
+{
     /**
      * Whether this class is initialized.
      *
@@ -30,14 +31,14 @@ class SimpleSAML_Stats
     /**
      * Create an output from a configuration object.
      *
-     * @param SimpleSAML_Configuration $config The configuration object.
+     * @param \SimpleSAML\Configuration $config The configuration object.
      *
      * @return mixed A new instance of the configured class.
      */
-    private static function createOutput(SimpleSAML_Configuration $config)
+    private static function createOutput(\SimpleSAML\Configuration $config)
     {
         $cls = $config->getString('class');
-        $cls = SimpleSAML\Module::resolveClass($cls, 'Stats_Output', 'SimpleSAML_Stats_Output');
+        $cls = \SimpleSAML\Module::resolveClass($cls, 'Stats_Output', '\SimpleSAML\Stats\Output');
 
         $output = new $cls($config);
         return $output;
@@ -50,10 +51,10 @@ class SimpleSAML_Stats
     private static function initOutputs()
     {
 
-        $config = SimpleSAML_Configuration::getInstance();
-        $outputCfgs = $config->getConfigList('statistics.out', array());
+        $config = \SimpleSAML\Configuration::getInstance();
+        $outputCfgs = $config->getConfigList('statistics.out', []);
 
-        self::$outputs = array();
+        self::$outputs = [];
         foreach ($outputCfgs as $cfg) {
             self::$outputs[] = self::createOutput($cfg);
         }
@@ -68,7 +69,7 @@ class SimpleSAML_Stats
      *
      * @return void|boolean False if output is not enabled, void otherwise.
      */
-    public static function log($event, array $data = array())
+    public static function log($event, array $data = [])
     {
         assert(is_string($event));
         assert(!isset($data['op']));
@@ -97,5 +98,4 @@ class SimpleSAML_Stats
             $out->emit($data);
         }
     }
-
 }
diff --git a/lib/SimpleSAML/Stats/Output.php b/lib/SimpleSAML/Stats/Output.php
index 8b019c8c9de4ccefa253a7e7016b3462afc2a875..a4a05ed44b0f318d9ec339fc9ac1d6687b10b160 100644
--- a/lib/SimpleSAML/Stats/Output.php
+++ b/lib/SimpleSAML/Stats/Output.php
@@ -1,20 +1,21 @@
 <?php
 
+namespace SimpleSAML\Stats;
 
 /**
  * Interface for statistics outputs.
  *
  * @package SimpleSAMLphp
  */
-abstract class SimpleSAML_Stats_Output
-{
 
+abstract class Output
+{
     /**
      * Initialize the output.
      *
-     * @param SimpleSAML_Configuration $config The configuration for this output.
+     * @param \SimpleSAML\Configuration $config The configuration for this output.
      */
-    public function __construct(SimpleSAML_Configuration $config)
+    public function __construct(\SimpleSAML\Configuration $config)
     {
         // do nothing by default
     }
diff --git a/lib/SimpleSAML/Store.php b/lib/SimpleSAML/Store.php
index 8f25b59c9194f2fc20843e7c30a428e33aa5f01e..d5be90656fd91737839453c198b00a9bfa864c4d 100644
--- a/lib/SimpleSAML/Store.php
+++ b/lib/SimpleSAML/Store.php
@@ -34,11 +34,8 @@ abstract class Store
             return self::$instance;
         }
 
-        $config = \SimpleSAML_Configuration::getInstance();
-        $storeType = $config->getString('store.type', null);
-        if ($storeType === null) {
-            $storeType = $config->getString('session.handler', 'phpsession');
-        }
+        $config = Configuration::getInstance();
+        $storeType = $config->getString('store.type', 'phpsession');
 
         switch ($storeType) {
             case 'phpsession':
diff --git a/lib/SimpleSAML/Store/Memcache.php b/lib/SimpleSAML/Store/Memcache.php
index 8f9fcfbea9ff51f6b53f9ef2e2a0304d0d84166a..209ae762f3672a58913838350a14656990d237f0 100644
--- a/lib/SimpleSAML/Store/Memcache.php
+++ b/lib/SimpleSAML/Store/Memcache.php
@@ -2,7 +2,7 @@
 
 namespace SimpleSAML\Store;
 
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Store;
 
 /**
@@ -42,7 +42,7 @@ class Memcache extends Store
         assert(is_string($type));
         assert(is_string($key));
 
-        return \SimpleSAML_Memcache::get($this->prefix . '.' . $type . '.' . $key);
+        return \SimpleSAML\Memcache::get($this->prefix.'.'.$type.'.'.$key);
     }
 
 
@@ -64,7 +64,7 @@ class Memcache extends Store
             $expire = 0;
         }
 
-        \SimpleSAML_Memcache::set($this->prefix . '.' . $type . '.' . $key, $value, $expire);
+        \SimpleSAML\Memcache::set($this->prefix.'.'.$type.'.'.$key, $value, $expire);
     }
 
 
@@ -79,6 +79,6 @@ class Memcache extends Store
         assert(is_string($type));
         assert(is_string($key));
 
-        \SimpleSAML_Memcache::delete($this->prefix . '.' . $type . '.' . $key);
+        \SimpleSAML\Memcache::delete($this->prefix.'.'.$type.'.'.$key);
     }
 }
diff --git a/lib/SimpleSAML/Store/Redis.php b/lib/SimpleSAML/Store/Redis.php
index 2f568e3600544953edfd2c43384ffe1be654850e..9091ddd631ebb9fffa80c48706fa73919f2d9af8 100644
--- a/lib/SimpleSAML/Store/Redis.php
+++ b/lib/SimpleSAML/Store/Redis.php
@@ -2,7 +2,7 @@
 
 namespace SimpleSAML\Store;
 
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Store;
 
 /**
@@ -33,14 +33,14 @@ class Redis extends Store
             $prefix = $config->getString('store.redis.prefix', 'SimpleSAMLphp');
 
             $redis = new \Predis\Client(
-                array(
+                [
                     'scheme' => 'tcp',
                     'host' => $host,
                     'port' => $port,
-                ),
-                array(
+                ],
+                [
                     'prefix' => $prefix,
-                )
+                ]
             );
         }
 
@@ -98,7 +98,8 @@ class Redis extends Store
         if ($expire === null) {
             $this->redis->set("{$type}.{$key}", $serialized);
         } else {
-            $this->redis->setex("{$type}.{$key}", $expire, $serialized);
+            // setex expire time is in seconds (not unix timestamp)
+            $this->redis->setex("{$type}.{$key}", $expire - time(), $serialized);
         }
     }
 
diff --git a/lib/SimpleSAML/Store/SQL.php b/lib/SimpleSAML/Store/SQL.php
old mode 100755
new mode 100644
index ec46c24ce98bb2c36fb470496a8d9f8c02204060..72bb84248cefd72baf526943579cbafedca2e982
--- a/lib/SimpleSAML/Store/SQL.php
+++ b/lib/SimpleSAML/Store/SQL.php
@@ -2,7 +2,7 @@
 
 namespace SimpleSAML\Store;
 
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Logger;
 use \SimpleSAML\Store;
 
@@ -48,7 +48,7 @@ class SQL extends Store
     /**
      * Initialize the SQL data store.
      */
-    protected function __construct()
+    public function __construct()
     {
         $config = Configuration::getInstance();
 
@@ -57,8 +57,11 @@ class SQL extends Store
         $password = $config->getString('store.sql.password', null);
         $options = $config->getArray('store.sql.options', null);
         $this->prefix = $config->getString('store.sql.prefix', 'simpleSAMLphp');
-
-        $this->pdo = new \PDO($dsn, $username, $password, $options);
+        try {
+            $this->pdo = new \PDO($dsn, $username, $password, $options);
+        } catch (\PDOException $e) {
+            throw new \Exception("Database error: ".$e->getMessage());
+        }
         $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
 
         $this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
@@ -77,7 +80,7 @@ class SQL extends Store
      */
     private function initTableVersionTable()
     {
-        $this->tableVersions = array();
+        $this->tableVersions = [];
 
         try {
             $fetchTableVersion = $this->pdo->query('SELECT _name, _version FROM '.$this->prefix.'_tableVersion');
@@ -112,13 +115,13 @@ class SQL extends Store
          * Queries for updates, grouped by version.
          * New updates can be added as a new array in this array
          */
-        $table_updates = array(
-            array(
+        $table_updates = [
+            [
                 'CREATE TABLE '.$this->prefix.
                 '_kvstore (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value '.$text_t.
                 ' NOT NULL, _expire TIMESTAMP, PRIMARY KEY (_key, _type))',
                 'CREATE INDEX '.$this->prefix.'_kvstore_expire ON '.$this->prefix.'_kvstore (_expire)'
-            ),
+            ],
             /**
              * This upgrade removes the default NOT NULL constraint on the _expire field in MySQL.
              * Because SQLite does not support field alterations, the approach is to:
@@ -128,16 +131,16 @@ class SQL extends Store
              *     Rename the new table correctly
              *     Readd the index
              */
-            array(
+            [
                 'CREATE TABLE '.$this->prefix.
                 '_kvstore_new (_type VARCHAR(30) NOT NULL, _key VARCHAR(50) NOT NULL, _value '.$text_t.
                 ' NOT NULL, _expire TIMESTAMP NULL, PRIMARY KEY (_key, _type))',
-                'INSERT INTO '.$this->prefix.'_kvstore_new SELECT * FROM ' . $this->prefix.'_kvstore',
+                'INSERT INTO '.$this->prefix.'_kvstore_new SELECT * FROM '.$this->prefix.'_kvstore',
                 'DROP TABLE '.$this->prefix.'_kvstore',
-                'ALTER TABLE '.$this->prefix.'_kvstore_new RENAME TO ' . $this->prefix . '_kvstore',
+                'ALTER TABLE '.$this->prefix.'_kvstore_new RENAME TO '.$this->prefix.'_kvstore',
                 'CREATE INDEX '.$this->prefix.'_kvstore_expire ON '.$this->prefix.'_kvstore (_expire)'
-            )
-        );
+            ]
+        ];
 
         $latest_version = count($table_updates);
 
@@ -190,8 +193,8 @@ class SQL extends Store
 
         $this->insertOrUpdate(
             $this->prefix.'_tableVersion',
-            array('_name'),
-            array('_name' => $name, '_version' => $version)
+            ['_name'],
+            ['_name' => $name, '_version' => $version]
         );
         $this->tableVersions[$name] = $version;
     }
@@ -243,8 +246,8 @@ class SQL extends Store
             }
         }
 
-        $updateCols = array();
-        $condCols = array();
+        $updateCols = [];
+        $condCols = [];
         foreach ($data as $col => $value) {
             $tmp = $col.' = :'.$col;
 
@@ -269,7 +272,7 @@ class SQL extends Store
         Logger::debug('store.sql: Cleaning key-value store.');
 
         $query = 'DELETE FROM '.$this->prefix.'_kvstore WHERE _expire < :now';
-        $params = array('now' => gmdate('Y-m-d H:i:s'));
+        $params = ['now' => gmdate('Y-m-d H:i:s')];
 
         $query = $this->pdo->prepare($query);
         $query->execute($params);
@@ -294,8 +297,8 @@ class SQL extends Store
         }
 
         $query = 'SELECT _value FROM '.$this->prefix.
-                 '_kvstore WHERE _type = :type AND _key = :key AND (_expire IS NULL OR _expire > :now)';
-        $params = array('type' => $type, 'key' => $key, 'now' => gmdate('Y-m-d H:i:s'));
+            '_kvstore WHERE _type = :type AND _key = :key AND (_expire IS NULL OR _expire > :now)';
+        $params = ['type' => $type, 'key' => $key, 'now' => gmdate('Y-m-d H:i:s')];
 
         $query = $this->pdo->prepare($query);
         $query->execute($params);
@@ -348,14 +351,14 @@ class SQL extends Store
         $value = serialize($value);
         $value = rawurlencode($value);
 
-        $data = array(
+        $data = [
             '_type'   => $type,
             '_key'    => $key,
             '_value'  => $value,
             '_expire' => $expire,
-        );
+        ];
 
-        $this->insertOrUpdate($this->prefix.'_kvstore', array('_type', '_key'), $data);
+        $this->insertOrUpdate($this->prefix.'_kvstore', ['_type', '_key'], $data);
     }
 
 
@@ -374,10 +377,10 @@ class SQL extends Store
             $key = sha1($key);
         }
 
-        $data = array(
+        $data = [
             '_type' => $type,
             '_key'  => $key,
-        );
+        ];
 
         $query = 'DELETE FROM '.$this->prefix.'_kvstore WHERE _type=:_type AND _key=:_key';
         $query = $this->pdo->prepare($query);
diff --git a/lib/SimpleSAML/Utilities.php b/lib/SimpleSAML/Utilities.php
index 68cd10b877b755f358603245fda896ee4e714b96..c6e04223e9baf472b6a5909d01bce4043ca676ce 100644
--- a/lib/SimpleSAML/Utilities.php
+++ b/lib/SimpleSAML/Utilities.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML;
 
 /**
  * Misc static functions that is used several places.in example parsing and id generation.
@@ -9,9 +10,9 @@
  *
  * @deprecated This entire class will be removed in SimpleSAMLphp 2.0.
  */
-class SimpleSAML_Utilities
-{
 
+class Utilities
+{
     /**
      * @deprecated This property will be removed in SSP 2.0. Please use SimpleSAML\Logger::isErrorMasked() instead.
      */
@@ -112,11 +113,11 @@ class SimpleSAML_Utilities
 
 
     /**
-     * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML_Auth_State::parseStateID() instead.
+     * @deprecated This method will be removed in SSP 2.0. Please use \SimpleSAML\Auth\State::parseStateID() instead.
      */
     public static function parseStateID($stateId)
     {
-        return SimpleSAML_Auth_State::parseStateID($stateId);
+        return \SimpleSAML\Auth\State::parseStateID($stateId);
     }
 
 
@@ -149,7 +150,7 @@ class SimpleSAML_Utilities
      */
     public static function generateID()
     {
-        return SimpleSAML\Utils\Random::generateID();
+        return \SimpleSAML\Utils\Random::generateID();
     }
 
 
@@ -159,7 +160,7 @@ class SimpleSAML_Utilities
      */
     public static function generateTimestamp($instant = null)
     {
-        return SimpleSAML\Utils\Time::generateTimestamp($instant);
+        return \SimpleSAML\Utils\Time::generateTimestamp($instant);
     }
 
 
@@ -168,16 +169,16 @@ class SimpleSAML_Utilities
      */
     public static function parseDuration($duration, $timestamp = null)
     {
-        return SimpleSAML\Utils\Time::parseDuration($duration, $timestamp);
+        return \SimpleSAML\Utils\Time::parseDuration($duration, $timestamp);
     }
 
 
     /**
-     * @deprecated This method will be removed in SSP 2.0. Please raise a SimpleSAML_Error_Error exception instead.
+     * @deprecated This method will be removed in SSP 2.0. Please raise a SimpleSAML\Error\Error exception instead.
      */
-    public static function fatalError($trackId = 'na', $errorCode = null, Exception $e = null)
+    public static function fatalError($trackId = 'na', $errorCode = null, \Exception $e = null)
     {
-        throw new SimpleSAML_Error_Error($errorCode, $e);
+        throw new \SimpleSAML\Error\Error($errorCode, $e);
     }
 
 
@@ -186,11 +187,11 @@ class SimpleSAML_Utilities
      */
     public static function ipCIDRcheck($cidr, $ip = null)
     {
-        return SimpleSAML\Utils\Net::ipCIDRcheck($cidr, $ip);
+        return \SimpleSAML\Utils\Net::ipCIDRcheck($cidr, $ip);
     }
 
 
-    private static function _doRedirect($url, $parameters = array())
+    private static function doRedirect($url, $parameters = [])
     {
         assert(is_string($url));
         assert(!empty($url));
@@ -213,7 +214,7 @@ class SimpleSAML_Utilities
         }
 
         if (strlen($url) > 2048) {
-            SimpleSAML\Logger::warning('Redirecting to a URL longer than 2048 bytes.');
+            \SimpleSAML\Logger::warning('Redirecting to a URL longer than 2048 bytes.');
         }
 
         // Set the location header
@@ -252,7 +253,7 @@ class SimpleSAML_Utilities
      * @deprecated 1.12.0 This method will be removed from the API. Instead, use the redirectTrustedURL() or
      * redirectUntrustedURL() functions accordingly.
      */
-    public static function redirect($url, $parameters = array(), $allowed_redirect_hosts = null)
+    public static function redirect($url, $parameters = [], $allowed_redirect_hosts = null)
     {
         assert(is_string($url));
         assert(strlen($url) > 0);
@@ -263,7 +264,7 @@ class SimpleSAML_Utilities
         } else {
             $url = self::normalizeURL($url);
         }
-        self::_doRedirect($url, $parameters);
+        self::doRedirect($url, $parameters);
     }
 
 
@@ -271,7 +272,7 @@ class SimpleSAML_Utilities
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\HTTP::redirectTrustedURL()
      *     instead.
      */
-    public static function redirectTrustedURL($url, $parameters = array())
+    public static function redirectTrustedURL($url, $parameters = [])
     {
         \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $parameters);
     }
@@ -281,7 +282,7 @@ class SimpleSAML_Utilities
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\HTTP::redirectUntrustedURL()
      *     instead.
      */
-    public static function redirectUntrustedURL($url, $parameters = array())
+    public static function redirectUntrustedURL($url, $parameters = [])
     {
         \SimpleSAML\Utils\HTTP::redirectUntrustedURL($url, $parameters);
     }
@@ -292,7 +293,7 @@ class SimpleSAML_Utilities
      */
     public static function transposeArray($in)
     {
-        return SimpleSAML\Utils\Arrays::transpose($in);
+        return \SimpleSAML\Utils\Arrays::transpose($in);
     }
 
 
@@ -300,18 +301,18 @@ class SimpleSAML_Utilities
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\XML::isDOMNodeOfType()
      *     instead.
      */
-    public static function isDOMElementOfType(DOMNode $element, $name, $nsURI)
+    public static function isDOMElementOfType(\DOMNode $element, $name, $nsURI)
     {
-        return SimpleSAML\Utils\XML::isDOMNodeOfType($element, $name, $nsURI);
+        return \SimpleSAML\Utils\XML::isDOMNodeOfType($element, $name, $nsURI);
     }
 
 
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\XML::getDOMChildren() instead.
      */
-    public static function getDOMChildren(DOMElement $element, $localName, $namespaceURI)
+    public static function getDOMChildren(\DOMElement $element, $localName, $namespaceURI)
     {
-        return SimpleSAML\Utils\XML::getDOMChildren($element, $localName, $namespaceURI);
+        return \SimpleSAML\Utils\XML::getDOMChildren($element, $localName, $namespaceURI);
     }
 
 
@@ -320,7 +321,7 @@ class SimpleSAML_Utilities
      */
     public static function getDOMText($element)
     {
-        return SimpleSAML\Utils\XML::getDOMText($element);
+        return \SimpleSAML\Utils\XML::getDOMText($element);
     }
 
 
@@ -419,7 +420,7 @@ class SimpleSAML_Utilities
      */
     public static function parseAttributes($attributes)
     {
-        return SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
+        return \SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
     }
 
 
@@ -428,7 +429,7 @@ class SimpleSAML_Utilities
      */
     public static function getSecretSalt()
     {
-        return SimpleSAML\Utils\Config::getSecretSalt();
+        return \SimpleSAML\Utils\Config::getSecretSalt();
     }
 
 
@@ -463,27 +464,27 @@ class SimpleSAML_Utilities
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\Crypto::loadPublicKey() instead.
      */
-    public static function loadPublicKey(SimpleSAML_Configuration $metadata, $required = false, $prefix = '')
+    public static function loadPublicKey(\SimpleSAML\Configuration $metadata, $required = false, $prefix = '')
     {
-        return SimpleSAML\Utils\Crypto::loadPublicKey($metadata, $required, $prefix);
+        return \SimpleSAML\Utils\Crypto::loadPublicKey($metadata, $required, $prefix);
     }
 
 
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\Crypto::loadPrivateKey() instead.
      */
-    public static function loadPrivateKey(SimpleSAML_Configuration $metadata, $required = false, $prefix = '')
+    public static function loadPrivateKey(\SimpleSAML\Configuration $metadata, $required = false, $prefix = '')
     {
-        return SimpleSAML\Utils\Crypto::loadPrivateKey($metadata, $required, $prefix);
+        return \SimpleSAML\Utils\Crypto::loadPrivateKey($metadata, $required, $prefix);
     }
 
 
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\XML::formatDOMElement() instead.
      */
-    public static function formatDOMElement(DOMElement $root, $indentBase = '')
+    public static function formatDOMElement(\DOMElement $root, $indentBase = '')
     {
-        SimpleSAML\Utils\XML::formatDOMElement($root, $indentBase);
+        \SimpleSAML\Utils\XML::formatDOMElement($root, $indentBase);
     }
 
 
@@ -492,7 +493,7 @@ class SimpleSAML_Utilities
      */
     public static function formatXMLString($xml, $indentBase = '')
     {
-        return SimpleSAML\Utils\XML::formatXMLString($xml, $indentBase);
+        return \SimpleSAML\Utils\XML::formatXMLString($xml, $indentBase);
     }
 
 
@@ -501,7 +502,7 @@ class SimpleSAML_Utilities
      */
     public static function arrayize($data, $index = 0)
     {
-        return SimpleSAML\Utils\Arrays::arrayize($data, $index);
+        return \SimpleSAML\Utils\Arrays::arrayize($data, $index);
     }
 
 
@@ -510,7 +511,7 @@ class SimpleSAML_Utilities
      */
     public static function isAdmin()
     {
-        return SimpleSAML\Utils\Auth::isAdmin();
+        return \SimpleSAML\Utils\Auth::isAdmin();
     }
 
 
@@ -519,7 +520,7 @@ class SimpleSAML_Utilities
      */
     public static function getAdminLoginURL($returnTo = null)
     {
-        return SimpleSAML\Utils\Auth::getAdminLoginURL($returnTo);
+        return \SimpleSAML\Utils\Auth::getAdminLoginURL($returnTo);
     }
 
 
@@ -560,18 +561,18 @@ class SimpleSAML_Utilities
         assert(is_string($destination));
         assert(is_array($post));
 
-        $postId = SimpleSAML\Utils\Random::generateID();
-        $postData = array(
+        $postId = \SimpleSAML\Utils\Random::generateID();
+        $postData = [
             'post' => $post,
             'url'  => $destination,
-        );
+        ];
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $session->setData('core_postdatalink', $postId, $postData);
 
-        $redirInfo = base64_encode(SimpleSAML\Utils\Crypto::aesEncrypt($session->getSessionId().':'.$postId));
+        $redirInfo = base64_encode(\SimpleSAML\Utils\Crypto::aesEncrypt($session->getSessionId().':'.$postId));
 
-        $url = SimpleSAML\Module::getModuleURL('core/postredirect.php', array('RedirInfo' => $redirInfo));
+        $url = \SimpleSAML\Module::getModuleURL('core/postredirect.php', ['RedirInfo' => $redirInfo]);
         $url = preg_replace("#^https:#", "http:", $url);
 
         return $url;
@@ -610,7 +611,7 @@ class SimpleSAML_Utilities
      */
     public static function getTempDir()
     {
-        return SimpleSAML\Utils\System::getTempDir();
+        return \SimpleSAML\Utils\System::getTempDir();
     }
 
 
@@ -619,7 +620,7 @@ class SimpleSAML_Utilities
      */
     public static function maskErrors($mask)
     {
-        SimpleSAML\Logger::maskErrors($mask);
+        \SimpleSAML\Logger::maskErrors($mask);
     }
 
 
@@ -628,7 +629,7 @@ class SimpleSAML_Utilities
      */
     public static function popErrorMask()
     {
-        SimpleSAML\Logger::popErrorMask();
+        \SimpleSAML\Logger::popErrorMask();
     }
 
 
@@ -664,7 +665,7 @@ class SimpleSAML_Utilities
     /**
      * @deprecated This method will be removed in SSP 2.0. Please use SimpleSAML\Utils\HTTP::fetch() instead.
      */
-    public static function fetch($path, $context = array(), $getHeaders = false)
+    public static function fetch($path, $context = [], $getHeaders = false)
     {
         return \SimpleSAML\Utils\HTTP::fetch($path, $context, $getHeaders);
     }
@@ -675,7 +676,7 @@ class SimpleSAML_Utilities
      */
     public static function aesEncrypt($clear)
     {
-        return SimpleSAML\Utils\Crypto::aesEncrypt($clear);
+        return \SimpleSAML\Utils\Crypto::aesEncrypt($clear);
     }
 
 
@@ -684,7 +685,7 @@ class SimpleSAML_Utilities
      */
     public static function aesDecrypt($encData)
     {
-        return SimpleSAML\Utils\Crypto::aesDecrypt($encData);
+        return \SimpleSAML\Utils\Crypto::aesDecrypt($encData);
     }
 
 
@@ -693,7 +694,7 @@ class SimpleSAML_Utilities
      */
     public static function isWindowsOS()
     {
-        return SimpleSAML\Utils\System::getOS() === SimpleSAML\Utils\System::WINDOWS;
+        return \SimpleSAML\Utils\System::getOS() === \SimpleSAML\Utils\System::WINDOWS;
     }
 
 
diff --git a/lib/SimpleSAML/Utils/Arrays.php b/lib/SimpleSAML/Utils/Arrays.php
index 0a5129230b98a50eac339225f2fb72ad0b441ed4..c27b198eb0284d72b69d013325ad924bdfa05498 100644
--- a/lib/SimpleSAML/Utils/Arrays.php
+++ b/lib/SimpleSAML/Utils/Arrays.php
@@ -23,7 +23,7 @@ class Arrays
      */
     public static function arrayize($data, $index = 0)
     {
-        return (is_array($data)) ? $data : array($index => $data);
+        return (is_array($data)) ? $data : [$index => $data];
     }
 
 
@@ -42,7 +42,7 @@ class Arrays
             return false;
         }
 
-        $ret = array();
+        $ret = [];
         foreach ($array as $k1 => $a2) {
             if (!is_array($a2)) {
                 return false;
@@ -50,7 +50,7 @@ class Arrays
 
             foreach ($a2 as $k2 => $v) {
                 if (!array_key_exists($k2, $ret)) {
-                    $ret[$k2] = array();
+                    $ret[$k2] = [];
                 }
                 $ret[$k2][$k1] = $v;
             }
diff --git a/lib/SimpleSAML/Utils/Attributes.php b/lib/SimpleSAML/Utils/Attributes.php
index 00e934f5e192e3332be5078cc7ce493bd8fdef02..88c87f1aa26a271f0f473062ace38c1c22029c07 100644
--- a/lib/SimpleSAML/Utils/Attributes.php
+++ b/lib/SimpleSAML/Utils/Attributes.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace SimpleSAML\Utils;
 
 /**
@@ -7,9 +8,9 @@ namespace SimpleSAML\Utils;
  * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
  * @package SimpleSAML
  */
+
 class Attributes
 {
-
     /**
      * Look for an attribute in a normalized attributes array, failing if it's not there.
      *
@@ -21,7 +22,7 @@ class Attributes
      * $allow_multiple is set to true, the first value will be returned.
      *
      * @throws \InvalidArgumentException If $attributes is not an array or $expected is not a string.
-     * @throws \SimpleSAML_Error_Exception If the expected attribute was not found in the attributes array.
+     * @throws \SimpleSAML\Error\Exception If the expected attribute was not found in the attributes array.
      */
     public static function getExpectedAttribute($attributes, $expected, $allow_multiple = false)
     {
@@ -38,7 +39,7 @@ class Attributes
         }
 
         if (!array_key_exists($expected, $attributes)) {
-            throw new \SimpleSAML_Error_Exception("No such attribute '".$expected."' found.");
+            throw new \SimpleSAML\Error\Exception("No such attribute '".$expected."' found.");
         }
         $attribute = $attributes[$expected];
 
@@ -47,11 +48,10 @@ class Attributes
         }
 
         if (count($attribute) === 0) {
-            throw new \SimpleSAML_Error_Exception("Empty attribute '".$expected."'.'");
-
+            throw new \SimpleSAML\Error\Exception("Empty attribute '".$expected."'.'");
         } elseif (count($attribute) > 1) {
             if ($allow_multiple === false) {
-                throw new \SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'More than one value found for the attribute, multiple values not allowed.'
                 );
             }
@@ -85,7 +85,7 @@ class Attributes
             );
         }
 
-        $newAttrs = array();
+        $newAttrs = [];
         foreach ($attributes as $name => $values) {
             if (!is_string($name)) {
                 throw new \InvalidArgumentException('Invalid attribute name: "'.print_r($name, true).'".');
@@ -127,6 +127,6 @@ class Attributes
             $defaultns = substr($name, 0, $slash);
             $name = substr($name, $slash + 1);
         }
-        return array(htmlspecialchars($defaultns), htmlspecialchars($name));
+        return [htmlspecialchars($defaultns), htmlspecialchars($name)];
     }
 }
diff --git a/lib/SimpleSAML/Utils/Auth.php b/lib/SimpleSAML/Utils/Auth.php
index 5360f74da0082e23911da5a27261a989a8892a78..7cff78b27c038d68e6aa07774197015dcf74bf82 100644
--- a/lib/SimpleSAML/Utils/Auth.php
+++ b/lib/SimpleSAML/Utils/Auth.php
@@ -10,7 +10,6 @@ use SimpleSAML\Module;
  */
 class Auth
 {
-
     /**
      * Retrieve a admin login URL.
      *
@@ -29,9 +28,29 @@ class Auth
             $returnTo = HTTP::getSelfURL();
         }
 
-        return Module::getModuleURL('core/login-admin.php', array('ReturnTo' => $returnTo));
+        return Module::getModuleURL('core/login-admin.php', ['ReturnTo' => $returnTo]);
+    }
+
+
+    /**
+     * Retrieve a admin logout URL.
+     *
+     * @param string|NULL $returnTo The URL the user should arrive on after admin authentication. Defaults to null.
+     *
+     * @return string A URL which can be used for logging out.
+     * @throws \InvalidArgumentException If $returnTo is neither a string nor null.
+     */
+    public static function getAdminLogoutURL($returnTo = null)
+    {
+        if (!(is_string($returnTo) || is_null($returnTo))) {
+            throw new \InvalidArgumentException('Invalid input parameters.');
+        }
+
+        $as = new \SimpleSAML\Auth\Simple('admin');
+        return $as->getLogoutURL($returnTo = null);
     }
 
+
     /**
      * Check whether the current user is admin.
      *
@@ -41,7 +60,7 @@ class Auth
      */
     public static function isAdmin()
     {
-        $session = \SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         return $session->isValid('admin') || $session->isValid('login-admin');
     }
 
@@ -52,7 +71,7 @@ class Auth
      * a login page if the current user doesn't have admin access.
      *
      * @return void This function will only return if the user is admin.
-     * @throws \SimpleSAML_Error_Exception If no "admin" authentication source was configured.
+     * @throws \SimpleSAML\Error\Exception If no "admin" authentication source was configured.
      *
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
@@ -64,13 +83,13 @@ class Auth
         }
 
         // not authenticated as admin user, start authentication
-        if (\SimpleSAML_Auth_Source::getById('admin') !== null) {
+        if (\SimpleSAML\Auth\Source::getById('admin') !== null) {
             $as = new \SimpleSAML\Auth\Simple('admin');
             $as->login();
         } else {
-            throw new \SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Cannot find "admin" auth source, and admin privileges are required.'
             );
         }
     }
-}
\ No newline at end of file
+}
diff --git a/lib/SimpleSAML/Utils/Config.php b/lib/SimpleSAML/Utils/Config.php
index fa044516bd42e2cd13cfec721993b0e28d493ce9..5f25f8a0de38e14c216c0adda424cc8d3660f36b 100644
--- a/lib/SimpleSAML/Utils/Config.php
+++ b/lib/SimpleSAML/Utils/Config.php
@@ -8,7 +8,6 @@ namespace SimpleSAML\Utils;
  */
 class Config
 {
-
     /**
      * Resolves a path that may be relative to the cert-directory.
      *
@@ -25,7 +24,7 @@ class Config
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $globalConfig = \SimpleSAML_Configuration::getInstance();
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
         $base = $globalConfig->getPathValue('certdir', 'cert/');
         return System::resolvePath($path, $base);
     }
@@ -48,7 +47,7 @@ class Config
      */
     public static function getSecretSalt()
     {
-        $secretSalt = \SimpleSAML_Configuration::getInstance()->getString('secretsalt');
+        $secretSalt = \SimpleSAML\Configuration::getInstance()->getString('secretsalt');
         if ($secretSalt === 'defaultsecretsalt') {
             throw new \InvalidArgumentException('The "secretsalt" configuration option must be set to a secret value.');
         }
@@ -66,14 +65,19 @@ class Config
      */
     public static function getConfigDir()
     {
-        $configDir    = dirname(dirname(dirname(__DIR__))) . '/config';
+        $configDir = dirname(dirname(dirname(__DIR__))).'/config';
         /** @var string|false $configDirEnv */
         $configDirEnv = getenv('SIMPLESAMLPHP_CONFIG_DIR');
+        
+        if ($configDirEnv === false) {
+            $configDirEnv = getenv('REDIRECT_SIMPLESAMLPHP_CONFIG_DIR');
+        }
+        
         if ($configDirEnv !== false) {
             if (!is_dir($configDirEnv)) {
                 throw new \InvalidArgumentException(
                     sprintf(
-                        'Config directory specified by environment variable SIMPLESAMLPHP_CONFIG_DIR is not a ' .
+                        'Config directory specified by environment variable SIMPLESAMLPHP_CONFIG_DIR is not a '.
                         'directory.  Given: "%s"',
                         $configDirEnv
                     )
diff --git a/lib/SimpleSAML/Utils/Config/Metadata.php b/lib/SimpleSAML/Utils/Config/Metadata.php
index 133d9ffe9ab176e7b16dd6146490517e4521f7e2..0ef14d230d88ed7b5729a07a85ff8f2cdc9be002 100644
--- a/lib/SimpleSAML/Utils/Config/Metadata.php
+++ b/lib/SimpleSAML/Utils/Config/Metadata.php
@@ -9,7 +9,6 @@ namespace SimpleSAML\Utils\Config;
  */
 class Metadata
 {
-
     /**
      * The string that identities Entity Categories.
      *
@@ -36,7 +35,7 @@ class Metadata
      * @var array The valid configuration options for a contact configuration array.
      * @see "Metadata for the OASIS Security Assertion Markup Language (SAML) V2.0", section 2.3.2.2.
      */
-    public static $VALID_CONTACT_OPTIONS = array(
+    public static $VALID_CONTACT_OPTIONS = [
         'contactType',
         'emailAddress',
         'givenName',
@@ -44,20 +43,20 @@ class Metadata
         'telephoneNumber',
         'company',
         'attributes',
-    );
+    ];
 
 
     /**
      * @var array The valid types of contact for a contact configuration array.
      * @see "Metadata for the OASIS Security Assertion Markup Language (SAML) V2.0", section 2.3.2.2.
      */
-    public static $VALID_CONTACT_TYPES = array(
+    public static $VALID_CONTACT_TYPES = [
         'technical',
         'support',
         'administrative',
         'billing',
         'other',
-    );
+    ];
 
 
     /**
@@ -117,8 +116,8 @@ class Metadata
 
         // check attributes is an associative array
         if (isset($contact['attributes'])) {
-            if (empty($contact['attributes']) 
-                || !is_array($contact['attributes']) 
+            if (empty($contact['attributes'])
+                || !is_array($contact['attributes'])
                 || count(array_filter(array_keys($contact['attributes']), 'is_string')) === 0
             ) {
                 throw new \InvalidArgumentException('"attributes" must be an array and cannot be empty.');
diff --git a/lib/SimpleSAML/Utils/Crypto.php b/lib/SimpleSAML/Utils/Crypto.php
index 749d9d2db082b0e7bdf60f6f5ed12218ea29bfa9..dece1961c5b20f664509b951a7aba740b3908dda 100644
--- a/lib/SimpleSAML/Utils/Crypto.php
+++ b/lib/SimpleSAML/Utils/Crypto.php
@@ -2,14 +2,17 @@
 
 namespace SimpleSAML\Utils;
 
+use SimpleSAML\Configuration;
+use SimpleSAML\Error;
+
 /**
  * A class for cryptography-related functions.
  *
  * @package SimpleSAMLphp
  */
+
 class Crypto
 {
-
     /**
      * Decrypt data using AES-256-CBC and the key provided as a parameter.
      *
@@ -18,7 +21,7 @@ class Crypto
      *
      * @return string The decrypted data.
      * @throws \InvalidArgumentException If $ciphertext is not a string.
-     * @throws \SimpleSAML_Error_Exception If the openssl module is not loaded.
+     * @throws Error\Exception If the openssl module is not loaded.
      *
      * @see \SimpleSAML\Utils\Crypto::aesDecrypt()
      */
@@ -37,7 +40,7 @@ class Crypto
             );
         }
         if (!function_exists("openssl_decrypt")) {
-            throw new \SimpleSAML_Error_Exception("The openssl PHP module is not loaded.");
+            throw new Error\Exception("The openssl PHP module is not loaded.");
         }
 
         // derive encryption and authentication keys from the secret
@@ -62,7 +65,7 @@ class Crypto
             }
         }
 
-        throw new \SimpleSAML_Error_Exception("Failed to decrypt ciphertext.");
+        throw new Error\Exception("Failed to decrypt ciphertext.");
     }
 
 
@@ -73,7 +76,7 @@ class Crypto
      *
      * @return string The decrypted data.
      * @throws \InvalidArgumentException If $ciphertext is not a string.
-     * @throws \SimpleSAML_Error_Exception If the openssl module is not loaded.
+     * @throws Error\Exception If the openssl module is not loaded.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
@@ -92,7 +95,7 @@ class Crypto
      *
      * @return string An HMAC of the encrypted data, the IV and the encrypted data, concatenated.
      * @throws \InvalidArgumentException If $data is not a string.
-     * @throws \SimpleSAML_Error_Exception If the openssl module is not loaded.
+     * @throws Error\Exception If the openssl module is not loaded.
      *
      * @see \SimpleSAML\Utils\Crypto::aesEncrypt()
      */
@@ -103,7 +106,7 @@ class Crypto
         }
 
         if (!function_exists("openssl_encrypt")) {
-            throw new \SimpleSAML_Error_Exception('The openssl PHP module is not loaded.');
+            throw new Error\Exception('The openssl PHP module is not loaded.');
         }
 
         // derive encryption and authentication keys from the secret
@@ -123,7 +126,7 @@ class Crypto
         );
 
         if ($ciphertext === false) {
-            throw new \SimpleSAML_Error_Exception("Failed to encrypt plaintext.");
+            throw new Error\Exception("Failed to encrypt plaintext.");
         }
 
         // return the ciphertext with proper authentication
@@ -138,7 +141,7 @@ class Crypto
      *
      * @return string An HMAC of the encrypted data, the IV and the encrypted data, concatenated.
      * @throws \InvalidArgumentException If $data is not a string.
-     * @throws \SimpleSAML_Error_Exception If the openssl module is not loaded.
+     * @throws Error\Exception If the openssl module is not loaded.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
@@ -160,8 +163,8 @@ class Crypto
     public static function der2pem($der, $type = 'CERTIFICATE')
     {
         return "-----BEGIN ".$type."-----\n".
-               chunk_split(base64_encode($der), 64, "\n").
-               "-----END ".$type."-----\n";
+            chunk_split(base64_encode($der), 64, "\n").
+            "-----END ".$type."-----\n";
     }
 
 
@@ -176,7 +179,7 @@ class Crypto
      * - 'PEM': Data for the private key, in PEM-format.
      * - 'password': Password for the private key.
      *
-     * @param \SimpleSAML_Configuration $metadata The metadata array the private key should be loaded from.
+     * @param \SimpleSAML\Configuration $metadata The metadata array the private key should be loaded from.
      * @param bool                      $required Whether the private key is required. If this is true, a
      * missing key will cause an exception. Defaults to false.
      * @param string                    $prefix The prefix which should be used when reading from the metadata
@@ -186,13 +189,13 @@ class Crypto
      *
      * @return array|NULL Extracted private key, or NULL if no private key is present.
      * @throws \InvalidArgumentException If $required is not boolean or $prefix is not a string.
-     * @throws \SimpleSAML_Error_Exception If no private key is found in the metadata, or it was not possible to load
+     * @throws Error\Exception If no private key is found in the metadata, or it was not possible to load
      *     it.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      */
-    public static function loadPrivateKey(\SimpleSAML_Configuration $metadata, $required = false, $prefix = '', $full_path = false)
+    public static function loadPrivateKey(Configuration $metadata, $required = false, $prefix = '', $full_path = false)
     {
         if (!is_bool($required) || !is_string($prefix) || !is_bool($full_path)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
@@ -202,7 +205,7 @@ class Crypto
         if ($file === null) {
             // no private key found
             if ($required) {
-                throw new \SimpleSAML_Error_Exception('No private key found in metadata.');
+                throw new Error\Exception('No private key found in metadata.');
             } else {
                 return null;
             }
@@ -214,12 +217,12 @@ class Crypto
 
         $data = @file_get_contents($file);
         if ($data === false) {
-            throw new \SimpleSAML_Error_Exception('Unable to load private key from file "'.$file.'"');
+            throw new Error\Exception('Unable to load private key from file "'.$file.'"');
         }
 
-        $ret = array(
+        $ret = [
             'PEM' => $data,
-        );
+        ];
 
         if ($metadata->hasValue($prefix.'privatekey_pass')) {
             $ret['password'] = $metadata->getString($prefix.'privatekey_pass');
@@ -246,23 +249,23 @@ class Crypto
      * - 'certFingerprint': Array of valid certificate fingerprints. (Deprecated. Only present if this is a
      *   certificate.)
      *
-     * @param \SimpleSAML_Configuration $metadata The metadata.
+     * @param \SimpleSAML\Configuration $metadata The metadata.
      * @param bool                      $required Whether the private key is required. If this is TRUE, a missing key
      *     will cause an exception. Default is FALSE.
      * @param string                    $prefix The prefix which should be used when reading from the metadata array.
      *     Defaults to ''.
      *
      * @return array|NULL Public key or certificate data, or NULL if no public key or certificate was found.
-     * @throws \InvalidArgumentException If $metadata is not an instance of \SimpleSAML_Configuration, $required is not
+     * @throws \InvalidArgumentException If $metadata is not an instance of \SimpleSAML\Configuration, $required is not
      *     boolean or $prefix is not a string.
-     * @throws \SimpleSAML_Error_Exception If no private key is found in the metadata, or it was not possible to load
+     * @throws Error\Exception If no private key is found in the metadata, or it was not possible to load
      *     it.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      * @author Lasse Birnbaum Jensen
      */
-    public static function loadPublicKey(\SimpleSAML_Configuration $metadata, $required = false, $prefix = '')
+    public static function loadPublicKey(Configuration $metadata, $required = false, $prefix = '')
     {
         if (!is_bool($required) || !is_string($prefix)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
@@ -283,11 +286,11 @@ class Crypto
                     "-----END CERTIFICATE-----\n";
                 $certFingerprint = strtolower(sha1(base64_decode($certData)));
 
-                return array(
+                return [
                     'certData'        => $certData,
                     'PEM'             => $pem,
-                    'certFingerprint' => array($certFingerprint),
-                );
+                    'certFingerprint' => [$certFingerprint],
+                ];
             }
             // no valid key found
         } elseif ($metadata->hasValue($prefix.'certFingerprint')) {
@@ -304,12 +307,12 @@ class Crypto
              * We can't build a full certificate from a fingerprint, and may as well return an array with only the
              * fingerprint(s) immediately.
              */
-            return array('certFingerprint' => $fps);
+            return ['certFingerprint' => $fps];
         }
 
         // no public key/certificate available
         if ($required) {
-            throw new \SimpleSAML_Error_Exception('No public key / certificate found in metadata.');
+            throw new Error\Exception('No public key / certificate found in metadata.');
         } else {
             return null;
         }
@@ -355,7 +358,7 @@ class Crypto
      *
      * @return string The hashed password.
      * @throws \InvalidArgumentException If the input parameters are not strings.
-     * @throws \SimpleSAML_Error_Exception If the algorithm specified is not supported.
+     * @throws Error\Exception If the algorithm specified is not supported.
      *
      * @see hash_algos()
      *
@@ -376,7 +379,8 @@ class Crypto
         }
 
         // hash w/ salt
-        if ($salt === null) { // no salt provided, generate one
+        if ($salt === null) {
+            // no salt provided, generate one
             // default 8 byte salt, but 4 byte for LDAP SHA1 hashes
             $bytes = ($algorithm == 'SSHA1') ? 4 : 8;
             $salt = openssl_random_pseudo_bytes($bytes);
@@ -389,7 +393,7 @@ class Crypto
             return $alg_str.base64_encode($hash.$salt);
         }
 
-        throw new \SimpleSAML_Error_Exception('Hashing algorithm \''.strtolower($algorithm).'\' is not supported');
+        throw new Error\Exception('Hashing algorithm \''.strtolower($algorithm).'\' is not supported');
     }
 
 
@@ -433,7 +437,7 @@ class Crypto
      *
      * @return boolean True if the hash corresponds with the given password, false otherwise.
      * @throws \InvalidArgumentException If the input parameters are not strings.
-     * @throws \SimpleSAML_Error_Exception If the algorithm specified is not supported.
+     * @throws Error\Exception If the algorithm specified is not supported.
      *
      * @author Dyonisius Visser, TERENA <visser@terena.org>
      */
@@ -466,6 +470,6 @@ class Crypto
             return $hash === $password;
         }
 
-        throw new \SimpleSAML_Error_Exception('Hashing algorithm \''.strtolower($alg).'\' is not supported');
+        throw new Error\Exception('Hashing algorithm \''.strtolower($alg).'\' is not supported');
     }
 }
diff --git a/lib/SimpleSAML/Utils/HTTP.php b/lib/SimpleSAML/Utils/HTTP.php
index 4dd033346dd7aa0e64656390495e20978315fffe..da6ec639da285f10a7410622069284e41361c61f 100644
--- a/lib/SimpleSAML/Utils/HTTP.php
+++ b/lib/SimpleSAML/Utils/HTTP.php
@@ -1,8 +1,11 @@
 <?php
 namespace SimpleSAML\Utils;
 
-use SimpleSAML\Module;
+use SimpleSAML\Configuration;
 use SimpleSAML\Logger;
+use SimpleSAML\Module;
+use SimpleSAML\Session;
+use SimpleSAML\Error;
 
 /**
  * HTTP-related utility methods.
@@ -11,34 +14,33 @@ use SimpleSAML\Logger;
  */
 class HTTP
 {
-
     /**
      * Obtain a URL where we can redirect to securely post a form with the given data to a specific destination.
      *
      * @param string $destination The destination URL.
      * @param array  $data An associative array containing the data to be posted to $destination.
      *
-     * @throws \SimpleSAML_Error_Exception If the current session is transient.
+     * @throws Error\Exception If the current session is transient.
      * @return string  A URL which allows to securely post a form to $destination.
      *
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
     private static function getSecurePOSTRedirectURL($destination, $data)
     {
-        $session = \SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         $id = self::savePOSTData($session, $destination, $data);
 
         // get the session ID
         $session_id = $session->getSessionId();
         if (is_null($session_id)) {
             // this is a transient session, it is pointless to continue
-            throw new \SimpleSAML_Error_Exception('Cannot save POST data to a transient session.');
+            throw new Error\Exception('Cannot save POST data to a transient session.');
         }
 
         // encrypt the session ID and the random ID
         $info = base64_encode(Crypto::aesEncrypt($session_id.':'.$id));
 
-        $url = Module::getModuleURL('core/postredirect.php', array('RedirInfo' => $info));
+        $url = Module::getModuleURL('core/postredirect.php', ['RedirInfo' => $info]);
         return preg_replace('#^https:#', 'http:', $url);
     }
 
@@ -110,6 +112,9 @@ class HTTP
     {
         $default_port = self::getServerHTTPS() ? '443' : '80';
         $port = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $default_port;
+
+        // Take care of edge-case where SERVER_PORT is an integer
+        $port = strval($port);
         
         if ($port !== $default_port) {
             return ':'.$port;
@@ -141,7 +146,7 @@ class HTTP
      * @author Mads Freek Petersen
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
-    private static function redirect($url, $parameters = array())
+    private static function redirect($url, $parameters = [])
     {
         if (!is_string($url) || empty($url) || !is_array($parameters)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
@@ -202,7 +207,7 @@ class HTTP
     /**
      * Save the given HTTP POST data and the destination where it should be posted to a given session.
      *
-     * @param \SimpleSAML_Session $session The session where to temporarily store the data.
+     * @param \SimpleSAML\Session $session The session where to temporarily store the data.
      * @param string              $destination The destination URL where the form should be posted.
      * @param array               $data An associative array with the data to be posted to $destination.
      *
@@ -211,14 +216,14 @@ class HTTP
      * @author Andjelko Horvat
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
-    private static function savePOSTData(\SimpleSAML_Session $session, $destination, $data)
+    private static function savePOSTData(Session $session, $destination, $data)
     {
         // generate a random ID to avoid replay attacks
         $id = Random::generateID();
-        $postData = array(
+        $postData = [
             'post' => $data,
             'url'  => $destination,
-        );
+        ];
 
         // save the post data to the session, tied to the random ID
         $session->setData('core_postdatalink', $id, $postData);
@@ -248,13 +253,13 @@ class HTTP
 
         $queryStart = strpos($url, '?');
         if ($queryStart === false) {
-            $oldQuery = array();
+            $oldQuery = [];
             $url .= '?';
         } else {
             /** @var string|false $oldQuery */
             $oldQuery = substr($url, $queryStart + 1);
             if ($oldQuery === false) {
-                $oldQuery = array();
+                $oldQuery = [];
             } else {
                 $oldQuery = self::parseQueryString($oldQuery);
             }
@@ -286,7 +291,7 @@ class HTTP
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $session = \SimpleSAML_Session::getSessionFromRequest();
+        $session = Session::getSessionFromRequest();
         if ($session->hasSessionCookie()) {
             return;
         }
@@ -295,7 +300,7 @@ class HTTP
 
         $url = Module::getModuleURL('core/no_cookie.php');
         if ($retryURL !== null) {
-            $url = self::addURLParameters($url, array('retryURL' => $retryURL));
+            $url = self::addURLParameters($url, ['retryURL' => $retryURL]);
         }
         self::redirectTrustedURL($url);
     }
@@ -311,7 +316,7 @@ class HTTP
      * @return string The normalized URL itself if it is allowed. An empty string if the $url parameter is empty as
      * defined by the empty() function.
      * @throws \InvalidArgumentException If the URL is malformed.
-     * @throws \SimpleSAML_Error_Exception If the URL is not allowed by configuration.
+     * @throws Error\Exception If the URL is not allowed by configuration.
      *
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
@@ -323,12 +328,12 @@ class HTTP
         $url = self::normalizeURL($url);
 
         if (filter_var($url, FILTER_VALIDATE_URL) === false) {
-            throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url);
+            throw new Error\Exception('Invalid URL: '.$url);
         }
 
         // get the white list of domains
         if ($trustedSites === null) {
-            $trustedSites = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.domains', array());
+            $trustedSites = Configuration::getInstance()->getValue('trusted.url.domains', []);
         }
 
         // validates the URL's host is among those allowed
@@ -341,7 +346,7 @@ class HTTP
             if ((isset($components['user']) && strpos($components['user'], '\\') !== false) ||
                 (isset($components['pass']) && strpos($components['pass'], '\\') !== false)
             ) {
-                throw new \SimpleSAML_Error_Exception('Invalid URL: '.$url);
+                throw new Error\Exception('Invalid URL: '.$url);
             }
 
             // allow URLs with standard ports specified (non-standard ports must then be allowed explicitly)
@@ -354,7 +359,7 @@ class HTTP
 
             $self_host = self::getSelfHostWithNonStandardPort();
 
-            $trustedRegex = \SimpleSAML_Configuration::getInstance()->getValue('trusted.url.regex', false);
+            $trustedRegex = Configuration::getInstance()->getValue('trusted.url.regex', false);
 
             $trusted = false;
             if ($trustedRegex) {
@@ -376,7 +381,7 @@ class HTTP
 
             // throw exception due to redirection to untrusted site
             if (!$trusted) {
-                throw new \SimpleSAML_Error_Exception('URL not allowed: '.$url);
+                throw new Error\Exception('URL not allowed: '.$url);
             }
         }
         return $url;
@@ -396,19 +401,19 @@ class HTTP
      * @return string|array An array if $getHeaders is set, containing the data and the headers respectively; string
      *  otherwise.
      * @throws \InvalidArgumentException If the input parameters are invalid.
-     * @throws \SimpleSAML_Error_Exception If the file or URL cannot be retrieved.
+     * @throws Error\Exception If the file or URL cannot be retrieved.
      *
      * @author Andjelko Horvat
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      * @author Marco Ferrante, University of Genova <marco@csita.unige.it>
      */
-    public static function fetch($url, $context = array(), $getHeaders = false)
+    public static function fetch($url, $context = [], $getHeaders = false)
     {
         if (!is_string($url)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
 
         $proxy = $config->getString('proxy', null);
         if ($proxy !== null) {
@@ -417,7 +422,7 @@ class HTTP
             }
             $proxy_auth = $config->getString('proxy.auth', false);
             if ($proxy_auth !== false) {
-                $context['http']['header'] = "Proxy-Authorization: Basic".base64_encode($proxy_auth);
+                $context['http']['header'] = "Proxy-Authorization: Basic ".base64_encode($proxy_auth);
             }
             if (!isset($context['http']['request_fulluri'])) {
                 $context['http']['request_fulluri'] = true;
@@ -437,10 +442,10 @@ class HTTP
                 // extract the hostname
                 $hostname = parse_url($url, PHP_URL_HOST);
                 if (!empty($hostname)) {
-                    $context['ssl'] = array(
+                    $context['ssl'] = [
                         'SNI_server_name' => $hostname,
                         'SNI_enabled'     => true,
-                    );
+                    ];
                 } else {
                     Logger::warning('Invalid URL format or local URL used through a proxy');
                 }
@@ -451,17 +456,17 @@ class HTTP
         $data = @file_get_contents($url, false, $context);
         if ($data === false) {
             $error = error_get_last();
-            throw new \SimpleSAML_Error_Exception('Error fetching '.var_export($url, true).':'.
+            throw new Error\Exception('Error fetching '.var_export($url, true).':'.
                 (is_array($error) ? $error['message'] : 'no error available'));
         }
 
         // data and headers
         if ($getHeaders) {
             if (isset($http_response_header)) {
-                $headers = array();
+                $headers = [];
                 foreach ($http_response_header as $h) {
                     if (preg_match('@^HTTP/1\.[01]\s+\d{3}\s+@', $h)) {
-                        $headers = array(); // reset
+                        $headers = []; // reset
                         $headers[0] = $h;
                         continue;
                     }
@@ -474,7 +479,7 @@ class HTTP
                 // no HTTP headers, probably a different protocol, e.g. file
                 $headers = null;
             }
-            return array($data, $headers);
+            return [$data, $headers];
         }
 
         return $data;
@@ -496,12 +501,12 @@ class HTTP
     {
         if (!array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
             // no Accept-Language header, return an empty set
-            return array();
+            return [];
         }
 
         $languages = explode(',', strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']));
 
-        $ret = array();
+        $ret = [];
 
         foreach ($languages as $l) {
             $opts = explode(';', $l);
@@ -593,14 +598,13 @@ class HTTP
      */
     public static function getBaseURL()
     {
-        $globalConfig = \SimpleSAML_Configuration::getInstance();
+        $globalConfig = Configuration::getInstance();
         $baseURL = $globalConfig->getString('baseurlpath', 'simplesaml/');
 
         if (preg_match('#^https?://.*/?$#D', $baseURL, $matches)) {
             // full URL in baseurlpath, override local server values
             return rtrim($baseURL, '/').'/';
-        } elseif (
-            (preg_match('#^/?([^/]?.*/)$#D', $baseURL, $matches)) ||
+        } elseif ((preg_match('#^/?([^/]?.*/)$#D', $baseURL, $matches)) ||
             (preg_match('#^\*(.*)/$#D', $baseURL, $matches)) ||
             ($baseURL === '')
         ) {
@@ -634,16 +638,16 @@ class HTTP
     /**
      * Retrieve the first element of the URL path.
      *
-     * @param boolean $trailingslash Whether to add a trailing slash to the element or not. Defaults to true.
+     * @param boolean $leadingSlash Whether to add a leading slash to the element or not. Defaults to true.
      *
-     * @return string The first element of the URL path, with an optional, trailing slash.
+     * @return string The first element of the URL path, with an optional, leading slash.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
      */
-    public static function getFirstPathElement($trailingslash = true)
+    public static function getFirstPathElement($leadingSlash = true)
     {
         if (preg_match('|^/(.*?)/|', $_SERVER['SCRIPT_NAME'], $matches)) {
-            return ($trailingslash ? '/' : '').$matches[1];
+            return ($leadingSlash ? '/' : '').$matches[1];
         }
         return '';
     }
@@ -667,16 +671,17 @@ class HTTP
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
         $allowed = $config->getBoolean('enable.http_post', false);
 
         if ($allowed && preg_match("#^http:#", $destination) && self::isHTTPS()) {
             // we need to post the data to HTTP
             $url = self::getSecurePOSTRedirectURL($destination, $data);
-        } else { // post the data directly
-            $session = \SimpleSAML_Session::getSessionFromRequest();
+        } else {
+            // post the data directly
+            $session = Session::getSessionFromRequest();
             $id = self::savePOSTData($session, $destination, $data);
-            $url = Module::getModuleURL('core/postredirect.php', array('RedirId' => $id));
+            $url = Module::getModuleURL('core/postredirect.php', ['RedirId' => $id]);
         }
 
         return $url;
@@ -757,7 +762,7 @@ class HTTP
      */
     public static function getSelfURL()
     {
-        $cfg = \SimpleSAML_Configuration::getInstance();
+        $cfg = Configuration::getInstance();
         $baseDir = $cfg->getBaseDir();
         $cur_path = realpath($_SERVER['SCRIPT_FILENAME']);
         // make sure we got a string from realpath()
@@ -788,16 +793,16 @@ class HTTP
              * for this case in the configuration. First, check if that's the case.
              */
 
-            /** @var \SimpleSAML_Configuration $appcfg */
+            /** @var \SimpleSAML\Configuration $appcfg */
             $appcfg = $cfg->getConfigItem('application', null);
-            $appurl = ($appcfg instanceof \SimpleSAML_Configuration) ? $appcfg->getString('baseURL', '') : '';
+            $appurl = ($appcfg instanceof Configuration) ? $appcfg->getString('baseURL', '') : '';
             if (!empty($appurl)) {
                 $protocol = parse_url($appurl, PHP_URL_SCHEME);
                 $hostname = parse_url($appurl, PHP_URL_HOST);
                 $port = parse_url($appurl, PHP_URL_PORT);
                 $port = !empty($port) ? ':'.$port : '';
-
-            } else { // no base URL specified for app, just use the current URL
+            } else {
+                // no base URL specified for app, just use the current URL
                 $protocol = 'http';
                 $protocol .= (self::getServerHTTPS()) ? 's' : '';
                 $hostname = self::getServerHost();
@@ -806,7 +811,7 @@ class HTTP
             return $protocol.'://'.$hostname.$port.$_SERVER['REQUEST_URI'];
         }
 
-        return self::getBaseURL().$rel_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path));
+        return self::getBaseURL().$url_path.substr($_SERVER['REQUEST_URI'], $uri_pos + strlen($url_path));
     }
 
 
@@ -914,7 +919,7 @@ class HTTP
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $res = array();
+        $res = [];
         if (empty($query_string)) {
             return $res;
         }
@@ -955,7 +960,7 @@ class HTTP
      *
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
-    public static function redirectTrustedURL($url, $parameters = array())
+    public static function redirectTrustedURL($url, $parameters = [])
     {
         if (!is_string($url) || !is_array($parameters)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
@@ -968,7 +973,7 @@ class HTTP
 
     /**
      * This function redirects to the specified URL after performing the appropriate security checks on it.
-     * Particularly, it will make sure that the provided URL is allowed by the 'redirect.trustedsites' directive in the
+     * Particularly, it will make sure that the provided URL is allowed by the 'trusted.url.domains' directive in the
      * configuration.
      *
      * If the aforementioned option is not set or the URL does correspond to a trusted site, it performs a redirection
@@ -987,7 +992,7 @@ class HTTP
      *
      * @author Jaime Perez, UNINETT AS <jaime.perez@uninett.no>
      */
-    public static function redirectUntrustedURL($url, $parameters = array())
+    public static function redirectUntrustedURL($url, $parameters = [])
     {
         if (!is_string($url) || !is_array($parameters)) {
             throw new \InvalidArgumentException('Invalid input parameters.');
@@ -1110,7 +1115,7 @@ class HTTP
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $default_params = array(
+        $default_params = [
             'lifetime' => 0,
             'expire'   => null,
             'path'     => '/',
@@ -1118,7 +1123,7 @@ class HTTP
             'secure'   => false,
             'httponly' => true,
             'raw'      => false,
-        );
+        ];
 
         if ($params !== null) {
             $params = array_merge($default_params, $params);
@@ -1204,7 +1209,7 @@ class HTTP
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $config = \SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
         $allowed = $config->getBoolean('enable.http_post', false);
 
         if ($allowed && preg_match("#^http:#", $destination) && self::isHTTPS()) {
@@ -1212,7 +1217,7 @@ class HTTP
             self::redirect(self::getSecurePOSTRedirectURL($destination, $data));
         }
 
-        $p = new \SimpleSAML_XHTML_Template($config, 'post.php');
+        $p = new \SimpleSAML\XHTML\Template($config, 'post.php');
         $p->data['destination'] = $destination;
         $p->data['post'] = $data;
         $p->show();
diff --git a/lib/SimpleSAML/Utils/HttpAdapter.php b/lib/SimpleSAML/Utils/HttpAdapter.php
new file mode 100644
index 0000000000000000000000000000000000000000..b82392076342830ed41121630c09ef287210a96e
--- /dev/null
+++ b/lib/SimpleSAML/Utils/HttpAdapter.php
@@ -0,0 +1,211 @@
+<?php
+
+namespace SimpleSAML\Utils;
+
+/**
+ * Provides a non-static wrapper for the HTTP utility class.
+ *
+ * @package SimpleSAML\Utils
+ */
+class HttpAdapter
+{
+    /**
+     * @see HTTP::getServerHTTPS()
+     */
+    public function getServerHTTPS()
+    {
+        return HTTP::getServerHTTPS();
+    }
+
+    /**
+     * @see HTTP::getServerPort()
+     */
+    public function getServerPort()
+    {
+        return HTTP::getServerPort();
+    }
+
+    /**
+     * @see HTTP::addURLParameters()
+     */
+    public function addURLParameters($url, $parameters)
+    {
+        return HTTP::addURLParameters($url, $parameters);
+    }
+
+    /**
+     * @see HTTP::checkSessionCookie()
+     */
+    public function checkSessionCookie($retryURL = null)
+    {
+        HTTP::checkSessionCookie($retryURL);
+    }
+
+    /**
+     * @see HTTP::checkURLAllowed()
+     */
+    public function checkURLAllowed($url, array $trustedSites = null)
+    {
+        return HTTP::checkURLAllowed($url, $trustedSites);
+    }
+
+    /**
+     * @see HTTP::fetch()
+     */
+    public function fetch($url, $context = [], $getHeaders = false)
+    {
+        return HTTP::fetch($url, $context, $getHeaders);
+    }
+
+    /**
+     * @see HTTP::getAcceptLanguage()
+     */
+    public function getAcceptLanguage()
+    {
+        return HTTP::getAcceptLanguage();
+    }
+
+    /**
+     * @see HTTP::guessBasePath()
+     */
+    public function guessBasePath()
+    {
+        return HTTP::guessBasePath();
+    }
+
+    /**
+     * @see HTTP::getBaseURL()
+     */
+    public function getBaseURL()
+    {
+        return HTTP::getBaseURL();
+    }
+
+    /**
+     * @see HTTP::getFirstPathElement()
+     */
+    public function getFirstPathElement($trailingslash = true)
+    {
+        return HTTP::getFirstPathElement($trailingslash);
+    }
+
+    /**
+     * @see HTTP::getPOSTRedirectURL()
+     */
+    public function getPOSTRedirectURL($destination, $data)
+    {
+        return HTTP::getPOSTRedirectURL($destination, $data);
+    }
+
+    /**
+     * @see HTTP::getSelfHost()
+     */
+    public function getSelfHost()
+    {
+        return HTTP::getSelfHost();
+    }
+
+    /**
+     * @see HTTP::getSelfHostWithNonStandardPort()
+     */
+    public function getSelfHostWithNonStandardPort()
+    {
+        return HTTP::getSelfHostWithNonStandardPort();
+    }
+
+    /**
+     * @see HTTP::getSelfHostWithPath()
+     */
+    public function getSelfHostWithPath()
+    {
+        return HTTP::getSelfHostWithPath();
+    }
+
+    /**
+     * @see HTTP::getSelfURL()
+     */
+    public function getSelfURL()
+    {
+        return HTTP::getSelfURL();
+    }
+
+    /**
+     * @see HTTP::getSelfURLHost()
+     */
+    public function getSelfURLHost()
+    {
+        return HTTP::getSelfURLHost();
+    }
+
+    /**
+     * @see HTTP::getSelfURLNoQuery()
+     */
+    public function getSelfURLNoQuery()
+    {
+        return HTTP::getSelfURLNoQuery();
+    }
+
+    /**
+     * @see HTTP::isHTTPS()
+     */
+    public function isHTTPS()
+    {
+        return HTTP::isHTTPS();
+    }
+
+    /**
+     * @see HTTP::normalizeURL()
+     */
+    public function normalizeURL($url)
+    {
+        return HTTP::normalizeURL($url);
+    }
+
+    /**
+     * @see HTTP::parseQueryString()
+     */
+    public function parseQueryString($query_string)
+    {
+        return HTTP::parseQueryString($query_string);
+    }
+
+    /**
+     * @see HTTP::redirectTrustedURL()
+     */
+    public function redirectTrustedURL($url, $parameters = [])
+    {
+        HTTP::redirectTrustedURL($url, $parameters);
+    }
+
+    /**
+     * @see HTTP::redirectUntrustedURL()
+     */
+    public function redirectUntrustedURL($url, $parameters = [])
+    {
+        HTTP::redirectUntrustedURL($url, $parameters);
+    }
+
+    /**
+     * @see HTTP::resolveURL()
+     */
+    public function resolveURL($url, $base = null)
+    {
+        return HTTP::resolveURL($url, $base);
+    }
+
+    /**
+     * @see HTTP::setCookie()
+     */
+    public function setCookie($name, $value, $params = null, $throw = true)
+    {
+        HTTP::setCookie($name, $value, $params, $throw);
+    }
+
+    /**
+     * @see HTTP::submitPOSTData()
+     */
+    public function submitPOSTData($destination, $data)
+    {
+        HTTP::submitPOSTData($destination, $data);
+    }
+}
diff --git a/lib/SimpleSAML/Utils/Net.php b/lib/SimpleSAML/Utils/Net.php
index 96526ad68349438dd947424d32624eb0e633dfd6..02619d2215f88f34ca19579bc744dd7bc982912f 100644
--- a/lib/SimpleSAML/Utils/Net.php
+++ b/lib/SimpleSAML/Utils/Net.php
@@ -35,8 +35,8 @@ class Net
         list ($net, $mask) = explode('/', $cidr);
         $mask = intval($mask);
 
-        $ip_ip = array();
-        $ip_net = array();
+        $ip_ip = [];
+        $ip_net = [];
         if (strstr($ip, ':') || strstr($net, ':')) {
             // Validate IPv6 with inet_pton, convert to hex with bin2hex
             // then store as a long with hexdec
diff --git a/lib/SimpleSAML/Utils/Random.php b/lib/SimpleSAML/Utils/Random.php
index b53ace2e5a5f40e1af4632c40db0a3a4421018ac..f3db05154b9a83aa01e83136b4a7650a075d047e 100644
--- a/lib/SimpleSAML/Utils/Random.php
+++ b/lib/SimpleSAML/Utils/Random.php
@@ -25,6 +25,6 @@ class Random
      */
     public static function generateID()
     {
-        return '_'.bin2hex(openssl_random_pseudo_bytes((int)((self::ID_LENGTH - 1)/2)));
+        return '_'.bin2hex(openssl_random_pseudo_bytes((int) ((self::ID_LENGTH - 1) / 2)));
     }
-}
\ No newline at end of file
+}
diff --git a/lib/SimpleSAML/Utils/System.php b/lib/SimpleSAML/Utils/System.php
index 43c0b9b55431568f5d4ce3d0585ec5e7fb1343b0..6769ae9b6d83597d8e8078856e93560c38d75213 100644
--- a/lib/SimpleSAML/Utils/System.php
+++ b/lib/SimpleSAML/Utils/System.php
@@ -1,14 +1,17 @@
 <?php
+
 namespace SimpleSAML\Utils;
 
+use SimpleSAML\Error;
+
 /**
  * System-related utility methods.
  *
  * @package SimpleSAMLphp
  */
+
 class System
 {
-
     const WINDOWS = 1;
     const LINUX = 2;
     const OSX = 3;
@@ -60,7 +63,7 @@ class System
      * This function retrieves the path to a directory where temporary files can be saved.
      *
      * @return string Path to a temporary directory, without a trailing directory separator.
-     * @throws \SimpleSAML_Error_Exception If the temporary directory cannot be created or it exists and does not belong
+     * @throws Error\Exception If the temporary directory cannot be created or it exists and does not belong
      * to the current user.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
@@ -69,7 +72,7 @@ class System
      */
     public static function getTempDir()
     {
-        $globalConfig = \SimpleSAML_Configuration::getInstance();
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
 
         $tempDir = rtrim(
             $globalConfig->getString(
@@ -82,7 +85,7 @@ class System
         if (!is_dir($tempDir)) {
             if (!mkdir($tempDir, 0700, true)) {
                 $error = error_get_last();
-                throw new \SimpleSAML_Error_Exception(
+                throw new Error\Exception(
                     'Error creating temporary directory "'.$tempDir.'": '.
                     (is_array($error) ? $error['message'] : 'no error available')
                 );
@@ -91,7 +94,7 @@ class System
             // check that the owner of the temp directory is the current user
             $stat = lstat($tempDir);
             if ($stat['uid'] !== posix_getuid()) {
-                throw new \SimpleSAML_Error_Exception(
+                throw new Error\Exception(
                     'Temporary directory "'.$tempDir.'" does not belong to the current user.'
                 );
             }
@@ -118,17 +121,24 @@ class System
     public static function resolvePath($path, $base = null)
     {
         if ($base === null) {
-            $config = \SimpleSAML_Configuration::getInstance();
+            $config = \SimpleSAML\Configuration::getInstance();
             $base = $config->getBaseDir();
         }
 
+        // normalise directory separator
+        $base = str_replace('\\', '/', $base);
+        $path = str_replace('\\', '/', $path);
+
         // remove trailing slashes
         $base = rtrim($base, '/');
+        $path = rtrim($path, '/');
 
         // check for absolute path
         if (substr($path, 0, 1) === '/') {
             // absolute path. */
             $ret = '/';
+        } elseif (static::pathContainsDriveLetter($path)) {
+            $ret = '';
         } else {
             // path relative to base
             $ret = $base;
@@ -141,7 +151,7 @@ class System
             } elseif ($d === '..') {
                 $ret = dirname($ret);
             } else {
-                if (substr($ret, -1) !== '/') {
+                if ($ret && substr($ret, -1) !== '/') {
                     $ret .= '/';
                 }
                 $ret .= $d;
@@ -163,7 +173,7 @@ class System
      * @param int    $mode The permissions to apply to the file. Defaults to 0600.
      *
      * @throws \InvalidArgumentException If any of the input parameters doesn't have the proper types.
-     * @throws \SimpleSAML_Error_Exception If the file cannot be saved, permissions cannot be changed or it is not
+     * @throws Error\Exception If the file cannot be saved, permissions cannot be changed or it is not
      *     possible to write to the target file.
      *
      * @author Andreas Solberg, UNINETT AS <andreas.solberg@uninett.no>
@@ -184,7 +194,7 @@ class System
         $res = @file_put_contents($tmpFile, $data);
         if ($res === false) {
             $error = error_get_last();
-            throw new \SimpleSAML_Error_Exception(
+            throw new Error\Exception(
                 'Error saving file "'.$tmpFile.'": '.
                 (is_array($error) ? $error['message'] : 'no error available')
             );
@@ -195,7 +205,7 @@ class System
                 unlink($tmpFile);
                 $error = error_get_last();
                 //$error = (is_array($error) ? $error['message'] : 'no error available');
-                throw new \SimpleSAML_Error_Exception(
+                throw new Error\Exception(
                     'Error changing file mode of "'.$tmpFile.'": '.
                     (is_array($error) ? $error['message'] : 'no error available')
                 );
@@ -205,7 +215,7 @@ class System
         if (!rename($tmpFile, $filename)) {
             unlink($tmpFile);
             $error = error_get_last();
-            throw new \SimpleSAML_Error_Exception(
+            throw new Error\Exception(
                 'Error moving "'.$tmpFile.'" to "'.$filename.'": '.
                 (is_array($error) ? $error['message'] : 'no error available')
             );
@@ -215,4 +225,18 @@ class System
             opcache_invalidate($filename);
         }
     }
+
+    /**
+     * Check if the supplied path contains a Windows-style drive letter.
+     *
+     * @param string $path
+     *
+     * @return bool
+     */
+    private static function pathContainsDriveLetter($path)
+    {
+        $letterAsciiValue = ord(strtoupper(substr($path, 0, 1)));
+        return substr($path, 1, 1) === ':'
+                && $letterAsciiValue >= 65 && $letterAsciiValue <= 90;
+    }
 }
diff --git a/lib/SimpleSAML/Utils/Time.php b/lib/SimpleSAML/Utils/Time.php
index be8d47b2d9986a55c12d849bc490a42e59dcaef9..78246f9415fdd9d886b8c75c7d7c072b01821a9e 100644
--- a/lib/SimpleSAML/Utils/Time.php
+++ b/lib/SimpleSAML/Utils/Time.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Time-related utility methods.
  *
@@ -9,10 +10,8 @@ namespace SimpleSAML\Utils;
 
 use SimpleSAML\Logger;
 
-
 class Time
 {
-
     /**
      * Whether the timezone has been initialized or not.
      *
@@ -45,7 +44,7 @@ class Time
      *
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      *
-     * @throws \SimpleSAML_Error_Exception If the timezone set in the configuration is invalid.
+     * @throws \SimpleSAML\Error\Exception If the timezone set in the configuration is invalid.
      *
      * @return void
      */
@@ -55,12 +54,12 @@ class Time
             return;
         }
 
-        $globalConfig = \SimpleSAML_Configuration::getInstance();
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
 
         $timezone = $globalConfig->getString('timezone', null);
         if ($timezone !== null) {
             if (!date_default_timezone_set($timezone)) {
-                throw new \SimpleSAML_Error_Exception('Invalid timezone set in the "timezone" option in config.php.');
+                throw new \SimpleSAML\Error\Exception('Invalid timezone set in the "timezone" option in config.php.');
             }
             self::$tz_initialized = true;
             return;
diff --git a/lib/SimpleSAML/Utils/XML.php b/lib/SimpleSAML/Utils/XML.php
index 3f540d96a4ea1c07ba06057a224093b4847ced07..9b1f37766c0f24c75f8e654164f45b5bf151dfc7 100644
--- a/lib/SimpleSAML/Utils/XML.php
+++ b/lib/SimpleSAML/Utils/XML.php
@@ -25,7 +25,7 @@ class XML
      *
      * @throws \InvalidArgumentException If $message is not a string or $type is not a string containing one of the
      *     values allowed.
-     * @throws \SimpleSAML_Error_Exception If $message contains a doctype declaration.
+     * @throws \SimpleSAML\Error\Exception If $message contains a doctype declaration.
      *
      * @return void
      *
@@ -34,24 +34,25 @@ class XML
      */
     public static function checkSAMLMessage($message, $type)
     {
-        $allowed_types = array('saml20', 'saml11', 'saml-meta');
+        $allowed_types = ['saml20', 'saml11', 'saml-meta'];
         if (!(is_string($message) && in_array($type, $allowed_types, true))) {
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
         // a SAML message should not contain a doctype-declaration
         if (strpos($message, '<!DOCTYPE') !== false) {
-            throw new \SimpleSAML_Error_Exception('XML contained a doctype declaration.');
+            throw new \SimpleSAML\Error\Exception('XML contained a doctype declaration.');
         }
 
         // see if debugging is enabled for XML validation
-        $debug = \SimpleSAML_Configuration::getInstance()->getArrayize('debug', array('validatexml' => false));
-        $enabled = \SimpleSAML_Configuration::getInstance()->getBoolean('debug.validatexml', false);
+        $debug = \SimpleSAML\Configuration::getInstance()->getArrayize('debug', ['validatexml' => false]);
+        $enabled = \SimpleSAML\Configuration::getInstance()->getBoolean('debug.validatexml', false);
 
         if (!(in_array('validatexml', $debug, true) // implicitly enabled
-              || (array_key_exists('validatexml', $debug) && $debug['validatexml'] === true) // explicitly enabled
-              // TODO: deprecate this option and remove it in 2.0
-              || $enabled // old 'debug.validatexml' configuration option
+            || (array_key_exists('validatexml', $debug) && $debug['validatexml'] === true)
+            // explicitly enabled
+            // TODO: deprecate this option and remove it in 2.0
+            || $enabled // old 'debug.validatexml' configuration option
         )) {
             // XML validation is disabled
             return;
@@ -98,12 +99,13 @@ class XML
         }
 
         // see if debugging is enabled for SAML messages
-        $debug = \SimpleSAML_Configuration::getInstance()->getArrayize('debug', array('saml' => false));
+        $debug = \SimpleSAML\Configuration::getInstance()->getArrayize('debug', ['saml' => false]);
 
         if (!(in_array('saml', $debug, true) // implicitly enabled
-              || (array_key_exists('saml', $debug) && $debug['saml'] === true) // explicitly enabled
-              // TODO: deprecate the old style and remove it in 2.0
-              || (array_key_exists(0, $debug) && $debug[0] === true) // old style 'debug'
+            || (array_key_exists('saml', $debug) && $debug['saml'] === true)
+            // explicitly enabled
+            // TODO: deprecate the old style and remove it in 2.0
+            || (array_key_exists(0, $debug) && $debug[0] === true) // old style 'debug'
         )) {
             // debugging messages is disabled
             return;
@@ -161,8 +163,8 @@ class XML
 
         // check what this element contains
         $fullText = ''; // all text in this element
-        $textNodes = array(); // text nodes which should be deleted
-        $childNodes = array(); // other child nodes
+        $textNodes = []; // text nodes which should be deleted
+        $childNodes = []; // other child nodes
         for ($i = 0; $i < $root->childNodes->length; $i++) {
             /** @var \DOMElement $child */
             $child = $root->childNodes->item($i);
@@ -283,7 +285,7 @@ class XML
             throw new \InvalidArgumentException('Invalid input parameters.');
         }
 
-        $ret = array();
+        $ret = [];
 
         for ($i = 0; $i < $element->childNodes->length; $i++) {
             /** @var \DOMElement $child */
@@ -309,7 +311,7 @@ class XML
      * @param \DOMElement $element The element we should extract text from.
      *
      * @return string The text content of the element.
-     * @throws \SimpleSAML_Error_Exception If the element contains a non-text child node.
+     * @throws \SimpleSAML\Error\Exception If the element contains a non-text child node.
      *
      * @author Olav Morken, UNINETT AS <olav.morken@uninett.no>
      */
@@ -321,7 +323,7 @@ class XML
             /** @var \DOMElement $child */
             $child = $element->childNodes->item($i);
             if (!($child instanceof \DOMText)) {
-                throw new \SimpleSAML_Error_Exception($element->localName.' contained a non-text child node.');
+                throw new \SimpleSAML\Error\Exception($element->localName.' contained a non-text child node.');
             }
 
             $txt .= $child->wholeText;
@@ -364,7 +366,7 @@ class XML
         // check if the namespace is a shortcut, and expand it if it is
         if ($nsURI[0] === '@') {
             // the defined shortcuts
-            $shortcuts = array(
+            $shortcuts = [
                 '@ds'      => 'http://www.w3.org/2000/09/xmldsig#',
                 '@md'      => 'urn:oasis:names:tc:SAML:2.0:metadata',
                 '@saml1'   => 'urn:oasis:names:tc:SAML:1.0:assertion',
@@ -373,7 +375,7 @@ class XML
                 '@saml2'   => 'urn:oasis:names:tc:SAML:2.0:assertion',
                 '@saml2p'  => 'urn:oasis:names:tc:SAML:2.0:protocol',
                 '@shibmd'  => 'urn:mace:shibboleth:metadata:1.0',
-            );
+            ];
 
             // check if it is a valid shortcut
             if (!array_key_exists($nsURI, $shortcuts)) {
@@ -429,11 +431,10 @@ class XML
         }
 
         if ($res) {
-            $config = \SimpleSAML_Configuration::getInstance();
+            $config = \SimpleSAML\Configuration::getInstance();
             /** @var string $schemaPath */
             $schemaPath = $config->resolvePath('schemas');
-            $schemaPath .= './';
-            $schemaFile = $schemaPath.$schema;
+            $schemaFile = $schemaPath.'/'.$schema;
 
             $res = $dom->schemaValidate($schemaFile);
             if ($res) {
diff --git a/lib/SimpleSAML/XHTML/EMail.php b/lib/SimpleSAML/XHTML/EMail.php
index 9638920e940b5f8dd1cedb190f15f49fc0fc7272..a9e239029b44de780c892dbb55e7ef35bda688e2 100644
--- a/lib/SimpleSAML/XHTML/EMail.php
+++ b/lib/SimpleSAML/XHTML/EMail.php
@@ -1,50 +1,54 @@
 <?php
 
+namespace SimpleSAML\XHTML;
+
 /**
  * A minimalistic Emailer class. Creates and sends HTML emails.
  *
  * @author Andreas kre Solberg, UNINETT AS. <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_XHTML_EMail
+
+class EMail
 {
-	private $to = null;
-	private $cc = null;
-	private $body = null;
-	private $from = null;
-	private $replyto = null;
-	private $subject = null;
-	private $headers = array();
-	
-
-	/**
-	 * Constructor
-	 */
-	public function __construct($to, $subject, $from = null, $cc = null, $replyto = null)
+    private $to = null;
+    private $cc = null;
+    private $body = null;
+    private $from = null;
+    private $replyto = null;
+    private $subject = null;
+    private $headers = [];
+
+
+    /**
+     * Constructor
+     */
+    public function __construct($to, $subject, $from = null, $cc = null, $replyto = null)
     {
-		$this->to = $to;
-		$this->cc = $cc;
-		$this->from = $from;
-		$this->replyto = $replyto;
-		$this->subject = $subject;
-	}
-
-	/*
+        $this->to = $to;
+        $this->cc = $cc;
+        $this->from = $from;
+        $this->replyto = $replyto;
+        $this->subject = $subject;
+    }
+
+    /*
      * @param string $body
      * @return void
      */
     public function setBody($body)
     {
-		$this->body = $body;
-	}
+        $this->body = $body;
+    }
 
 
-	/*
+    /*
      * @param string $body
-     * @return void
+     * @return string
      */
-	private function getHTML($body) {
-		return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    private function getHTML($body)
+    {
+        return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 <head>
@@ -64,56 +68,58 @@ pre {
 </head>
 <body>
 <div class="container" style="background: #fafafa; border: 1px solid #eee; margin: 2em; padding: .6em;">
-' . $body . '
+'.$body.'
 </div>
 </body>
 </html>';
-	}
+    }
 
 
     /*
      * @return void
      */
-	public function send()
+    public function send()
     {
-		if ($this->to === null) {
-            throw new Exception('EMail field [to] is required and not set.');
+        if ($this->to === null) {
+            throw new \Exception('EMail field [to] is required and not set.');
         } elseif ($this->subject === null) {
-            throw new Exception('EMail field [subject] is required and not set.');
+            throw new \Exception('EMail field [subject] is required and not set.');
         } elseif ($this->body === null) {
-            throw new Exception('EMail field [body] is required and not set.');
+            throw new \Exception('EMail field [body] is required and not set.');
+        }
+
+        $random_hash = bin2hex(openssl_random_pseudo_bytes(16));
+
+        if (isset($this->from)) {
+            $this->headers[] = 'From: '.$this->from;
+        }
+        if (isset($this->replyto)) {
+            $this->headers[] = 'Reply-To: '.$this->replyto;
         }
-		
-		$random_hash = bin2hex(openssl_random_pseudo_bytes(16));
-		
-		if (isset($this->from))
-			$this->headers[]= 'From: ' . $this->from;
-		if (isset($this->replyto))
-			$this->headers[]= 'Reply-To: ' . $this->replyto;
-
-		$this->headers[] = 'Content-Type: multipart/alternative; boundary="simplesamlphp-' . $random_hash . '"'; 
-		
-		$message = '
---simplesamlphp-' . $random_hash . '
+
+        $this->headers[] = 'Content-Type: multipart/alternative; boundary="simplesamlphp-'.$random_hash.'"';
+
+        $message = '
+--simplesamlphp-'.$random_hash.'
 Content-Type: text/plain; charset="utf-8" 
 Content-Transfer-Encoding: 8bit
 
-' . strip_tags(html_entity_decode($this->body)) . '
+'.strip_tags(html_entity_decode($this->body)).'
 
---simplesamlphp-' . $random_hash . '
+--simplesamlphp-'.$random_hash.'
 Content-Type: text/html; charset="utf-8" 
 Content-Transfer-Encoding: 8bit
 
-' . $this->getHTML($this->body) . '
+'.$this->getHTML($this->body).'
 
---simplesamlphp-' . $random_hash . '--
+--simplesamlphp-'.$random_hash.'--
 ';
-		$headers = implode("\n", $this->headers);
+        $headers = implode("\n", $this->headers);
 
-		$mail_sent = @mail($this->to, $this->subject, $message, $headers);
-		SimpleSAML\Logger::debug('Email: Sending e-mail to [' . $this->to . '] : ' . ($mail_sent ? 'OK' : 'Failed'));
-		if (!$mail_sent) {
-            throw new Exception('Error when sending e-mail');
+        $mail_sent = @mail($this->to, $this->subject, $message, $headers);
+        \SimpleSAML\Logger::debug('Email: Sending e-mail to ['.$this->to.'] : '.($mail_sent ? 'OK' : 'Failed'));
+        if (!$mail_sent) {
+            throw new \Exception('Error when sending e-mail');
         }
-	}
+    }
 }
diff --git a/lib/SimpleSAML/XHTML/IdPDisco.php b/lib/SimpleSAML/XHTML/IdPDisco.php
index 70b06d7172c5640e9d217e79d02e5ffcd401b73d..51449f95f970297a48f2fe11bfe1278ac43a04f9 100644
--- a/lib/SimpleSAML/XHTML/IdPDisco.php
+++ b/lib/SimpleSAML/XHTML/IdPDisco.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\XHTML;
 
 /**
  * This class implements a generic IdP discovery service, for use in various IdP
@@ -13,13 +14,13 @@
  * @author Andreas Ă…kre Solberg <andreas@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class SimpleSAML_XHTML_IdPDisco
-{
 
+class IdPDisco
+{
     /**
      * An instance of the configuration class.
      *
-     * @var SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     protected $config;
 
@@ -34,7 +35,7 @@ class SimpleSAML_XHTML_IdPDisco
     /**
      * An instance of the metadata handler, which will allow us to fetch metadata about IdPs.
      *
-     * @var SimpleSAML_Metadata_MetaDataStorageHandler
+     * @var \SimpleSAML\Metadata\MetaDataStorageHandler
      */
     protected $metadata;
 
@@ -42,7 +43,7 @@ class SimpleSAML_XHTML_IdPDisco
     /**
      * The users session.
      *
-     * @var SimpleSAML_Session
+     * @var \SimpleSAML\Session
      */
     protected $session;
 
@@ -93,7 +94,7 @@ class SimpleSAML_XHTML_IdPDisco
      *
      * @var array
      */
-    protected $scopedIDPList = array();
+    protected $scopedIDPList = [];
 
     /**
      * The URL the user should be redirected to after choosing an IdP.
@@ -118,9 +119,9 @@ class SimpleSAML_XHTML_IdPDisco
         assert(is_string($instance));
 
         // initialize standard classes
-        $this->config = SimpleSAML_Configuration::getInstance();
-        $this->metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
-        $this->session = SimpleSAML_Session::getSessionFromRequest();
+        $this->config = \SimpleSAML\Configuration::getInstance();
+        $this->metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
+        $this->session = \SimpleSAML\Session::getSessionFromRequest();
         $this->instance = $instance;
         $this->metadataSets = $metadataSets;
 
@@ -128,7 +129,7 @@ class SimpleSAML_XHTML_IdPDisco
 
         // standard discovery service parameters
         if (!array_key_exists('entityID', $_GET)) {
-            throw new Exception('Missing parameter: entityID');
+            throw new \Exception('Missing parameter: entityID');
         } else {
             $this->spEntityId = $_GET['entityID'];
         }
@@ -142,7 +143,7 @@ class SimpleSAML_XHTML_IdPDisco
         $this->log('returnIdParam initially set to ['.$this->returnIdParam.']');
 
         if (!array_key_exists('return', $_GET)) {
-            throw new Exception('Missing parameter: return');
+            throw new \Exception('Missing parameter: return');
         } else {
             $this->returnURL = \SimpleSAML\Utils\HTTP::checkURLAllowed($_GET['return']);
         }
@@ -175,7 +176,7 @@ class SimpleSAML_XHTML_IdPDisco
      */
     protected function log($message)
     {
-        SimpleSAML\Logger::info('idpDisco.'.$this->instance.': '.$message);
+        \SimpleSAML\Logger::info('idpDisco.'.$this->instance.': '.$message);
     }
 
 
@@ -213,13 +214,13 @@ class SimpleSAML_XHTML_IdPDisco
     {
         $prefixedName = 'idpdisco_'.$this->instance.'_'.$name;
 
-        $params = array(
+        $params = [
             // we save the cookies for 90 days
             'lifetime' => (60 * 60 * 24 * 90),
             // the base path for cookies. This should be the installation directory for SimpleSAMLphp
             'path'     => $this->config->getBasePath(),
             'httponly' => false,
-        );
+        ];
 
         \SimpleSAML\Utils\HTTP::setCookie($prefixedName, $value, $params, false);
     }
@@ -249,7 +250,7 @@ class SimpleSAML_XHTML_IdPDisco
             try {
                 $this->metadata->getMetaData($idp, $metadataSet);
                 return $idp;
-            } catch (Exception $e) {
+            } catch (\Exception $e) {
                 // continue
             }
         }
@@ -289,7 +290,7 @@ class SimpleSAML_XHTML_IdPDisco
          * back. Therefore we do some quick and dirty parsing of the query string.
          */
         $qstr = $_SERVER['QUERY_STRING'];
-        $matches = array();
+        $matches = [];
         if (preg_match('/(?:^|&)idp_([^=]+)=/', $qstr, $matches)) {
             return $this->validateIdP(urldecode($matches[1]));
         }
@@ -458,7 +459,7 @@ class SimpleSAML_XHTML_IdPDisco
      */
     protected function getIdPList()
     {
-        $idpList = array();
+        $idpList = [];
         foreach ($this->metadataSets as $metadataSet) {
             $newList = $this->metadata->getList($metadataSet);
             /*
@@ -511,23 +512,23 @@ class SimpleSAML_XHTML_IdPDisco
      */
     protected function start()
     {
-        $idp = $this->getTargetIdp();
+        $idp = $this->getTargetIdP();
         if ($idp !== null) {
             $extDiscoveryStorage = $this->config->getString('idpdisco.extDiscoveryStorage', null);
             if ($extDiscoveryStorage !== null) {
                 $this->log('Choice made ['.$idp.'] (Forwarding to external discovery storage)');
-                \SimpleSAML\Utils\HTTP::redirectTrustedURL($extDiscoveryStorage, array(
+                \SimpleSAML\Utils\HTTP::redirectTrustedURL($extDiscoveryStorage, [
                     'entityID'      => $this->spEntityId,
                     'IdPentityID'   => $idp,
                     'returnIDParam' => $this->returnIdParam,
                     'isPassive'     => 'true',
                     'return'        => $this->returnURL
-                ));
+                ]);
             } else {
                 $this->log(
                     'Choice made ['.$idp.'] (Redirecting the user back. returnIDParam='.$this->returnIdParam.')'
                 );
-                \SimpleSAML\Utils\HTTP::redirectTrustedURL($this->returnURL, array($this->returnIdParam => $idp));
+                \SimpleSAML\Utils\HTTP::redirectTrustedURL($this->returnURL, [$this->returnIdParam => $idp]);
             }
         }
 
@@ -566,7 +567,7 @@ class SimpleSAML_XHTML_IdPDisco
             );
             \SimpleSAML\Utils\HTTP::redirectTrustedURL(
                 $this->returnURL,
-                array($this->returnIdParam => $idpintersection[0])
+                [$this->returnIdParam => $idpintersection[0]]
             );
         }
 
@@ -582,11 +583,48 @@ class SimpleSAML_XHTML_IdPDisco
                 $templateFile = 'selectidp-links.php';
                 break;
             default:
-                throw new Exception('Invalid value for the \'idpdisco.layout\' option.');
+                throw new \Exception('Invalid value for the \'idpdisco.layout\' option.');
+        }
+
+        $t = new Template($this->config, $templateFile, 'disco');
+
+        $fallbackLanguage = 'en';
+        $defaultLanguage = $this->config->getString('language.default', $fallbackLanguage);
+        $translator = $t->getTranslator();
+        $language = $translator->getLanguage()->getLanguage();
+        $tryLanguages = [0 => $language, 1 => $defaultLanguage, 2 => $fallbackLanguage];
+
+        $newlist = [];
+        foreach ($idpList as $entityid => $data) {
+            $newlist[$entityid]['entityid'] = $entityid;
+            foreach ($tryLanguages as $lang) {
+                if ($name = $this->getEntityDisplayName($data, $lang)) {
+                    $newlist[$entityid]['name'] = $name;
+                    continue;
+                }
+            }
+            if (empty($newlist[$entityid]['name'])) {
+                $newlist[$entityid]['name'] = $entityid;
+            }
+            foreach ($tryLanguages as $lang) {
+                if (!empty($data['description'][$lang])) {
+                    $newlist[$entityid]['description'] = $data['description'][$lang];
+                    continue;
+                }
+            }
+            if (!empty($data['icon'])) {
+                $newlist[$entityid]['icon'] = $data['icon'];
+                $newlist[$entityid]['iconurl'] = \SimpleSAML\Utils\HTTP::resolveURL($data['icon']);
+            }
         }
+        usort(
+            $newlist,
+            function ($idpentry1, $idpentry2) {
+                return strcasecmp($idpentry1['name'], $idpentry2['name']);
+            }
+        );
 
-        $t = new SimpleSAML_XHTML_Template($this->config, $templateFile, 'disco');
-        $t->data['idplist'] = $idpList;
+        $t->data['idplist'] = $newlist;
         $t->data['preferredidp'] = $preferredIdP;
         $t->data['return'] = $this->returnURL;
         $t->data['returnIDParam'] = $this->returnIdParam;
@@ -595,4 +633,16 @@ class SimpleSAML_XHTML_IdPDisco
         $t->data['rememberenabled'] = $this->config->getBoolean('idpdisco.enableremember', false);
         $t->show();
     }
+
+    private function getEntityDisplayName(array $idpData, $language)
+    {
+        if (isset($idpData['UIInfo']['DisplayName'][$language])) {
+            return $idpData['UIInfo']['DisplayName'][$language];
+        } elseif (isset($idpData['name'][$language])) {
+            return $idpData['name'][$language];
+        } elseif (isset($idpData['OrganizationDisplayName'][$language])) {
+            return $idpData['OrganizationDisplayName'][$language];
+        }
+        return null;
+    }
 }
diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
index 844ed4cc1514ce96d4a68a531c7a51aecdf12adb..3ae190b88a82062c04bbeaa839c5e7ee9ae25078 100644
--- a/lib/SimpleSAML/XHTML/Template.php
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\XHTML;
 
 /**
  * A minimalistic XHTML PHP based template system implemented for SimpleSAMLphp.
@@ -11,14 +12,14 @@
 use JaimePerez\TwigConfigurableI18n\Twig\Environment as Twig_Environment;
 use JaimePerez\TwigConfigurableI18n\Twig\Extensions\Extension\I18n as Twig_Extensions_Extension_I18n;
 
-class SimpleSAML_XHTML_Template
+class Template
 {
     /**
      * The data associated with this template, accessible within the template itself.
      *
      * @var array
      */
-    public $data = array();
+    public $data = [];
 
     /**
      * A translator instance configured to work with this template.
@@ -37,7 +38,7 @@ class SimpleSAML_XHTML_Template
     /**
      * The configuration to use in this template.
      *
-     * @var SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $configuration;
 
@@ -72,9 +73,9 @@ class SimpleSAML_XHTML_Template
      *
      * Used to intercept certain parts of the template handling, while keeping away unwanted/unexpected hooks. Set
      * the 'theme.controller' configuration option to a class that implements the
-     * SimpleSAML\XHTML\TemplateControllerInterface interface to use it.
+     * \SimpleSAML\XHTML\TemplateControllerInterface interface to use it.
      *
-     * @var SimpleSAML\XHTML\TemplateControllerInterface
+     * @var \SimpleSAML\XHTML\TemplateControllerInterface
      */
     private $controller;
 
@@ -93,11 +94,11 @@ class SimpleSAML_XHTML_Template
     /**
      * Constructor
      *
-     * @param SimpleSAML_Configuration $configuration Configuration object
+     * @param \SimpleSAML\Configuration $configuration Configuration object
      * @param string                   $template Which template file to load
      * @param string|null              $defaultDictionary The default dictionary where tags will come from.
      */
-    public function __construct(\SimpleSAML_Configuration $configuration, $template, $defaultDictionary = null)
+    public function __construct(\SimpleSAML\Configuration $configuration, $template, $defaultDictionary = null)
     {
         $this->configuration = $configuration;
         $this->template = $template;
@@ -108,18 +109,18 @@ class SimpleSAML_XHTML_Template
         list($this->module) = $this->findModuleAndTemplateName($template);
 
         // parse config to find theme and module theme is in, if any
-        list($this->theme['module'], $this->theme['name']) = self::findModuleAndTemplateName(
+        list($this->theme['module'], $this->theme['name']) = $this->findModuleAndTemplateName(
             $this->configuration->getString('theme.use', 'default')
         );
 
         // initialize internationalization system
-        $this->translator = new SimpleSAML\Locale\Translate($configuration, $defaultDictionary);
+        $this->translator = new \SimpleSAML\Locale\Translate($configuration, $defaultDictionary);
         $this->localization = new \SimpleSAML\Locale\Localization($configuration);
 
         // check if we need to attach a theme controller
         $controller = $this->configuration->getString('theme.controller', false);
         if ($controller && class_exists($controller) &&
-            class_implements($controller, '\SimpleSAML\XHTML\TemplateControllerInterface')
+            in_array('\SimpleSAML\XHTML\TemplateControllerInterface', class_implements($controller))
         ) {
             $this->controller = new $controller();
         }
@@ -154,33 +155,35 @@ class SimpleSAML_XHTML_Template
     /**
      * Set up the places where twig can look for templates.
      *
-     * @return Twig_Loader_Filesystem The twig template loader or false if the template does not exist.
-     * @throws Twig_Error_Loader In case a failure occurs.
+     * @return TemplateLoader The twig template loader or false if the template does not exist.
+     * @throws \Twig_Error_Loader In case a failure occurs.
      */
     private function setupTwigTemplatepaths()
     {
         $filename = $this->normalizeTemplateName($this->template);
 
         // get namespace if any
-        list($namespace, $filename) = self::findModuleAndTemplateName($filename);
+        list($namespace, $filename) = $this->findModuleAndTemplateName($filename);
         $this->twig_template = ($namespace !== null) ? '@'.$namespace.'/'.$filename : $filename;
-        $loader = new \Twig_Loader_Filesystem();
+        $loader = new TemplateLoader();
         $templateDirs = $this->findThemeTemplateDirs();
         if ($this->module) {
-            $templateDirs[] = array($this->module => $this->getModuleTemplateDir($this->module));
+            $templateDirs[] = [$this->module => TemplateLoader::getModuleTemplateDir($this->module)];
         }
         if ($this->theme['module']) {
             try {
-                $templateDirs[] = array($this->theme['module'] => $this->getModuleTemplateDir($this->theme['module']));
+                $templateDirs[] = [
+                    $this->theme['module'] => TemplateLoader::getModuleTemplateDir($this->theme['module'])
+                ];
             } catch (\InvalidArgumentException $e) {
                 // either the module is not enabled or it has no "templates" directory, ignore
             }
         }
 
         // default, themeless templates are checked last
-        $templateDirs[] = array(
+        $templateDirs[] = [
             \Twig_Loader_Filesystem::MAIN_NAMESPACE => $this->configuration->resolvePath('templates')
-        );
+        ];
         foreach ($templateDirs as $entry) {
             $loader->addPath($entry[key($entry)], key($entry));
         }
@@ -210,20 +213,20 @@ class SimpleSAML_XHTML_Template
             $this->localization->addModuleDomain($this->theme['module']);
         }
 
-        $options = array(
+        $options = [
             'cache' => $cache,
             'auto_reload' => $auto_reload,
-            'translation_function' => array('\SimpleSAML\Locale\Translate', 'translateSingularNativeGettext'),
-            'translation_function_plural' => array('\SimpleSAML\Locale\Translate', 'translatePluralNativeGettext'),
-        );
+            'translation_function' => ['\SimpleSAML\Locale\Translate', 'translateSingularNativeGettext'],
+            'translation_function_plural' => ['\SimpleSAML\Locale\Translate', 'translatePluralNativeGettext'],
+        ];
 
         // set up translation
         if ($this->localization->i18nBackend === \SimpleSAML\Locale\Localization::GETTEXT_I18N_BACKEND) {
-            $options['translation_function'] = array('\SimpleSAML\Locale\Translate', 'translateSingularGettext');
-            $options['translation_function_plural'] = array(
+            $options['translation_function'] = ['\SimpleSAML\Locale\Translate', 'translateSingularGettext'];
+            $options['translation_function_plural'] = [
                 '\SimpleSAML\Locale\Translate',
                 'translatePluralGettext'
-            );
+            ];
         } // TODO: add a branch for the old SimpleSAMLphp backend
 
         $twig = new Twig_Environment($loader, $options);
@@ -250,8 +253,8 @@ class SimpleSAML_XHTML_Template
         $twig->addFilter(
             new \Twig_SimpleFilter(
                 'translateFromArray',
-                array('\SimpleSAML\Locale\Translate', 'translateFromArray'),
-                array('needs_context' => true)
+                ['\SimpleSAML\Locale\Translate', 'translateFromArray'],
+                ['needs_context' => true]
             )
         );
 
@@ -269,20 +272,22 @@ class SimpleSAML_XHTML_Template
      */
     private function findThemeTemplateDirs()
     {
-        if ($this->theme['module'] === null) { // no module involved
-            return array();
+        if ($this->theme['module'] === null) {
+            // no module involved
+            return [];
         }
 
         // setup directories & namespaces
         $themeDir = \SimpleSAML\Module::getModuleDir($this->theme['module']).'/themes/'.$this->theme['name'];
         $subdirs = scandir($themeDir);
-        if (empty($subdirs)) { // no subdirectories in the theme directory, nothing to do here
+        if (empty($subdirs)) {
+            // no subdirectories in the theme directory, nothing to do here
             // this is probably wrong, log a message
-            \SimpleSAML\Logger::warning('Emtpy theme directory for theme "'.$this->theme['name'].'".');
-            return array();
+            \SimpleSAML\Logger::warning('Empty theme directory for theme "'.$this->theme['name'].'".');
+            return [];
         }
 
-        $themeTemplateDirs = array();
+        $themeTemplateDirs = [];
         foreach ($subdirs as $entry) {
             // discard anything that's not a directory. Expression is negated to profit from lazy evaluation
             if (!($entry !== '.' && $entry !== '..' && is_dir($themeDir.'/'.$entry))) {
@@ -291,29 +296,29 @@ class SimpleSAML_XHTML_Template
 
             // set correct name for the default namespace
             $ns = ($entry === 'default') ? \Twig_Loader_Filesystem::MAIN_NAMESPACE : $entry;
-            $themeTemplateDirs[] = array($ns => $themeDir.'/'.$entry);
+            $themeTemplateDirs[] = [$ns => $themeDir.'/'.$entry];
         }
         return $themeTemplateDirs;
     }
 
+
     /**
      * Get the template directory of a module, if it exists.
      *
-     * @return string The templates directory of a module.
+     * @return string The templates directory of a module
      *
-     * @throws InvalidArgumentException If the module is not enabled or it has no templates directory.
+     * @throws \InvalidArgumentException If the module is not enabled or it has no templates directory.
      */
     private function getModuleTemplateDir($module)
     {
         if (!\SimpleSAML\Module::isModuleEnabled($module)) {
-            throw new InvalidArgumentException('The module \''.$module.'\' is not enabled.');
+            throw new \InvalidArgumentException('The module \''.$module.'\' is not enabled.');
         }
         $moduledir = \SimpleSAML\Module::getModuleDir($module);
         // check if module has a /templates dir, if so, append
         $templatedir = $moduledir.'/templates';
         if (!is_dir($templatedir)) {
-            throw new InvalidArgumentException('The module \''.$module.'\' has no templates directory.');
-
+            throw new \InvalidArgumentException('The module \''.$module.'\' has no templates directory.');
         }
         return $templatedir;
     }
@@ -326,12 +331,12 @@ class SimpleSAML_XHTML_Template
      *
      * @param string $module The module where we need to search for templates.
      *
-     * @throws InvalidArgumentException If the module is not enabled or it has no templates directory.
+     * @throws \InvalidArgumentException If the module is not enabled or it has no templates directory.
      */
     public function addTemplatesFromModule($module)
     {
-        $dir = $this->getModuleTemplateDir($module);
-        /** @var Twig_Loader_Filesystem $loader */
+        $dir = TemplateLoader::getModuleTemplateDir($module);
+        /** @var \Twig_Loader_Filesystem $loader */
         $loader = $this->twig->getLoader();
         $loader->addPath($dir, $module);
     }
@@ -346,10 +351,11 @@ class SimpleSAML_XHTML_Template
     private function generateLanguageBar()
     {
         $languages = $this->translator->getLanguage()->getLanguageList();
+        ksort($languages);
         $langmap = null;
         if (count($languages) > 1) {
             $parameterName = $this->getTranslator()->getLanguage()->getLanguageParameterName();
-            $langmap = array();
+            $langmap = [];
             foreach ($languages as $lang => $current) {
                 $lang = strtolower($lang);
                 $langname = $this->translator->getLanguage()->getLanguageLocalizedName($lang);
@@ -357,13 +363,13 @@ class SimpleSAML_XHTML_Template
                 if (!$current) {
                     $url = htmlspecialchars(\SimpleSAML\Utils\HTTP::addURLParameters(
                         '',
-                        array($parameterName => $lang)
+                        [$parameterName => $lang]
                     ));
                 }
-                $langmap[$lang] = array(
+                $langmap[$lang] = [
                     'name' => $langname,
                     'url' => $url,
-                );
+                ];
             }
         }
         return $langmap;
@@ -428,7 +434,7 @@ class SimpleSAML_XHTML_Template
     private function findModuleAndTemplateName($template)
     {
         $tmp = explode(':', $template, 2);
-        return (count($tmp) === 2) ? array($tmp[0], $tmp[1]) : array(null, $tmp[0]);
+        return (count($tmp) === 2) ? [$tmp[0], $tmp[1]] : [null, $tmp[0]];
     }
 
 
@@ -445,7 +451,7 @@ class SimpleSAML_XHTML_Template
      *
      * @return string The absolute path to the template file.
      *
-     * @throws Exception If the template file couldn't be found.
+     * @throws \Exception If the template file couldn't be found.
      */
     private function findTemplatePath($template, $throw_exception = true)
     {
@@ -497,7 +503,7 @@ class SimpleSAML_XHTML_Template
             $error = 'Template: Could not find template file ['.$template.'] at ['.$filename.']';
             \SimpleSAML\Logger::critical($_SERVER['PHP_SELF'].' - '.$error);
 
-            throw new Exception($error);
+            throw new \Exception($error);
         } else {
             // missing template expected, return NULL
             return null;
@@ -654,8 +660,8 @@ class SimpleSAML_XHTML_Template
 
 
     /**
-     * @param      $file
-     * @param null $otherConfig
+     * @param string $file
+     * @param \SimpleSAML\Configuration|null $otherConfig
      *
      * @deprecated This method will be removed in SSP 2.0. Please use
      * \SimpleSAML\Locale\Translate::includeLanguageFile() instead.
@@ -715,9 +721,9 @@ class SimpleSAML_XHTML_Template
      */
     public function t(
         $tag,
-        $replacements = array(),
+        $replacements = [],
         $fallbackdefault = true,
-        $oldreplacements = array(),
+        $oldreplacements = [],
         $striptags = false
     ) {
         return $this->translator->t($tag, $replacements, $fallbackdefault, $oldreplacements, $striptags);
diff --git a/lib/SimpleSAML/XHTML/TemplateControllerInterface.php b/lib/SimpleSAML/XHTML/TemplateControllerInterface.php
index bd54907c48a9e5d4152062e36a19add335ad83ee..8d6f4e733ee95f3f082f8cda06fe4f631f74622e 100644
--- a/lib/SimpleSAML/XHTML/TemplateControllerInterface.php
+++ b/lib/SimpleSAML/XHTML/TemplateControllerInterface.php
@@ -7,7 +7,8 @@ namespace SimpleSAML\XHTML;
  *
  * @package SimpleSAMLphp
  */
-interface TemplateControllerInterface {
+interface TemplateControllerInterface
+{
 
     /**
      * Implement to modify the twig environment after its initialization (e.g. add filters or extensions).
diff --git a/lib/SimpleSAML/XHTML/TemplateLoader.php b/lib/SimpleSAML/XHTML/TemplateLoader.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5090d5544612a05e68270e28eda74e57310b352
--- /dev/null
+++ b/lib/SimpleSAML/XHTML/TemplateLoader.php
@@ -0,0 +1,72 @@
+<?php
+
+
+namespace SimpleSAML\XHTML;
+
+/**
+ * This class extends the Twig\Loader\FilesystemLoader so that we can load templates from modules in twig, even
+ * when the main template is not part of a module (or the same one).
+ *
+ * @package simplesamlphp/simplesamlphp
+ */
+class TemplateLoader extends \Twig\Loader\FilesystemLoader
+{
+    /**
+     * This method adds a namespace dynamically so that we can load templates from modules whenever we want.
+     *
+     * @inheritdoc
+     */
+    protected function findTemplate($name, $throw = true)
+    {
+        list($namespace, $shortname) = $this->parseModuleName($name);
+        if (!in_array($namespace, $this->paths, true) && $namespace !== self::MAIN_NAMESPACE) {
+            $this->addPath(self::getModuleTemplateDir($namespace), $namespace);
+        }
+        return parent::findTemplate($name, $throw);
+    }
+
+
+    /**
+     * Parse the name of a template in a module.
+     *
+     * @param string $name The full name of the template, including namespace and template name / path.
+     *
+     * @return array An array with the corresponding namespace and name of the template. The namespace defaults to
+     * \Twig\Loader\FilesystemLoader::MAIN_NAMESPACE, if none was specified in $name.
+     */
+    protected function parseModuleName($name, $default = self::MAIN_NAMESPACE)
+    {
+        if (strpos($name, ':')) {
+            // we have our old SSP format
+            list($namespace, $shortname) = explode(':', $name, 2);
+            $shortname = strtr($shortname, [
+                '.tpl.php' => '.twig',
+                '.php' => '.twig',
+            ]);
+            return [$namespace, $shortname];
+        }
+        return [$default, $name];
+    }
+
+
+    /**
+     * Get the template directory of a module, if it exists.
+     *
+     * @return string The templates directory of a module.
+     *
+     * @throws \InvalidArgumentException If the module is not enabled or it has no templates directory.
+     */
+    public static function getModuleTemplateDir($module)
+    {
+        if (!\SimpleSAML\Module::isModuleEnabled($module)) {
+            throw new \InvalidArgumentException('The module \''.$module.'\' is not enabled.');
+        }
+        $moduledir = \SimpleSAML\Module::getModuleDir($module);
+        // check if module has a /templates dir, if so, append
+        $templatedir = $moduledir.'/templates';
+        if (!is_dir($templatedir)) {
+            throw new \InvalidArgumentException('The module \''.$module.'\' has no templates directory.');
+        }
+        return $templatedir;
+    }
+}
diff --git a/lib/SimpleSAML/XML/Errors.php b/lib/SimpleSAML/XML/Errors.php
index 4b4f167a8dcdca20ac3f66e92e2f8c73f360799b..6f6d228ef34432187b2bcf481e66b1df82a3854f 100644
--- a/lib/SimpleSAML/XML/Errors.php
+++ b/lib/SimpleSAML/XML/Errors.php
@@ -16,11 +16,10 @@ use LibXMLError;
 
 class Errors
 {
-
     /**
      * @var array This is an stack of error logs. The topmost element is the one we are currently working on.
      */
-    private static $errorStack = array();
+    private static $errorStack = [];
 
     /**
      * @var bool This is the xml error state we had before we began logging.
@@ -67,7 +66,7 @@ class Errors
         }
 
         // Add a new level to the error stack
-        self::$errorStack[] = array();
+        self::$errorStack[] = [];
     }
 
 
@@ -82,7 +81,7 @@ class Errors
         // Check whether the error access functions are present
         if (!function_exists('libxml_use_internal_errors')) {
             // Pretend that no errors occurred
-            return array();
+            return [];
         }
 
         // Add any errors which may have occurred
@@ -111,8 +110,8 @@ class Errors
     public static function formatError($error)
     {
         assert($error instanceof LibXMLError);
-        return 'level=' . $error->level . ',code='  . $error->code . ',line=' . $error->line . ',col=' . $error->column .
-            ',msg=' . trim($error->message);
+        return 'level='.$error->level.',code='.$error->code.',line='.$error->line.',col='.$error->column.
+            ',msg='.trim($error->message);
     }
 
 
@@ -132,7 +131,7 @@ class Errors
 
         $ret = '';
         foreach ($errors as $error) {
-            $ret .= self::formatError($error) . "\n";
+            $ret .= self::formatError($error)."\n";
         }
 
         return $ret;
diff --git a/lib/SimpleSAML/XML/Parser.php b/lib/SimpleSAML/XML/Parser.php
index b8dda85226cccc11fd715fefa9e2fb9b01796535..39287b2cb967edb1f4a0b7839a7860afb52f7cbb 100644
--- a/lib/SimpleSAML/XML/Parser.php
+++ b/lib/SimpleSAML/XML/Parser.php
@@ -28,7 +28,7 @@ class Parser
         // Traverse all existing namespaces in element
         $namespaces = $element->getNamespaces();
         foreach ($namespaces as $prefix => $ns) {
-            $element[(($prefix === '') ? 'xmlns' : 'xmlns:' . $prefix)] = $ns;
+            $element[(($prefix === '') ? 'xmlns' : 'xmlns:'.$prefix)] = $ns;
         }
         
         /* Create a new parser with the xml document where the namespace definitions
@@ -52,7 +52,9 @@ class Parser
         $result = $this->simplexml->xpath($xpath);
         if (!is_array($result) || empty($result)) {
             if ($required) {
-                throw new \Exception('Could not get value from XML document using the following XPath expression: ' . $xpath);
+                throw new \Exception(
+                    'Could not get value from XML document using the following XPath expression: '.$xpath
+                );
             } else {
                 return null;
             }
@@ -69,7 +71,9 @@ class Parser
             }
         }
         if ($required) {
-            throw new \Exception('Could not get value from XML document using multiple alternative XPath expressions.');
+            throw new \Exception(
+                'Could not get value from XML document using multiple alternative XPath expressions.'
+            );
         } else {
             return null;
         }
diff --git a/lib/SimpleSAML/XML/Shib13/AuthnRequest.php b/lib/SimpleSAML/XML/Shib13/AuthnRequest.php
index f52fea212cfa4f379ccb94e6676d1a7abd93cd70..221951d9b777e5b71f8513890582afec4acc852d 100644
--- a/lib/SimpleSAML/XML/Shib13/AuthnRequest.php
+++ b/lib/SimpleSAML/XML/Shib13/AuthnRequest.php
@@ -36,18 +36,21 @@ class AuthnRequest
 
     public function createRedirect($destination, $shire)
     {
-        $metadata = \SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpmetadata = $metadata->getMetaDataConfig($destination, 'shib13-idp-remote');
 
-        $desturl = $idpmetadata->getDefaultEndpoint('SingleSignOnService', array('urn:mace:shibboleth:1.0:profiles:AuthnRequest'));
+        $desturl = $idpmetadata->getDefaultEndpoint(
+            'SingleSignOnService',
+            ['urn:mace:shibboleth:1.0:profiles:AuthnRequest']
+        );
         $desturl = $desturl['Location'];
 
         $target = $this->getRelayState();
         
-        $url = $desturl . '?' .
-            'providerId=' . urlencode($this->getIssuer()) .
-            '&shire=' . urlencode($shire) .
-            (isset($target) ? '&target=' . urlencode($target) : '');
+        $url = $desturl.'?'.
+            'providerId='.urlencode($this->getIssuer()).
+            '&shire='.urlencode($shire).
+            (isset($target) ? '&target='.urlencode($target) : '');
         return $url;
     }
 }
diff --git a/lib/SimpleSAML/XML/Shib13/AuthnResponse.php b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php
index 61a8f32bafd9d69a15bb48b42453bb71211c6012..8b6c1fb6e3686a77638c6ddc625f649000a27bab 100644
--- a/lib/SimpleSAML/XML/Shib13/AuthnResponse.php
+++ b/lib/SimpleSAML/XML/Shib13/AuthnResponse.php
@@ -20,7 +20,6 @@ use SimpleSAML\XML\Validator;
 
 class AuthnResponse
 {
-
     /**
      * @var \SimpleSAML\XML\Validator This variable contains an XML validator for this message.
      */
@@ -92,18 +91,18 @@ class AuthnResponse
         }
 
         // Validate the signature
-        $this->validator = new Validator($this->dom, array('ResponseID', 'AssertionID'));
+        $this->validator = new Validator($this->dom, ['ResponseID', 'AssertionID']);
 
         // Get the issuer of the response
         $issuer = $this->getIssuer();
 
         // Get the metadata of the issuer
-        $metadata = \SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $md = $metadata->getMetaDataConfig($issuer, 'shib13-idp-remote');
 
         $publicKeys = $md->getPublicKeys('signing');
         if (!empty($publicKeys)) {
-            $certFingerprints = array();
+            $certFingerprints = [];
             foreach ($publicKeys as $key) {
                 if ($key['type'] !== 'X509Certificate') {
                     continue;
@@ -120,7 +119,9 @@ class AuthnResponse
             // Validate against CA
             $this->validator->validateCA(Config::getCertPath($md->getString('caFile')));
         } else {
-            throw new \SimpleSAML_Error_Exception('Missing certificate in Shibboleth 1.3 IdP Remote metadata for identity provider [' . $issuer . '].');
+            throw new \SimpleSAML\Error\Exception(
+                'Missing certificate in Shibboleth 1.3 IdP Remote metadata for identity provider ['.$issuer.'].'
+            );
         }
 
         return true;
@@ -149,7 +150,7 @@ class AuthnResponse
             $node = dom_import_simplexml($node);
         }
 
-        assert($node instanceof DOMNode);
+        assert($node instanceof \DOMNode);
 
         return $this->validator->isNodeValidated($node);
     }
@@ -166,13 +167,13 @@ class AuthnResponse
     private function doXPathQuery($query, $node = null)
     {
         assert(is_string($query));
-        assert($this->dom instanceof DOMDocument);
+        assert($this->dom instanceof \DOMDocument);
 
         if ($node === null) {
             $node = $this->dom->documentElement;
         }
 
-        assert($node instanceof DOMNode);
+        assert($node instanceof \DOMNode);
 
         $xPath = new \DOMXpath($this->dom);
         $xPath->registerNamespace('shibp', self::SHIB_PROTOCOL_NS);
@@ -202,15 +203,15 @@ class AuthnResponse
     
     public function getAttributes()
     {
-        $metadata = \SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
-        $md = $metadata->getMetadata($this->getIssuer(), 'shib13-idp-remote');
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
+        $md = $metadata->getMetaData($this->getIssuer(), 'shib13-idp-remote');
         $base64 = isset($md['base64attributes']) ? $md['base64attributes'] : false;
 
-        if (! ($this->dom instanceof \DOMDocument)) {
-            return array();
+        if (!($this->dom instanceof \DOMDocument)) {
+            return [];
         }
 
-        $attributes = array();
+        $attributes = [];
 
         $assertions = $this->doXPathQuery('/shibp:Response/shib:Assertion');
 
@@ -228,20 +229,23 @@ class AuthnResponse
 
                 if ($start && $end) {
                     if (!self::checkDateConditions($start, $end)) {
-                        error_log('Date check failed ... (from ' . $start . ' to ' . $end . ')');
+                        error_log('Date check failed ... (from '.$start.' to '.$end.')');
                         continue;
                     }
                 }
             }
 
-            $attribute_nodes = $this->doXPathQuery('shib:AttributeStatement/shib:Attribute/shib:AttributeValue', $assertion);
+            $attribute_nodes = $this->doXPathQuery(
+                'shib:AttributeStatement/shib:Attribute/shib:AttributeValue',
+                $assertion
+            );
             /** @var \DOMElement $attribute */
             foreach ($attribute_nodes as $attribute) {
                 $value = $attribute->textContent;
                 $name = $attribute->parentNode->getAttribute('AttributeName');
 
                 if ($attribute->hasAttribute('Scope')) {
-                    $scopePart = '@' . $attribute->getAttribute('Scope');
+                    $scopePart = '@'.$attribute->getAttribute('Scope');
                 } else {
                     $scopePart = '';
                 }
@@ -251,16 +255,16 @@ class AuthnResponse
                 }
 
                 if (!array_key_exists($name, $attributes)) {
-                    $attributes[$name] = array();
+                    $attributes[$name] = [];
                 }
 
                 if ($base64) {
                     $encodedvalues = explode('_', $value);
                     foreach ($encodedvalues as $v) {
-                        $attributes[$name][] = base64_decode($v) . $scopePart;
+                        $attributes[$name][] = base64_decode($v).$scopePart;
                     }
                 } else {
-                    $attributes[$name][] = $value . $scopePart;
+                    $attributes[$name][] = $value.$scopePart;
                 }
             }
         }
@@ -283,7 +287,7 @@ class AuthnResponse
 
     public function getNameID()
     {
-        $nameID = array();
+        $nameID = [];
 
         $query = '/shibp:Response/shib:Assertion/shib:AuthenticationStatement/shib:Subject/shib:NameIdentifier';
         $nodelist = $this->doXPathQuery($query);
@@ -300,13 +304,13 @@ class AuthnResponse
     /**
      * Build a authentication response.
      *
-     * @param \SimpleSAML_Configuration $idp Metadata for the IdP the response is sent from.
-     * @param \SimpleSAML_Configuration $sp Metadata for the SP the response is sent to.
+     * @param \SimpleSAML\Configuration $idp Metadata for the IdP the response is sent from.
+     * @param \SimpleSAML\Configuration $sp Metadata for the SP the response is sent to.
      * @param string $shire The endpoint on the SP the response is sent to.
      * @param array|null $attributes The attributes which should be included in the response.
      * @return string The response.
      */
-    public function generate(\SimpleSAML_Configuration $idp, \SimpleSAML_Configuration $sp, $shire, $attributes)
+    public function generate(\SimpleSAML\Configuration $idp, \SimpleSAML\Configuration $sp, $shire, $attributes)
     {
         assert(is_string($shire));
         assert($attributes === null || is_array($attributes));
@@ -316,7 +320,7 @@ class AuthnResponse
         } elseif ($idp->hasValue('scopedattributes')) {
             $scopedAttributes = $idp->getArray('scopedattributes');
         } else {
-            $scopedAttributes = array();
+            $scopedAttributes = [];
         }
 
         $id = Random::generateID();
@@ -327,7 +331,7 @@ class AuthnResponse
         $notBefore = Time::generateTimestamp(time() - 30);
         
         
-        $assertionExpire = Time::generateTimestamp(time() + 60 * 5);# 5 minutes
+        $assertionExpire = Time::generateTimestamp(time() + 300); // 5 minutes
         $assertionid = Random::generateID();
 
         $spEntityId = $sp->getString('entityid');
@@ -338,18 +342,18 @@ class AuthnResponse
         $namequalifier = $sp->getString('NameQualifier', $spEntityId);
         $nameid = Random::generateID();
         $subjectNode =
-            '<Subject>' .
-            '<NameIdentifier' .
-            ' Format="urn:mace:shibboleth:1.0:nameIdentifier"' .
-            ' NameQualifier="' . htmlspecialchars($namequalifier) . '"' .
-            '>' .
-            htmlspecialchars($nameid) .
-            '</NameIdentifier>' .
-            '<SubjectConfirmation>' .
-            '<ConfirmationMethod>' .
-            'urn:oasis:names:tc:SAML:1.0:cm:bearer' .
-            '</ConfirmationMethod>' .
-            '</SubjectConfirmation>' .
+            '<Subject>'.
+            '<NameIdentifier'.
+            ' Format="urn:mace:shibboleth:1.0:nameIdentifier"'.
+            ' NameQualifier="'.htmlspecialchars($namequalifier).'"'.
+            '>'.
+            htmlspecialchars($nameid).
+            '</NameIdentifier>'.
+            '<SubjectConfirmation>'.
+            '<ConfirmationMethod>'.
+            'urn:oasis:names:tc:SAML:1.0:cm:bearer'.
+            '</ConfirmationMethod>'.
+            '</SubjectConfirmation>'.
             '</Subject>';
 
         $encodedattributes = '';
@@ -359,7 +363,7 @@ class AuthnResponse
             $encodedattributes .= $subjectNode;
 
             foreach ($attributes as $name => $value) {
-                $encodedattributes .= $this->enc_attribute($name, $value, $base64, $scopedAttributes);
+                $encodedattributes .= $this->encAttribute($name, $value, $base64, $scopedAttributes);
             }
 
             $encodedattributes .= '</AttributeStatement>';
@@ -371,25 +375,25 @@ class AuthnResponse
         $response = '<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol"
     xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"
     xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" IssueInstant="' . $issueInstant. '"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" IssueInstant="'.$issueInstant.'"
     MajorVersion="1" MinorVersion="1"
-    Recipient="' . htmlspecialchars($shire) . '" ResponseID="' . $id . '">
+    Recipient="'.htmlspecialchars($shire).'" ResponseID="'.$id.'">
     <Status>
         <StatusCode Value="samlp:Success" />
     </Status>
     <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion"
-        AssertionID="' . $assertionid . '" IssueInstant="' . $issueInstant. '"
-        Issuer="' . htmlspecialchars($idp->getString('entityid')) . '" MajorVersion="1" MinorVersion="1">
-        <Conditions NotBefore="' . $notBefore. '" NotOnOrAfter="'. $assertionExpire . '">
+        AssertionID="'.$assertionid.'" IssueInstant="'.$issueInstant.'"
+        Issuer="'.htmlspecialchars($idp->getString('entityid')).'" MajorVersion="1" MinorVersion="1">
+        <Conditions NotBefore="'.$notBefore.'" NotOnOrAfter="'.$assertionExpire.'">
             <AudienceRestrictionCondition>
-                <Audience>' . htmlspecialchars($audience) . '</Audience>
+                <Audience>'.htmlspecialchars($audience).'</Audience>
             </AudienceRestrictionCondition>
         </Conditions>
-        <AuthenticationStatement AuthenticationInstant="' . $issueInstant. '"
-            AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified">' .
-            $subjectNode . '
+        <AuthenticationStatement AuthenticationInstant="'.$issueInstant.'"
+            AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified">'.
+            $subjectNode.'
         </AuthenticationStatement>
-        ' . $encodedattributes . '
+        '.$encodedattributes.'
     </Assertion>
 </Response>';
 
@@ -406,7 +410,7 @@ class AuthnResponse
      * @param array $scopedAttributes  Array of attributes names which are scoped.
      * @return string  The attribute encoded as an XML-string.
      */
-    private function enc_attribute($name, $values, $base64, $scopedAttributes)
+    private function encAttribute($name, $values, $base64, $scopedAttributes)
     {
         assert(is_string($name));
         assert(is_array($values));
@@ -419,14 +423,15 @@ class AuthnResponse
             $scoped = false;
         }
 
-        $attr = '<Attribute AttributeName="' . htmlspecialchars($name) . '" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">';
+        $attr = '<Attribute AttributeName="'.htmlspecialchars($name).
+            '" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">';
         foreach ($values as $value) {
             $scopePart = '';
             if ($scoped) {
                 $tmp = explode('@', $value, 2);
                 if (count($tmp) === 2) {
                     $value = $tmp[0];
-                    $scopePart = ' Scope="' . htmlspecialchars($tmp[1]) . '"';
+                    $scopePart = ' Scope="'.htmlspecialchars($tmp[1]).'"';
                 }
             }
 
@@ -434,7 +439,7 @@ class AuthnResponse
                 $value = base64_encode($value);
             }
 
-            $attr .= '<AttributeValue' . $scopePart . '>' . htmlspecialchars($value) . '</AttributeValue>';
+            $attr .= '<AttributeValue'.$scopePart.'>'.htmlspecialchars($value).'</AttributeValue>';
         }
         $attr .= '</Attribute>';
 
diff --git a/lib/SimpleSAML/XML/Signer.php b/lib/SimpleSAML/XML/Signer.php
index 2c69e6b3f2da76a007c4474f8e1a11052ddf667e..26f46ab62f3163f6a47896a6edafdf7b3c8e1e0b 100644
--- a/lib/SimpleSAML/XML/Signer.php
+++ b/lib/SimpleSAML/XML/Signer.php
@@ -39,7 +39,7 @@ class Signer
     /**
      * @var array Extra certificates which should be included in the response.
      */
-    private $extraCertificates = array();
+    private $extraCertificates = [];
 
 
     /**
@@ -52,13 +52,13 @@ class Signer
      *  - privatekey       The file with the private key, relative to the cert-directory.
      *  - privatekey_pass  The passphrase for the private key.
      *  - certificate      The file with the certificate, relative to the cert-directory.
-     *  - privatekey_array The private key, as an array returned from SimpleSAML_Utilities::loadPrivateKey.
-     *  - publickey_array  The public key, as an array returned from SimpleSAML_Utilities::loadPublicKey.
+     *  - privatekey_array The private key, as an array returned from \SimpleSAML\Utils\Crypto::loadPrivateKey.
+     *  - publickey_array  The public key, as an array returned from \SimpleSAML\Utils\Crypto::loadPublicKey.
      *  - id               The name of the ID attribute.
      *
      * @param array $options  Associative array with options for the constructor. Defaults to an empty array.
      */
-    public function __construct($options = array())
+    public function __construct($options = [])
     {
         assert(is_array($options));
 
@@ -84,7 +84,7 @@ class Signer
         }
 
         if (array_key_exists('id', $options)) {
-            $this->setIdAttribute($options['id']);
+            $this->setIDAttribute($options['id']);
         }
     }
 
@@ -93,7 +93,7 @@ class Signer
      * Set the private key from an array.
      *
      * This function loads the private key from an array matching what is returned
-     * by SimpleSAML_Utilities::loadPrivateKey(...).
+     * by \SimpleSAML\Utils\Crypto::loadPrivateKey(...).
      *
      * @param array $privatekey  The private key.
      */
@@ -102,7 +102,7 @@ class Signer
         assert(is_array($privatekey));
         assert(array_key_exists('PEM', $privatekey));
 
-        $this->privateKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
+        $this->privateKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);
         if (array_key_exists('password', $privatekey)) {
             $this->privateKey->passphrase = $privatekey['password'];
         }
@@ -136,14 +136,14 @@ class Signer
         }
 
         if (!file_exists($keyFile)) {
-            throw new \Exception('Could not find private key file "' . $keyFile . '".');
+            throw new \Exception('Could not find private key file "'.$keyFile.'".');
         }
         $keyData = file_get_contents($keyFile);
         if ($keyData === false) {
-            throw new \Exception('Unable to read private key file "' . $keyFile . '".');
+            throw new \Exception('Unable to read private key file "'.$keyFile.'".');
         }
 
-        $privatekey = array('PEM' => $keyData);
+        $privatekey = ['PEM' => $keyData];
         if ($pass !== null) {
             $privatekey['password'] = $pass;
         }
@@ -155,7 +155,7 @@ class Signer
      * Set the public key / certificate we should include in the signature.
      *
      * This function loads the public key from an array matching what is returned
-     * by SimpleSAML_Utilities::loadPublicKey(...).
+     * by \SimpleSAML\Utils\Crypto::loadPublicKey(...).
      *
      * @param array $publickey The public key.
      * @throws \Exception
@@ -198,12 +198,12 @@ class Signer
         }
 
         if (!file_exists($certFile)) {
-            throw new \Exception('Could not find certificate file "' . $certFile . '".');
+            throw new \Exception('Could not find certificate file "'.$certFile.'".');
         }
 
         $cert = file_get_contents($certFile);
         if ($cert === false) {
-            throw new \Exception('Unable to read certificate file "' . $certFile . '".');
+            throw new \Exception('Unable to read certificate file "'.$certFile.'".');
         }
         $this->certificate = $cert;
     }
@@ -245,12 +245,12 @@ class Signer
         }
 
         if (!file_exists($certFile)) {
-            throw new \Exception('Could not find extra certificate file "' . $certFile . '".');
+            throw new \Exception('Could not find extra certificate file "'.$certFile.'".');
         }
 
         $certificate = file_get_contents($certFile);
         if ($certificate === false) {
-            throw new \Exception('Unable to read extra certificate file "' . $certFile . '".');
+            throw new \Exception('Unable to read extra certificate file "'.$certFile.'".');
         }
 
         $this->extraCertificates[] = $certificate;
@@ -284,15 +284,15 @@ class Signer
         $objXMLSecDSig = new XMLSecurityDSig();
         $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
 
-        $options = array();
+        $options = [];
         if (!empty($this->idAttrName)) {
             $options['id_name'] = $this->idAttrName;
         }
 
         $objXMLSecDSig->addReferenceList(
-            array($node),
-            XMLSecurityDSig::SHA1,
-            array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
+            [$node],
+            XMLSecurityDSig::SHA256,
+            ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N],
             $options
         );
 
diff --git a/lib/SimpleSAML/XML/Validator.php b/lib/SimpleSAML/XML/Validator.php
index becf3516e74c6ca9ffc4e19619d09a6cce597e42..8dd46f8971c6c1bfd63fd17ed9f8e1db15428875 100644
--- a/lib/SimpleSAML/XML/Validator.php
+++ b/lib/SimpleSAML/XML/Validator.php
@@ -15,7 +15,6 @@ use SimpleSAML\Logger;
 
 class Validator
 {
-
     /**
      * @var string This variable contains the X509 certificate the XML document
      *             was signed with, or NULL if it wasn't signed with an X509 certificate.
@@ -36,7 +35,7 @@ class Validator
      * take the following values:
      * - NULL/FALSE: No validation will be performed. This is the default.
      * - A string: Assumed to be a PEM-encoded certificate / public key.
-     * - An array: Assumed to be an array returned by SimpleSAML_Utilities::loadPublicKey.
+     * - An array: Assumed to be an array returned by \SimpleSAML\Utils\Crypto::loadPublicKey.
      *
      * @param \DOMNode $xmlNode The XML node which contains the Signature element.
      * @param string|array $idAttribute The ID attribute which is used in node references. If
@@ -53,9 +52,9 @@ class Validator
         if ($publickey === null) {
             $publickey = false;
         } elseif (is_string($publickey)) {
-            $publickey = array(
+            $publickey = [
                 'PEM' => $publickey,
-            );
+            ];
         } else {
             assert($publickey === false || is_array($publickey));
         }
@@ -116,7 +115,7 @@ class Validator
                 $certificate = $objKey->getX509Certificate();
                 if ($certificate === null) {
                     // Wasn't signed with an X509 certificate
-                    throw new \Exception('Message wasn\'t signed with an X509 certificate,' .
+                    throw new \Exception('Message wasn\'t signed with an X509 certificate,'.
                         ' and no public key was provided in the metadata.');
                 }
 
@@ -211,7 +210,7 @@ class Validator
         $certFingerprint = self::calculateX509Fingerprint($certificate);
         if ($certFingerprint === null) {
             // Couldn't calculate fingerprint from X509 certificate. Should not happen.
-            throw new \Exception('Unable to calculate fingerprint from X509' .
+            throw new \Exception('Unable to calculate fingerprint from X509'.
                 ' certificate. Maybe it isn\'t an X509 certificate?');
         }
 
@@ -225,8 +224,8 @@ class Validator
         }
 
         // None of the fingerprints matched. Throw an exception describing the error.
-        throw new \Exception('Invalid fingerprint of certificate. Expected one of [' .
-            implode('], [', $fingerprints) . '], but got [' . $certFingerprint . ']');
+        throw new \Exception('Invalid fingerprint of certificate. Expected one of ['.
+            implode('], [', $fingerprints).'], but got ['.$certFingerprint.']');
     }
 
 
@@ -250,7 +249,7 @@ class Validator
         }
 
         if (!is_array($fingerprints)) {
-            $fingerprints = array($fingerprints);
+            $fingerprints = [$fingerprints];
         }
 
         // Normalize the fingerprints
@@ -325,14 +324,15 @@ class Validator
         assert(is_string($caFile));
 
         // Clear openssl errors
-        while (openssl_error_string() !== false);
+        while (openssl_error_string() !== false) {
+        }
 
-        $res = openssl_x509_checkpurpose($certificate, X509_PURPOSE_ANY, array($caFile));
+        $res = openssl_x509_checkpurpose($certificate, X509_PURPOSE_ANY, [$caFile]);
 
         $errors = '';
         // Log errors
         while (($error = openssl_error_string()) !== false) {
-            $errors .= ' [' . $error . ']';
+            $errors .= ' ['.$error.']';
         }
 
         if ($res !== true) {
@@ -361,25 +361,25 @@ class Validator
         assert(is_string($certificate));
         assert(is_string($caFile));
 
-        $command = array(
+        $command = [
             'openssl', 'verify',
             '-CAfile', $caFile,
             '-purpose', 'any',
-        );
+        ];
 
         $cmdline = '';
         foreach ($command as $c) {
-            $cmdline .= escapeshellarg($c) . ' ';
+            $cmdline .= escapeshellarg($c).' ';
         }
 
         $cmdline .= '2>&1';
-        $descSpec = array(
-            0 => array('pipe', 'r'),
-            1 => array('pipe', 'w'),
-        );
+        $descSpec = [
+            0 => ['pipe', 'r'],
+            1 => ['pipe', 'w'],
+        ];
         $process = proc_open($cmdline, $descSpec, $pipes);
         if (!is_resource($process)) {
-            throw new \Exception('Failed to execute verification command: ' . $cmdline);
+            throw new \Exception('Failed to execute verification command: '.$cmdline);
         }
 
         if (fwrite($pipes[0], $certificate) === false) {
@@ -391,7 +391,7 @@ class Validator
         while (!feof($pipes[1])) {
             $line = trim(fgets($pipes[1]));
             if (strlen($line) > 0) {
-                $out .= ' [' . $line . ']';
+                $out .= ' ['.$line.']';
             }
         }
         fclose($pipes[1]);
@@ -421,21 +421,21 @@ class Validator
         assert(is_string($caFile));
 
         if (!file_exists($caFile)) {
-            throw new \Exception('Could not load CA file: ' . $caFile);
+            throw new \Exception('Could not load CA file: '.$caFile);
         }
 
-        Logger::debug('Validating certificate against CA file: ' . var_export($caFile, true));
+        Logger::debug('Validating certificate against CA file: '.var_export($caFile, true));
 
         $resBuiltin = self::validateCABuiltIn($certificate, $caFile);
         if ($resBuiltin !== true) {
-            Logger::debug('Failed to validate with internal function: ' . var_export($resBuiltin, true));
+            Logger::debug('Failed to validate with internal function: '.var_export($resBuiltin, true));
 
             $resExternal = self::validateCAExec($certificate, $caFile);
             if ($resExternal !== true) {
-                Logger::debug('Failed to validate with external function: ' . var_export($resExternal, true));
-                throw new \Exception('Could not verify certificate against CA file "'
-                    . $caFile . '". Internal result:' . $resBuiltin .
-                    ' External result:' . $resExternal);
+                Logger::debug('Failed to validate with external function: '.var_export($resExternal, true));
+                throw new \Exception('Could not verify certificate against CA file "'.
+                    $caFile.'". Internal result:'.$resBuiltin.
+                    ' External result:'.$resExternal);
             }
         }
 
diff --git a/lib/_autoload.php b/lib/_autoload.php
index 018468b550e5071c1a57bb52df3fe2b73918fc8f..245acd1e5561f4e1f7b1bc2fe270909b07997d36 100644
--- a/lib/_autoload.php
+++ b/lib/_autoload.php
@@ -11,7 +11,8 @@
 // SSP is loaded as a separate project
 if (file_exists(dirname(dirname(__FILE__)).'/vendor/autoload.php')) {
     require_once dirname(dirname(__FILE__)).'/vendor/autoload.php';
-} else {  // SSP is loaded as a library
+} else {
+    // SSP is loaded as a library
     if (file_exists(dirname(dirname(__FILE__)).'/../../autoload.php')) {
         require_once dirname(dirname(__FILE__)).'/../../autoload.php';
     } else {
diff --git a/lib/_autoload_modules.php b/lib/_autoload_modules.php
index 9a2c753f76708e2d6bc037232996689fdff86acb..41ca267a9eb9604a18c4e8817456e2383aaa11df 100644
--- a/lib/_autoload_modules.php
+++ b/lib/_autoload_modules.php
@@ -33,7 +33,7 @@ function temporaryLoader($class)
     $original = $class;
 
     // list of classes that have been renamed or moved
-    $renamed = array(
+    $renamed = [
         'SimpleSAML_Metadata_MetaDataStorageHandlerMDX' => 'SimpleSAML_Metadata_Sources_MDQ',
         'SimpleSAML_Logger_LoggingHandlerSyslog' => 'SimpleSAML_Logger_SyslogLoggingHandler',
         'SimpleSAML_Logger_LoggingHandlerErrorLog' => 'SimpleSAML_Logger_ErrorLogLoggingHandler',
@@ -42,7 +42,7 @@ function temporaryLoader($class)
         'SimpleSAML_IdP_LogoutHandler' => 'SimpleSAML_IdP_LogoutHandlerInterface',
         'SimpleSAML_IdP_LogoutIFrame' => 'SimpleSAML_IdP_IFrameLogoutHandler',
         'SimpleSAML_IdP_LogoutTraditional' => 'SimpleSAML_IdP_TraditionalLogoutHandler',
-    );
+    ];
     if (array_key_exists($class, $renamed)) {
         // the class has been renamed, try to load it and create an alias
         $class = $renamed[$class];
@@ -126,7 +126,8 @@ function sspmodAutoloadPSR0($className)
 function sspmodAutoloadPSR4($className)
 {
     $elements = explode('\\', $className);
-    if ($elements[0] === '') { // class name starting with /, ignore
+    if ($elements[0] === '') {
+        // class name starting with /, ignore
         array_shift($elements);
     }
     if (count($elements) < 4) {
diff --git a/locales/en/LC_MESSAGES/messages.po b/locales/en/LC_MESSAGES/messages.po
index 4df17251e7c762211466c312adf1dc5d78e59466..33e9ac937b4d56e06b1924f003da7d202ebac87d 100644
--- a/locales/en/LC_MESSAGES/messages.po
+++ b/locales/en/LC_MESSAGES/messages.po
@@ -47,6 +47,9 @@ msgstr "Username"
 msgid "{login:processing}"
 msgstr "Processing..."
 
+msgid "Back"
+msgstr "Back"
+
 msgid "{errors:title_METADATA}"
 msgstr "Error loading metadata"
 
diff --git a/locales/nl/LC_MESSAGES/messages.po b/locales/nl/LC_MESSAGES/messages.po
index 1810ebbb9ed7d7ccd710e3d9425c6e6ca2bcba2c..60a972e7929626e60a47237ffedff01dc29b5fe0 100644
--- a/locales/nl/LC_MESSAGES/messages.po
+++ b/locales/nl/LC_MESSAGES/messages.po
@@ -44,6 +44,9 @@ msgstr "Toestandsinformatie verloren"
 msgid "{login:username}"
 msgstr "Gebruikersnaam"
 
+msgid "Back"
+msgstr "Terug"
+
 msgid "{errors:title_METADATA}"
 msgstr "Fout bij het laden van metadata"
 
diff --git a/metadata-templates/adfs-idp-hosted.php b/metadata-templates/adfs-idp-hosted.php
index cace17d0c556a4d1d7d1d93de86fc06bb5e91527..dd81340695659141227cedfe84a77bbf0dbb82d1 100644
--- a/metadata-templates/adfs-idp-hosted.php
+++ b/metadata-templates/adfs-idp-hosted.php
@@ -1,12 +1,12 @@
 <?php
 
-$metadata['__DYNAMIC:1__'] = array(
-	'host' => '__DEFAULT__',
-	'privatekey' => 'server.pem',
-	'certificate' => 'server.crt',
-	'auth' => 'example-userpass',
-	'authproc' => array(
-		// Convert LDAP names to WS-Fed Claims.
-		100 => array('class' => 'core:AttributeMap', 'name2claim'),
-	),
-);
+$metadata['__DYNAMIC:1__'] = [
+    'host' => '__DEFAULT__',
+    'privatekey' => 'server.pem',
+    'certificate' => 'server.crt',
+    'auth' => 'example-userpass',
+    'authproc' => [
+        // Convert LDAP names to WS-Fed Claims.
+        100 => ['class' => 'core:AttributeMap', 'name2claim'],
+    ],
+];
diff --git a/metadata-templates/adfs-sp-remote.php b/metadata-templates/adfs-sp-remote.php
index 8b627ee4b36e706f8cb6e59eb698be59d05bc409..ec2d79c9167c4fc39ba90a5d7f26d10a9cc30d38 100644
--- a/metadata-templates/adfs-sp-remote.php
+++ b/metadata-templates/adfs-sp-remote.php
@@ -1,12 +1,12 @@
 <?php
 
-$metadata['urn:federation:localhost'] = array(
-	'prp' => 'https://localhost/adfs/ls/',
-	'simplesaml.nameidattribute' => 'uid',
-	'authproc' => array(
-		50 => array(
-			'class' => 'core:AttributeLimit',
-			'cn', 'mail', 'uid', 'eduPersonAffiliation',
-		),
-	),
-);
+$metadata['urn:federation:localhost'] = [
+    'prp' => 'https://localhost/adfs/ls/',
+    'simplesaml.nameidattribute' => 'uid',
+    'authproc' => [
+        50 => [
+            'class' => 'core:AttributeLimit',
+            'cn', 'mail', 'uid', 'eduPersonAffiliation',
+        ],
+    ],
+];
diff --git a/metadata-templates/saml20-idp-hosted.php b/metadata-templates/saml20-idp-hosted.php
index 81a2007267ccc0e46573b2a8ba7cb025a626e1df..ecb05ce111e82712e65647eeb6f039f43b80fc1b 100644
--- a/metadata-templates/saml20-idp-hosted.php
+++ b/metadata-templates/saml20-idp-hosted.php
@@ -5,67 +5,47 @@
  * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-hosted
  */
 
-$metadata['__DYNAMIC:1__'] = array(
-	/*
-	 * The hostname of the server (VHOST) that will use this SAML entity.
-	 *
-	 * Can be '__DEFAULT__', to use this entry by default.
-	 */
-	'host' => '__DEFAULT__',
+$metadata['__DYNAMIC:1__'] = [
+    /*
+     * The hostname of the server (VHOST) that will use this SAML entity.
+     *
+     * Can be '__DEFAULT__', to use this entry by default.
+     */
+    'host' => '__DEFAULT__',
 
-	// X.509 key and certificate. Relative to the cert directory.
-	'privatekey' => 'server.pem',
-	'certificate' => 'server.crt',
+    // X.509 key and certificate. Relative to the cert directory.
+    'privatekey' => 'server.pem',
+    'certificate' => 'server.crt',
 
-	/*
-	 * Authentication source to use. Must be one that is configured in
-	 * 'config/authsources.php'.
-	 */
-	'auth' => 'example-userpass',
+    /*
+     * Authentication source to use. Must be one that is configured in
+     * 'config/authsources.php'.
+     */
+    'auth' => 'example-userpass',
 
-	/*
-	 * WARNING: SHA-1 is disallowed starting January the 1st, 2014.
-	 *
-	 * Uncomment the following option to start using SHA-256 for your signatures.
-	 * Currently, SimpleSAMLphp defaults to SHA-1, which has been deprecated since
-	 * 2011, and will be disallowed by NIST as of 2014. Please refer to the following
-	 * document for more information:
-	 * 
-	 * http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf
-	 *
-	 * If you are uncertain about service providers supporting SHA-256 or other
-	 * algorithms of the SHA-2 family, you can configure it individually in the
-	 * SP-remote metadata set for those that support it. Once you are certain that
-	 * all your configured SPs support SHA-2, you can safely remove the configuration
-	 * options in the SP-remote metadata set and uncomment the following option.
-	 *
-	 * Please refer to the IdP hosted reference for more information.
-	 */
-	//'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
+    /* Uncomment the following to use the uri NameFormat on attributes. */
+    /*
+    'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
+    'authproc' => [
+        // Convert LDAP names to oids.
+        100 => ['class' => 'core:AttributeMap', 'name2oid'],
+    ],
+    */
 
-	/* Uncomment the following to use the uri NameFormat on attributes. */
-	/*
-	'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri',
-	'authproc' => array(
-		// Convert LDAP names to oids.
-		100 => array('class' => 'core:AttributeMap', 'name2oid'),
-	),
-	*/
-
-	/*
-	 * Uncomment the following to specify the registration information in the
-	 * exported metadata. Refer to:
+    /*
+     * Uncomment the following to specify the registration information in the
+     * exported metadata. Refer to:
      * http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/cs01/saml-metadata-rpi-v1.0-cs01.html
-	 * for more information.
-	 */
-	/*
-	'RegistrationInfo' => array(
-		'authority' => 'urn:mace:example.org',
-		'instant' => '2008-01-17T11:28:03Z',
-		'policies' => array(
-			'en' => 'http://example.org/policy',
-			'es' => 'http://example.org/politica',
-		),
-	),
-	*/
-);
+     * for more information.
+     */
+    /*
+    'RegistrationInfo' => [
+        'authority' => 'urn:mace:example.org',
+        'instant' => '2008-01-17T11:28:03Z',
+        'policies' => [
+            'en' => 'http://example.org/policy',
+            'es' => 'http://example.org/politica',
+        ],
+    ],
+    */
+];
diff --git a/metadata-templates/saml20-idp-remote.php b/metadata-templates/saml20-idp-remote.php
index 49f44f02848603cd54b9b63e4cd3d56ae507bdd8..d390647e6c4492223c149a1812c3f3409280d130 100644
--- a/metadata-templates/saml20-idp-remote.php
+++ b/metadata-templates/saml20-idp-remote.php
@@ -4,7 +4,5 @@
  *
  * Remember to remove the IdPs you don't use from this file.
  *
- * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-remote 
+ * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-remote
  */
-
-
diff --git a/metadata-templates/saml20-sp-remote.php b/metadata-templates/saml20-sp-remote.php
index 46262cee186653c68fffc1414e2f11fea2369371..a9940e8202da870bfc23199c7794c18b60454452 100644
--- a/metadata-templates/saml20-sp-remote.php
+++ b/metadata-templates/saml20-sp-remote.php
@@ -8,20 +8,34 @@
 /*
  * Example SimpleSAMLphp SAML 2.0 SP
  */
-$metadata['https://saml2sp.example.org'] = array(
-	'AssertionConsumerService' => 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
-	'SingleLogoutService' => 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',
-);
+$metadata['https://saml2sp.example.org'] = [
+    'AssertionConsumerService' => 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp',
+    'SingleLogoutService' => 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp',
+];
 
 /*
  * This example shows an example config that works with G Suite (Google Apps) for education.
- * What is important is that you have an attribute in your IdP that maps to the local part of the email address
- * at G Suite. In example, if your Google account is foo.com, and you have a user that has an email john@foo.com, then you
+ * What is important is that you have an attribute in your IdP that maps to the local part of the email address at
+ * G Suite. In example, if your Google account is foo.com, and you have a user that has an email john@foo.com, then you
  * must set the simplesaml.nameidattribute to be the name of an attribute that for this user has the value of 'john'.
  */
-$metadata['google.com'] = array(
-	'AssertionConsumerService' => 'https://www.google.com/a/g.feide.no/acs',
-	'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
-	'simplesaml.nameidattribute' => 'uid',
-	'simplesaml.attributes' => FALSE,
-);
+$metadata['google.com'] = [
+    'AssertionConsumerService' => 'https://www.google.com/a/g.feide.no/acs',
+    'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
+    'simplesaml.nameidattribute' => 'uid',
+    'simplesaml.attributes' => false,
+];
+
+$metadata['https://legacy.example.edu'] = [
+    'AssertionConsumerService' => 'https://legacy.example.edu/saml/acs',
+    /*
+     * Currently, SimpleSAMLphp defaults to the SHA-256 hashing algorithm.
+     * Uncomment the following option to use SHA-1 for signatures directed
+     * at this specific service provider if it does not support SHA-256 yet.
+     *
+     * WARNING: SHA-1 is disallowed starting January the 1st, 2014.
+     * Please refer to the following document for more information:
+     * http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf
+     */
+    //'signature.algorithm' => 'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
+];
diff --git a/metadata-templates/shib13-idp-hosted.php b/metadata-templates/shib13-idp-hosted.php
index 7617fd685ac2309d4492a340d41b56dbfd544959..28ccc42b33fd334964f13c7289a54a6c9f26dcc0 100644
--- a/metadata-templates/shib13-idp-hosted.php
+++ b/metadata-templates/shib13-idp-hosted.php
@@ -5,22 +5,21 @@
  * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-idp-hosted
  */
 
-$metadata['__DYNAMIC:1__'] = array(
+$metadata['__DYNAMIC:1__'] = [
+    /*
+     * The hostname of the server (VHOST) that will use this SAML entity.
+     *
+     * Can be '__DEFAULT__', to use this entry by default.
+     */
+    'host' => '__DEFAULT__',
 
-	/*
-	 * The hostname of the server (VHOST) that will use this SAML entity.
-	 *
-	 * Can be '__DEFAULT__', to use this entry by default.
-	 */
-	'host' => '__DEFAULT__',
+    // X.509 key and certificate. Relative to the cert directory.
+    'privatekey' => 'server.pem',
+    'certificate' => 'server.crt',
 
-	// X.509 key and certificate. Relative to the cert directory.
-	'privatekey' => 'server.pem',
-	'certificate' => 'server.crt',
-
-	/*
-	 * Authentication source to use. Must be one that is configured in
-	 * 'config/authsources.php'.
-	 */
-	'auth' => 'example-userpass',
-);
+    /*
+     * Authentication source to use. Must be one that is configured in
+     * 'config/authsources.php'.
+     */
+    'auth' => 'example-userpass',
+];
diff --git a/metadata-templates/shib13-idp-remote.php b/metadata-templates/shib13-idp-remote.php
index b48b6f9f922238e981624a3f56596f954d8a605b..69c1ef324edad0fc605baf4fc95963e1dbca1cb4 100644
--- a/metadata-templates/shib13-idp-remote.php
+++ b/metadata-templates/shib13-idp-remote.php
@@ -8,8 +8,8 @@
  */
 
 /*
-$metadata['theproviderid-of-the-idp'] = array(
-	'SingleSignOnService'  => 'https://idp.example.org/shibboleth-idp/SSO',
-	'certificate'          => 'example.pem',
-);
+$metadata['theproviderid-of-the-idp'] = [
+    'SingleSignOnService' => 'https://idp.example.org/shibboleth-idp/SSO',
+    'certificate' => 'example.pem',
+];
 */
diff --git a/metadata-templates/shib13-sp-hosted.php b/metadata-templates/shib13-sp-hosted.php
index f15cc910ef3978be5d77adceb1008c1cd94c9234..e3581c9b864459d0927a6f2d5d7369ff53dadcd3 100644
--- a/metadata-templates/shib13-sp-hosted.php
+++ b/metadata-templates/shib13-sp-hosted.php
@@ -8,6 +8,6 @@
 /*
  * Example of hosted Shibboleth 1.3 SP.
  */
-$metadata['__DYNAMIC:1__'] = array(
-	'host' => '__DEFAULT__',
-);
+$metadata['__DYNAMIC:1__'] = [
+    'host' => '__DEFAULT__',
+];
diff --git a/metadata-templates/shib13-sp-remote.php b/metadata-templates/shib13-sp-remote.php
index 5d0f3100aa9c73f1d2f58fa8e55f4c3b4a7c9525..f60174e28841f75a9cbf426621ca25e10abb4d0a 100644
--- a/metadata-templates/shib13-sp-remote.php
+++ b/metadata-templates/shib13-sp-remote.php
@@ -8,9 +8,8 @@
 /*
  * This is just an example:
  */
-$metadata['https://sp.shiblab.feide.no'] = array(
-	'AssertionConsumerService' => 'http://sp.shiblab.feide.no/Shibboleth.sso/SAML/POST',
-	'audience'                 => 'urn:mace:feide:shiblab',
-	'base64attributes'         => FALSE,
-);
-
+$metadata['https://sp.shiblab.feide.no'] = [
+    'AssertionConsumerService' => 'http://sp.shiblab.feide.no/Shibboleth.sso/SAML/POST',
+    'audience' => 'urn:mace:feide:shiblab',
+    'base64attributes' => false,
+];
diff --git a/metadata-templates/wsfed-idp-remote.php b/metadata-templates/wsfed-idp-remote.php
index 215fb0cd28493aea88a750384f0d84a214cd37bb..214679ce372f8325c64acc281c047c28055adb59 100644
--- a/metadata-templates/wsfed-idp-remote.php
+++ b/metadata-templates/wsfed-idp-remote.php
@@ -3,7 +3,7 @@
  * WS-Federation remote IdP metadata for SimpleSAMLphp.
  */
 
-$metadata['urn:federation:pingfederate:localhost'] = array(
-	'prp' => 'https://localhost:9031/idp/prp.wsf',
-	'certificate' => 'pingfed-localhost.pem',
-);
+$metadata['urn:federation:pingfederate:localhost'] = [
+    'prp' => 'https://localhost:9031/idp/prp.wsf',
+    'certificate' => 'pingfed-localhost.pem',
+];
diff --git a/metadata-templates/wsfed-sp-hosted.php b/metadata-templates/wsfed-sp-hosted.php
index 3a68b7a6b27c75b62fc6264de9ac437466d546d7..5ebdf21c197003673ea2fcf394cd43e9db10f8ad 100644
--- a/metadata-templates/wsfed-sp-hosted.php
+++ b/metadata-templates/wsfed-sp-hosted.php
@@ -6,6 +6,6 @@
  *  - host
  */
 
-$metadata['__DYNAMIC:1__'] = array(
-	'host' => '__DEFAULT__',
-);
+$metadata['__DYNAMIC:1__'] = [
+    'host' => '__DEFAULT__',
+];
diff --git a/modules/.gitignore b/modules/.gitignore
index 14877bd3f2741c9f668795c886c2879baf0c5065..063665917650c84fdff7c342704432b959a01263 100644
--- a/modules/.gitignore
+++ b/modules/.gitignore
@@ -7,7 +7,6 @@
 !/authcrypt/
 !/authfacebook/
 !/authlinkedin/
-!/authmyspace/
 !/authorize/
 !/authtwitter/
 !/authwindowslive/
@@ -39,3 +38,6 @@
 !/smartattributes/
 !/sqlauth/
 !/statistics/
+
+*/enable
+*/disable
diff --git a/modules/adfs/lib/IdP/ADFS.php b/modules/adfs/lib/IdP/ADFS.php
index 3a28b9243497602ca75a5a8c9524e4ef6c0be8ee..691480b7bf5e20a8cc8568688b1be3b4218c315d 100644
--- a/modules/adfs/lib/IdP/ADFS.php
+++ b/modules/adfs/lib/IdP/ADFS.php
@@ -1,39 +1,50 @@
 <?php
 
-class sspmod_adfs_IdP_ADFS
+namespace SimpleSAML\Module\adfs\IdP;
+
+use RobRichards\XMLSecLibs\XMLSecurityDSig;
+use RobRichards\XMLSecLibs\XMLSecurityKey;
+
+class ADFS
 {
-    public static function receiveAuthnRequest(SimpleSAML_IdP $idp)
+    public static function receiveAuthnRequest(\SimpleSAML\IdP $idp)
     {
         try {
             parse_str($_SERVER['QUERY_STRING'], $query);
 
             $requestid = $query['wctx'];
             $issuer = $query['wtrealm'];
-            $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+
+            $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
             $spMetadata = $metadata->getMetaDataConfig($issuer, 'adfs-sp-remote');
 
-            SimpleSAML\Logger::info('ADFS - IdP.prp: Incoming Authentication request: '.$issuer.' id '.$requestid);
-        } catch(Exception $exception) {
-            throw new SimpleSAML_Error_Error('PROCESSAUTHNREQUEST', $exception);
+            \SimpleSAML\Logger::info('ADFS - IdP.prp: Incoming Authentication request: '.$issuer.' id '.$requestid);
+        } catch (\Exception $exception) {
+            throw new \SimpleSAML\Error\Error('PROCESSAUTHNREQUEST', $exception);
         }
 
-        $state = array(
-            'Responder' => array('sspmod_adfs_IdP_ADFS', 'sendResponse'),
+        $state = [
+            'Responder' => ['\SimpleSAML\Module\adfs\IdP\ADFS', 'sendResponse'],
             'SPMetadata' => $spMetadata->toArray(),
             'ForceAuthn' => false,
             'isPassive' => false,
             'adfs:wctx' => $requestid,
-        );
+            'adfs:wreply' => false
+        ];
 
-        $idp->handleAuthenticationRequest($state);		
+        if (isset($query['wreply']) && !empty($query['wreply'])) {
+            $state['adfs:wreply'] = \SimpleSAML\Utils\HTTP::checkURLAllowed($query['wreply']);
+        }
+
+        $idp->handleAuthenticationRequest($state);
     }
 
-    private static function generateResponse($issuer, $target, $nameid, $attributes)
+    private static function generateResponse($issuer, $target, $nameid, $attributes, $assertionLifetime)
     {
-        $issueInstant = SimpleSAML\Utils\Time::generateTimestamp();
-        $notBefore = SimpleSAML\Utils\Time::generateTimestamp(time() - 30);
-        $assertionExpire = SimpleSAML\Utils\Time::generateTimestamp(time() + 60 * 5);
-        $assertionID = SimpleSAML\Utils\Random::generateID();
+        $issueInstant = \SimpleSAML\Utils\Time::generateTimestamp();
+        $notBefore = \SimpleSAML\Utils\Time::generateTimestamp(time() - 30);
+        $assertionExpire = \SimpleSAML\Utils\Time::generateTimestamp(time() + $assertionLifetime);
+        $assertionID = \SimpleSAML\Utils\Random::generateID();
         $nameidFormat = 'http://schemas.xmlsoap.org/claims/UPN';
         $nameid = htmlspecialchars($nameid);
 
@@ -62,7 +73,10 @@ MSG;
                 continue;
             }
 
-            list($namespace, $name) = SimpleSAML\Utils\Attributes::getAttributeNamespace($name, 'http://schemas.xmlsoap.org/claims');
+            list($namespace, $name) = \SimpleSAML\Utils\Attributes::getAttributeNamespace(
+                $name,
+                'http://schemas.xmlsoap.org/claims'
+            );
             foreach ($values as $value) {
                 if ((!isset($value)) || ($value === '')) {
                     continue;
@@ -74,7 +88,6 @@ MSG;
                     <saml:AttributeValue>$value</saml:AttributeValue>
                 </saml:Attribute>
 MSG;
-
             }
         }
 
@@ -93,19 +106,21 @@ MSG;
         return $result;
     }
 
-    private static function signResponse($response, $key, $cert)
+    private static function signResponse($response, $key, $cert, $algo)
     {
         $objXMLSecDSig = new XMLSecurityDSig();
-        $objXMLSecDSig->idKeys = array('AssertionID');	
-        $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);	
-        $responsedom = \SAML2\DOMDocumentFactory::fromString(str_replace ("\r", "", $response));
+        $objXMLSecDSig->idKeys = ['AssertionID'];
+        $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
+        $responsedom = \SAML2\DOMDocumentFactory::fromString(str_replace("\r", "", $response));
         $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0);
         $objXMLSecDSig->addReferenceList(
-            array($firstassertionroot), XMLSecurityDSig::SHA1,
-            array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
-            array('id_name' => 'AssertionID')
+            [$firstassertionroot],
+            XMLSecurityDSig::SHA256,
+            ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N],
+            ['id_name' => 'AssertionID']
         );
-        $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));
+
+        $objKey = new XMLSecurityKey($algo, ['type' => 'private']);
         $objKey->loadKey($key, true);
         $objXMLSecDSig->sign($objKey);
         if ($cert) {
@@ -113,79 +128,83 @@ MSG;
             $objXMLSecDSig->add509Cert($public_cert, true);
         }
         $newSig = $responsedom->importNode($objXMLSecDSig->sigNode, true);
-        $firstassertionroot->appendChild($newSig);	
+        $firstassertionroot->appendChild($newSig);
         return $responsedom->saveXML();
     }
 
     private static function postResponse($url, $wresult, $wctx)
     {
-        $wresult = htmlspecialchars($wresult);
-        $wctx = htmlspecialchars($wctx);
-
-        $post = <<<MSG
-    <body onload="document.forms[0].submit()">
-        <form method="post" action="$url">
-            <input type="hidden" name="wa" value="wsignin1.0">
-            <input type="hidden" name="wresult" value="$wresult">
-            <input type="hidden" name="wctx" value="$wctx">
-            <noscript>
-                <input type="submit" value="Continue">
-            </noscript>
-        </form>
-    </body>
-MSG;
-
-        echo $post;
-        exit;
+        $config = \SimpleSAML\Configuration::getInstance();
+        $t = new \SimpleSAML\XHTML\Template($config, 'adfs:postResponse.twig');
+        $t->data['baseurlpath'] = \SimpleSAML\Module::getModuleURL('adfs');
+        $t->data['url'] = $url;
+        $t->data['wresult'] = $wresult;
+        $t->data['wctx'] = $wctx;
+        $t->show();
     }
 
     public static function sendResponse(array $state)
     {
         $spMetadata = $state["SPMetadata"];
         $spEntityId = $spMetadata['entityid'];
-        $spMetadata = SimpleSAML_Configuration::loadFromArray($spMetadata,
-            '$metadata[' . var_export($spEntityId, true) . ']');
+        $spMetadata = \SimpleSAML\Configuration::loadFromArray(
+            $spMetadata,
+            '$metadata['.var_export($spEntityId, true).']'
+        );
 
         $attributes = $state['Attributes'];
 
         $nameidattribute = $spMetadata->getValue('simplesaml.nameidattribute');
         if (!empty($nameidattribute)) {
             if (!array_key_exists($nameidattribute, $attributes)) {
-                throw new Exception('simplesaml.nameidattribute does not exist in resulting attribute set');
+                throw new \Exception('simplesaml.nameidattribute does not exist in resulting attribute set');
             }
             $nameid = $attributes[$nameidattribute][0];
         } else {
-            $nameid = SimpleSAML\Utils\Random::generateID();
+            $nameid = \SimpleSAML\Utils\Random::generateID();
         }
 
-        $idp = SimpleSAML_IdP::getByState($state);		
+        $idp = \SimpleSAML\IdP::getByState($state);
         $idpMetadata = $idp->getConfig();
         $idpEntityId = $idpMetadata->getString('entityid');
 
-        $idp->addAssociation(array(
-            'id' => 'adfs:' . $spEntityId,
-            'Handler' => 'sspmod_adfs_IdP_ADFS',
+        $idp->addAssociation([
+            'id' => 'adfs:'.$spEntityId,
+            'Handler' => '\SimpleSAML\Module\adfs\IdP\ADFS',
             'adfs:entityID' => $spEntityId,
-        ));
+        ]);
 
-        $response = sspmod_adfs_IdP_ADFS::generateResponse($idpEntityId, $spEntityId, $nameid, $attributes);
+        $assertionLifetime = $spMetadata->getInteger('assertion.lifetime', null);
+        if ($assertionLifetime === null) {
+            $assertionLifetime = $idpMetadata->getInteger('assertion.lifetime', 300);
+        }
+
+        $response = ADFS::generateResponse($idpEntityId, $spEntityId, $nameid, $attributes, $assertionLifetime);
 
         $privateKeyFile = \SimpleSAML\Utils\Config::getCertPath($idpMetadata->getString('privatekey'));
         $certificateFile = \SimpleSAML\Utils\Config::getCertPath($idpMetadata->getString('certificate'));
-        $wresult = sspmod_adfs_IdP_ADFS::signResponse($response, $privateKeyFile, $certificateFile);
+
+        $algo = $spMetadata->getString('signature.algorithm', null);
+        if ($algo === null) {
+            $algo = $idpMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
+        }
+        $wresult = ADFS::signResponse($response, $privateKeyFile, $certificateFile, $algo);
 
         $wctx = $state['adfs:wctx'];
-        sspmod_adfs_IdP_ADFS::postResponse($spMetadata->getValue('prp'), $wresult, $wctx);
+        $wreply = $state['adfs:wreply'] ? : $spMetadata->getValue('prp');
+        ADFS::postResponse($wreply, $wresult, $wctx);
     }
 
-    public static function sendLogoutResponse(SimpleSAML_IdP $idp, array $state)
+    public static function sendLogoutResponse(\SimpleSAML\IdP $idp, array $state)
     {
         // NB:: we don't know from which SP the logout request came from
         $idpMetadata = $idp->getConfig();
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($idpMetadata->getValue('redirect-after-logout', \SimpleSAML\Utils\HTTP::getBaseURL()));
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL(
+            $idpMetadata->getValue('redirect-after-logout', \SimpleSAML\Utils\HTTP::getBaseURL())
+        );
     }
 
-    public static function receiveLogoutMessage(SimpleSAML_IdP $idp)
+    public static function receiveLogoutMessage(\SimpleSAML\IdP $idp)
     {
         // if a redirect is to occur based on wreply, we will redirect to url as
         // this implies an override to normal sp notification
@@ -194,22 +213,24 @@ MSG;
             assert(false);
         }
 
-        $state = array(
-            'Responder' => array('sspmod_adfs_IdP_ADFS', 'sendLogoutResponse'),
-        );
+        $state = [
+            'Responder' => ['\SimpleSAML\Module\adfs\IdP\ADFS', 'sendLogoutResponse'],
+        ];
         $assocId = null;
-        // TODO: verify that this is really no problem for: 
+        // TODO: verify that this is really no problem for:
         //       a) SSP, because there's no caller SP.
         //       b) ADFS SP because caller will be called back..
         $idp->handleLogoutRequest($state, $assocId);
     }
 
     // accepts an association array, and returns a URL that can be accessed to terminate the association
-    public static function getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState)
+    public static function getLogoutURL(\SimpleSAML\IdP $idp, array $association, $relayState)
     {
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $spMetadata = $metadata->getMetaDataConfig($association['adfs:entityID'], 'adfs-sp-remote');
-        $returnTo = SimpleSAML\Module::getModuleURL('adfs/idp/prp.php?assocId=' . urlencode($association["id"]) . '&relayState=' . urlencode($relayState));
-        return $spMetadata->getValue('prp') . '?' . 'wa=wsignoutcleanup1.0&wreply=' . urlencode($returnTo);
+        $returnTo = \SimpleSAML\Module::getModuleURL(
+            'adfs/idp/prp.php?assocId='.urlencode($association["id"]).'&relayState='.urlencode($relayState)
+        );
+        return $spMetadata->getValue('prp').'?wa=wsignoutcleanup1.0&wreply='.urlencode($returnTo);
     }
 }
diff --git a/modules/adfs/lib/SAML2/XML/fed/Const.php b/modules/adfs/lib/SAML2/XML/fed/Const.php
index d24436ca32e6033db669d6cd5e986b8ae9f39b86..1fd7fb15e9f40dba500737b62683bfbbefdb5121 100644
--- a/modules/adfs/lib/SAML2/XML/fed/Const.php
+++ b/modules/adfs/lib/SAML2/XML/fed/Const.php
@@ -1,10 +1,14 @@
 <?php
+
+namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
+
 /**
  * Class representing fed Constants.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_adfs_SAML2_XML_fed_Const
+
+class FedConst
 {
     /**
      * The namespace for WS-FED protocol.
diff --git a/modules/adfs/lib/SAML2/XML/fed/Endpoint.php b/modules/adfs/lib/SAML2/XML/fed/Endpoint.php
index 24178c713864b96257e0b4518c7ccea141e0e7bf..d3ac56ad346d423bc21b354243dcaebae6112bb3 100644
--- a/modules/adfs/lib/SAML2/XML/fed/Endpoint.php
+++ b/modules/adfs/lib/SAML2/XML/fed/Endpoint.php
@@ -1,18 +1,22 @@
 <?php
+
+namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
+
 /**
  * Class representing fed Endpoint.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_adfs_SAML2_XML_fed_Endpoint
+
+class Endpoint
 {
     /**
      * Add this endpoint to an XML element.
      *
-     * @param DOMElement $parent  The element we should append this endpoint to.
+     * @param \DOMElement $parent  The element we should append this endpoint to.
      * @param string $name  The name of the element we should create.
      */
-    public static function appendXML(DOMElement $parent, $name, $address)
+    public static function appendXML(\DOMElement $parent, $name, $address)
     {
         assert(is_string($name));
         assert(is_string($address));
diff --git a/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php b/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php
index d162507e2a29c7429de30bd72c4d79af6cbd0280..55a802d507f38bb9137129f8bd64ee9b5fa7b351 100644
--- a/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php
+++ b/modules/adfs/lib/SAML2/XML/fed/SecurityTokenServiceType.php
@@ -1,17 +1,21 @@
 <?php
+
+namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
+
 /**
  * Class representing SecurityTokenServiceType RoleDescriptor.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_adfs_SAML2_XML_fed_SecurityTokenServiceType extends SAML2_XML_md_RoleDescriptor
+
+class SecurityTokenServiceType extends \SAML2\XML\md\RoleDescriptor
 {
     /**
      * List of supported protocols.
      *
      * @var array
      */
-    public $protocolSupportEnumeration = array(sspmod_adfs_SAML2_XML_fed_Const::NS_FED);
+    public $protocolSupportEnumeration = [FedConst::NS_FED];
 
     /**
      * The Location of Services.
@@ -23,9 +27,9 @@ class sspmod_adfs_SAML2_XML_fed_SecurityTokenServiceType extends SAML2_XML_md_Ro
     /**
      * Initialize a SecurityTokenServiceType element.
      *
-     * @param DOMElement|null $xml  The XML element we should load.
+     * @param \DOMElement|null $xml  The XML element we should load.
      */
-    public function __construct(DOMElement $xml = null)
+    public function __construct(\DOMElement $xml = null)
     {
         parent::__construct('RoleDescriptor', $xml);
         if ($xml === null) {
@@ -36,19 +40,19 @@ class sspmod_adfs_SAML2_XML_fed_SecurityTokenServiceType extends SAML2_XML_md_Ro
     /**
      * Convert this SecurityTokenServiceType RoleDescriptor to XML.
      *
-     * @param DOMElement $parent  The element we should add this contact to.
-     * @return DOMElement  The new ContactPerson-element.
+     * @param \DOMElement $parent  The element we should add this contact to.
+     * @return \DOMElement  The new ContactPerson-element.
      */
-    public function toXML(DOMElement $parent)
+    public function toXML(\DOMElement $parent)
     {
         assert(is_string($this->Location));
 
         $e = parent::toXML($parent);
-        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:fed', sspmod_adfs_SAML2_XML_fed_Const::NS_FED);
+        $e->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:fed', FedConst::NS_FED);
         $e->setAttributeNS(\SAML2\Constants::NS_XSI, 'xsi:type', 'fed:SecurityTokenServiceType');
-        sspmod_adfs_SAML2_XML_fed_TokenTypesOffered::appendXML($e);
-        sspmod_adfs_SAML2_XML_fed_Endpoint::appendXML($e, 'SecurityTokenServiceEndpoint', $this->Location);
-        sspmod_adfs_SAML2_XML_fed_Endpoint::appendXML($e, 'fed:PassiveRequestorEndpoint', $this->Location);
+        TokenTypesOffered::appendXML($e);
+        Endpoint::appendXML($e, 'SecurityTokenServiceEndpoint', $this->Location);
+        Endpoint::appendXML($e, 'fed:PassiveRequestorEndpoint', $this->Location);
 
         return $e;
     }
diff --git a/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php b/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php
index 280b80c3aecd261a764a2d1efb3ad74285bacb2f..8e30f442c7b23a7e823c253c5190b2ce8ae4511a 100644
--- a/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php
+++ b/modules/adfs/lib/SAML2/XML/fed/TokenTypesOffered.php
@@ -1,22 +1,26 @@
 <?php
+
+namespace SimpleSAML\Module\adfs\SAML2\XML\fed;
+
 /**
  * Class representing fed TokenTypesOffered.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_adfs_SAML2_XML_fed_TokenTypesOffered
+
+class TokenTypesOffered
 {
     /**
      * Add tokentypesoffered to an XML element.
      *
-     * @param DOMElement $parent  The element we should append this endpoint to.
+     * @param \DOMElement $parent  The element we should append this endpoint to.
      */
-    public static function appendXML(DOMElement $parent)
+    public static function appendXML(\DOMElement $parent)
     {
-        $e = $parent->ownerDocument->createElementNS(sspmod_adfs_SAML2_XML_fed_Const::NS_FED, 'fed:TokenTypesOffered');
+        $e = $parent->ownerDocument->createElementNS(FedConst::NS_FED, 'fed:TokenTypesOffered');
         $parent->appendChild($e);
 
-        $tokentype = $parent->ownerDocument->createElementNS(sspmod_adfs_SAML2_XML_fed_Const::NS_FED, 'fed:TokenType');
+        $tokentype = $parent->ownerDocument->createElementNS(FedConst::NS_FED, 'fed:TokenType');
         $tokentype->setAttribute('Uri', 'urn:oasis:names:tc:SAML:1.0:assertion');
         $e->appendChild($tokentype);
 
diff --git a/modules/adfs/templates/postResponse.twig b/modules/adfs/templates/postResponse.twig
new file mode 100644
index 0000000000000000000000000000000000000000..857aa8d7ab6fcd28e21630ea84031a22452840a4
--- /dev/null
+++ b/modules/adfs/templates/postResponse.twig
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="{{ baseurlpath }}/assets/js/postResponse.js"></script>
+    </head>
+    <body>
+        <form method="post" action="{{ url }}">
+            <input type="hidden" name="wa" value="wsignin1.0">
+            <input type="hidden" name="wresult" value="{{ wresult|escape('html') }}">
+            <input type="hidden" name="wctx" value="{{ wctx|escape('html') }}">
+            <noscript>
+                <input type="submit" value="Continue">
+            </noscript>
+        </form>
+    </body>
+</html>
diff --git a/modules/adfs/www/assets/js/postReponse.js b/modules/adfs/www/assets/js/postReponse.js
new file mode 100644
index 0000000000000000000000000000000000000000..a813b92cbec83b7ac265163431ac1f0d7d5f00e3
--- /dev/null
+++ b/modules/adfs/www/assets/js/postReponse.js
@@ -0,0 +1,3 @@
+document.addEventListener('DOMContentLoaded', function () {
+    document.forms[0].submit();
+});
diff --git a/modules/adfs/www/idp/metadata.php b/modules/adfs/www/idp/metadata.php
index aaec9361c213de440ccbc8be7db6616007b3cb08..473af96dc6e9bf81e910b3e0fd4370998798f6fb 100644
--- a/modules/adfs/www/idp/metadata.php
+++ b/modules/adfs/www/idp/metadata.php
@@ -1,79 +1,78 @@
 <?php
 
 // load configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$config = \SimpleSAML\Configuration::getInstance();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
 if (!$config->getBoolean('enable.adfs-idp', false)) {
-    throw new SimpleSAML_Error_Error('NOACCESS');
+    throw new \SimpleSAML\Error\Error('NOACCESS');
 }
 
 // check if valid local session exists
 if ($config->getBoolean('admin.protectmetadata', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
 
 try {
     $idpentityid = isset($_GET['idpentityid']) ?
-        $_GET['idpentityid'] :
-        $metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
+        $_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
     $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'adfs-idp-hosted');
 
-    $availableCerts = array();
+    $availableCerts = [];
 
-    $keys = array();
-    $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
+    $keys = [];
+    $certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
     if ($certInfo !== null) {
         $availableCerts['new_idp.crt'] = $certInfo;
-        $keys[] = array(
+        $keys[] = [
             'type'            => 'X509Certificate',
             'signing'         => true,
             'encryption'      => true,
             'X509Certificate' => $certInfo['certData'],
-        );
+        ];
         $hasNewCert = true;
     } else {
         $hasNewCert = false;
     }
 
-    $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
+    $certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
     $availableCerts['idp.crt'] = $certInfo;
-    $keys[] = array(
+    $keys[] = [
         'type'            => 'X509Certificate',
         'signing'         => true,
         'encryption'      => ($hasNewCert ? false : true),
         'X509Certificate' => $certInfo['certData'],
-    );
+    ];
 
     if ($idpmeta->hasValue('https.certificate')) {
-        $httpsCert = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
+        $httpsCert = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
         assert(isset($httpsCert['certData']));
         $availableCerts['https.crt'] = $httpsCert;
-        $keys[] = array(
+        $keys[] = [
             'type'            => 'X509Certificate',
             'signing'         => true,
             'encryption'      => false,
             'X509Certificate' => $httpsCert['certData'],
-        );
+        ];
     }
 
-    $adfs_service_location = SimpleSAML\Module::getModuleURL('adfs').'/idp/prp.php';
-    $metaArray = array(
+    $adfs_service_location = \SimpleSAML\Module::getModuleURL('adfs').'/idp/prp.php';
+    $metaArray = [
         'metadata-set'        => 'adfs-idp-remote',
         'entityid'            => $idpentityid,
-        'SingleSignOnService' => array(
-            0 => array(
+        'SingleSignOnService' => [
+            0 => [
                 'Binding'  => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 'Location' => $adfs_service_location
-            )
-        ),
-        'SingleLogoutService' => array(
-            0 => array(
+            ]
+        ],
+        'SingleLogoutService' => [
+            0 => [
                 'Binding'  => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 'Location' => $adfs_service_location
-            )
-        ),
-    );
+            ]
+        ],
+    ];
 
     if (count($keys) === 1) {
         $metaArray['certData'] = $keys[0]['X509Certificate'];
@@ -94,7 +93,7 @@ try {
         );
 
         if (!$idpmeta->hasValue('OrganizationURL')) {
-            throw new SimpleSAML_Error_Exception('If OrganizationName is set, OrganizationURL must also be set.');
+            throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
         }
         $metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
     }
@@ -121,16 +120,16 @@ try {
 
     $metaflat = '$metadata['.var_export($idpentityid, true).'] = '.var_export($metaArray, true).';';
 
-    $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid);
+    $metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($idpentityid);
     $metaBuilder->addSecurityTokenServiceType($metaArray);
     $metaBuilder->addOrganizationInfo($metaArray);
     $technicalContactEmail = $config->getString('technicalcontact_email', null);
     if ($technicalContactEmail && $technicalContactEmail !== 'na@example.org') {
-        $metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact(array(
+        $metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact([
             'emailAddress' => $technicalContactEmail,
             'name'         => $config->getString('technicalcontact_name', null),
             'contactType'  => 'technical',
-        )));
+        ]));
     }
     $output_xhtml = array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml';
     $metaxml = $metaBuilder->getEntityDescriptorText($output_xhtml);
@@ -139,17 +138,30 @@ try {
     }
 
     // sign the metadata if enabled
-    $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP');
+    $metaxml = \SimpleSAML\Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'ADFS IdP');
 
     if ($output_xhtml) {
         $defaultidp = $config->getString('default-adfs-idp', null);
 
-        $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin');
+        $t = new \SimpleSAML\XHTML\Template($config, 'metadata.php', 'admin');
 
         $t->data['clipboard.js'] = true;
         $t->data['available_certs'] = $availableCerts;
+        $certdata = [];
+        foreach (array_keys($availableCerts) as $availableCert) {
+            $certdata[$availableCert]['name'] = $availableCert;
+            $certdata[$availableCert]['url'] = \SimpleSAML\Module::getModuleURL('saml/idp/certs.php').
+                '/'.$availableCert;
+
+            $certdata[$availableCert]['comment'] = '';
+            if ($availableCerts[$availableCert]['certFingerprint'][0] === 'afe71c28ef740bc87425be13a2263d37971da1f9') {
+                $certdata[$availableCert]['comment'] = 'This is the default certificate.'.
+                    ' Generate a new certificate if this is a production system.';
+            }
+        }
+        $t->data['certdata'] = $certdata;
         $t->data['header'] = 'adfs-idp'; // TODO: Replace with headerString in 2.0
-        $t->data['headerString'] = $t->noop('metadata_adfs-idp');
+        $t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_adfs-idp');
         $t->data['metaurl'] = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery();
         $t->data['metadata'] = htmlspecialchars($metaxml);
         $t->data['metadataflat'] = htmlspecialchars($metaflat);
@@ -166,6 +178,6 @@ try {
 
         exit(0);
     }
-} catch (Exception $exception) {
-    throw new SimpleSAML_Error_Error('METADATA', $exception);
+} catch (\Exception $exception) {
+    throw new \SimpleSAML\Error\Error('METADATA', $exception);
 }
diff --git a/modules/adfs/www/idp/prp.php b/modules/adfs/www/idp/prp.php
index 99f8db825cd43553196b7a75401972191e133a3b..03a973b11656b4d2a020e79d0a4834c9ab8a265d 100644
--- a/modules/adfs/www/idp/prp.php
+++ b/modules/adfs/www/idp/prp.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * ADFS PRP IDP protocol support for SimpleSAMLphp.
  *
@@ -6,23 +7,23 @@
  * @package SimpleSAMLphp
  */
 
-SimpleSAML\Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
+\SimpleSAML\Logger::info('ADFS - IdP.prp: Accessing ADFS IdP endpoint prp');
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('adfs-idp-hosted');
-$idp = SimpleSAML_IdP::getById('adfs:' . $idpEntityId);
+$idp = \SimpleSAML\IdP::getById('adfs:'.$idpEntityId);
 
 if (isset($_GET['wa'])) {
     if ($_GET['wa'] === 'wsignout1.0') {
-        sspmod_adfs_IdP_ADFS::receiveLogoutMessage($idp);
-    } else if ($_GET['wa'] === 'wsignin1.0') {
-        sspmod_adfs_IdP_ADFS::receiveAuthnRequest($idp);
+        \SimpleSAML\Module\adfs\IdP\ADFS::receiveLogoutMessage($idp);
+    } elseif ($_GET['wa'] === 'wsignin1.0') {
+        \SimpleSAML\Module\adfs\IdP\ADFS::receiveAuthnRequest($idp);
     }
     assert(false);
 } elseif (isset($_GET['assocId'])) {
     // logout response from ADFS SP
     $assocId = $_GET['assocId']; // Association ID of the SP that sent the logout response
     $relayState = $_GET['relayState']; // Data that was sent in the logout request to the SP. Can be null
-    $logoutError = null; // null on success, or an instance of a SimpleSAML_Error_Exception on failure.
+    $logoutError = null; // null on success, or an instance of a \SimpleSAML\Error\Exception on failure.
     $idp->handleLogoutResponse($assocId, $relayState, $logoutError);
 }
diff --git a/modules/authX509/dictionaries/X509warning.definition.json b/modules/authX509/dictionaries/X509warning.definition.json
index e74d3077517bc60b78b8ff54d9f4baef80114fa4..d56bed1be7cac133e4e66fafdfe182c19be23de0 100644
--- a/modules/authX509/dictionaries/X509warning.definition.json
+++ b/modules/authX509/dictionaries/X509warning.definition.json
@@ -1,6 +1,6 @@
 {
   "warning": {
-    "en": "Your certificate will expire in %days% days."
+    "en": "Your certificate will expire in %daysleft% days."
   },
   "warning_header": {
     "en": "Your certificate is about to expire."
diff --git a/modules/authX509/dictionaries/X509warning.translation.json b/modules/authX509/dictionaries/X509warning.translation.json
index 4a9b0b95774683605ea7b24229f8fff0705265b2..e22096295f62ed70bd97b712e0910f4f06f5f737 100644
--- a/modules/authX509/dictionaries/X509warning.translation.json
+++ b/modules/authX509/dictionaries/X509warning.translation.json
@@ -1,10 +1,10 @@
 {
   "warning": {
-    "nl": "Je certificaat verloopt over %days% dagen.",
-    "no": "Sertifikatet ditt vil utløpe om %days% dager.",
-    "da": "Dit certifikat udløber om %days% dage.",
-    "es": "Su certificado caduca en %days% dĂ­as.",
-    "el": "\u0397 \u03b9\u03c3\u03c7\u03cd\u03c2 \u03c4\u03bf\u03c5 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd \u03c3\u03b1\u03c2 \u03b8\u03b1 \u03bb\u03ae\u03be\u03b5\u03b9 \u03c3\u03b5 %days%."
+    "nl": "Je certificaat verloopt over %daysleft% dagen.",
+    "no": "Sertifikatet ditt vil utløpe om %daysleft% dager.",
+    "da": "Dit certifikat udløber om %daysleft% dage.",
+    "es": "Su certificado caduca en %daysleft% dĂ­as.",
+    "el": "\u0397 \u03b9\u03c3\u03c7\u03cd\u03c2 \u03c4\u03bf\u03c5 \u03c0\u03b9\u03c3\u03c4\u03bf\u03c0\u03bf\u03b9\u03b7\u03c4\u03b9\u03ba\u03bf\u03cd \u03c3\u03b1\u03c2 \u03b8\u03b1 \u03bb\u03ae\u03be\u03b5\u03b9 \u03c3\u03b5 %daysleft%."
   },
   "warning_header": {
     "nl": "Je certificaat verloopt binnenkort.",
diff --git a/modules/authX509/docs/authX509.md b/modules/authX509/docs/authX509.md
index ac4a65851e7d975798939578950067ce513fb28a..dcb8ff92590351fe477cefa1cf7be18db0a13dc6 100644
--- a/modules/authX509/docs/authX509.md
+++ b/modules/authX509/docs/authX509.md
@@ -47,9 +47,9 @@ example authsources.php entry:
     'x509' => array(
         'authX509:X509userCert',
         'hostname' => 'ldaps://ldap.example.net',
-        'enable_tls' => FALSE,
-        'attributes' => array("cn", "uid", "mail", "ou", "sn"),
-        'search.enable' => TRUE,
+        'enable_tls' => false,
+        'attributes' => array('cn', 'uid', 'mail', 'ou', 'sn'),
+        'search.enable' => true,
         'search.attributes' => array('uid', 'mail'),
         'search.base' => 'dc=example,dc=net',
         'authX509:x509attributes' => array('UID' => 'uid'),
diff --git a/modules/authX509/lib/Auth/Process/ExpiryWarning.php b/modules/authX509/lib/Auth/Process/ExpiryWarning.php
index 0a6fe5bf9bb48df307d7baa78ff918c83762f179..1b9c1ca8753b5dc95ae1bb3a6830245a400e45f7 100644
--- a/modules/authX509/lib/Auth/Process/ExpiryWarning.php
+++ b/modules/authX509/lib/Auth/Process/ExpiryWarning.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authX509\Auth\Process;
+
 /**
  * Filter which shows a warning if the user's client certificate is about to expire.
  *
@@ -14,7 +16,8 @@
  * @author Joost van Dijk, SURFnet. <Joost.vanDijk@surfnet.nl>
  * @package SimpleSAMLphp
  */
-class sspmod_authX509_Auth_Process_ExpiryWarning extends SimpleSAML_Auth_ProcessingFilter
+
+class ExpiryWarning extends \SimpleSAML\Auth\ProcessingFilter
 {
 
     private $warndaysbefore = 30;
@@ -35,14 +38,14 @@ class sspmod_authX509_Auth_Process_ExpiryWarning extends SimpleSAML_Auth_Process
         if (array_key_exists('warndaysbefore', $config)) {
             $this->warndaysbefore = $config['warndaysbefore'];
             if (!is_string($this->warndaysbefore)) {
-                throw new Exception('Invalid value for \'warndaysbefore\'-option to authX509::ExpiryWarning filter.');
+                throw new \Exception('Invalid value for \'warndaysbefore\'-option to authX509::ExpiryWarning filter.');
             }
         }
 
         if (array_key_exists('renewurl', $config)) {
             $this->renewurl = $config['renewurl'];
             if (!is_string($this->renewurl)) {
-                throw new Exception('Invalid value for \'renewurl\'-option to authX509::ExpiryWarning filter.');
+                throw new \Exception('Invalid value for \'renewurl\'-option to authX509::ExpiryWarning filter.');
             }
         }
     }
@@ -72,25 +75,24 @@ class sspmod_authX509_Auth_Process_ExpiryWarning extends SimpleSAML_Auth_Process
         $client_cert = $_SERVER['SSL_CLIENT_CERT'];
         $client_cert_data = openssl_x509_parse($client_cert);
         if ($client_cert_data == false) {
-            SimpleSAML\Logger::error('authX509: invalid cert');
+            \SimpleSAML\Logger::error('authX509: invalid cert');
             return;
         }
         $validTo = $client_cert_data['validTo_time_t'];
         $now = time();
-        $daysleft = (int)(($validTo - $now) / (24*60*60));
+        $daysleft = (int) (($validTo - $now) / 86400); //24*60*60
         if ($daysleft > $this->warndaysbefore) {
             // We have a certificate that will be valid for some time. Skip the warning
             return;
         }
 
-        SimpleSAML\Logger::warning('authX509: user certificate expires in ' . $daysleft . ' days');
+        \SimpleSAML\Logger::warning('authX509: user certificate expires in '.$daysleft.' days');
         $state['daysleft'] = $daysleft;
         $state['renewurl'] = $this->renewurl;
 
-        /* Save state and redirect. */
-        $id = SimpleSAML_Auth_State::saveState($state, 'warning:expire');
-        $url = SimpleSAML\Module::getModuleURL('authX509/expirywarning.php');
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
+        // Save state and redirect
+        $id = \SimpleSAML\Auth\State::saveState($state, 'warning:expire');
+        $url = \SimpleSAML\Module::getModuleURL('authX509/expirywarning.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
     }
-
 }
diff --git a/modules/authX509/lib/Auth/Source/X509userCert.php b/modules/authX509/lib/Auth/Source/X509userCert.php
index 36f93a48f7a11d6c1d660132a3e83622d7f42a77..4605c0ee97e4b19e95909e81c2ab255ee7922254 100644
--- a/modules/authX509/lib/Auth/Source/X509userCert.php
+++ b/modules/authX509/lib/Auth/Source/X509userCert.php
@@ -1,24 +1,26 @@
 <?php
 
+namespace SimpleSAML\Module\authX509\Auth\Source;
+
 /**
  * This class implements x509 certificate authentication with certificate validation against an LDAP directory.
  *
  * @author Emmanuel Dreyfus <manu@netbsd.org>
  * @package SimpleSAMLphp
  */
-class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
-{
 
+class X509userCert extends \SimpleSAML\Auth\Source
+{
     /**
      * x509 attributes to use from the certificate for searching the user in the LDAP directory.
      */
-    private $x509attributes = array('UID' => 'uid');
+    private $x509attributes = ['UID' => 'uid'];
 
 
     /**
      * LDAP attribute containing the user certificate.
      */
-    private $ldapusercert = array('userCertificate;binary');
+    private $ldapusercert = ['userCertificate;binary'];
 
 
     /**
@@ -50,9 +52,9 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
 
         parent::__construct($info, $config);
 
-        $this->ldapcf = new sspmod_ldap_ConfigHelper(
+        $this->ldapcf = new \SimpleSAML\Module\ldap\ConfigHelper(
             $config,
-            'Authentication source ' . var_export($this->authId, true)
+            'Authentication source '.var_export($this->authId, true)
         );
 
         return;
@@ -68,11 +70,12 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
      */
     public function authFailed(&$state)
     {
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = \SimpleSAML\Configuration::getInstance();
 
-        $t = new SimpleSAML_XHTML_Template($config, 'authX509:X509error.php');
+        $t = new \SimpleSAML\XHTML\Template($config, 'authX509:X509error.php');
+        $t->data['loginurl'] = \SimpleSAML\Utils\HTTP::getSelfURL();
         $t->data['errorcode'] = $state['authX509.error'];
-        $t->data['errorcodes'] = SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
+        $t->data['errorcodes'] = \SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
 
         $t->show();
         exit();
@@ -104,7 +107,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
         $client_cert = $_SERVER['SSL_CLIENT_CERT'];
         $client_cert_data = openssl_x509_parse($client_cert);
         if ($client_cert_data === false) {
-            SimpleSAML\Logger::error('authX509: invalid cert');
+            \SimpleSAML\Logger::error('authX509: invalid cert');
             $state['authX509.error'] = "INVALIDCERT";
             $this->authFailed($state);
 
@@ -117,7 +120,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
             // value is scalar
             if (array_key_exists($x509_attr, $client_cert_data['subject'])) {
                 $value = $client_cert_data['subject'][$x509_attr];
-                SimpleSAML\Logger::info('authX509: cert '. $x509_attr.' = '.$value);
+                \SimpleSAML\Logger::info('authX509: cert '.$x509_attr.' = '.$value);
                 $dn = $ldapcf->searchfordn($ldap_attr, $value, true);
                 if ($dn !== null) {
                     break;
@@ -126,7 +129,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
         }
 
         if ($dn === null) {
-            SimpleSAML\Logger::error('authX509: cert has no matching user in LDAP.');
+            \SimpleSAML\Logger::error('authX509: cert has no matching user in LDAP.');
             $state['authX509.error'] = "UNKNOWNCERT";
             $this->authFailed($state);
 
@@ -134,7 +137,8 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
             return;
         }
 
-        if ($this->ldapusercert === null) { // do not check for certificate match
+        if ($this->ldapusercert === null) {
+            // do not check for certificate match
             $attributes = $ldapcf->getAttributes($dn);
             assert(is_array($attributes));
             $state['Attributes'] = $attributes;
@@ -146,7 +150,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
 
         $ldap_certs = $ldapcf->getAttributes($dn, $this->ldapusercert);
         if ($ldap_certs === false) {
-            SimpleSAML\Logger::error('authX509: no certificate found in LDAP for dn='.$dn);
+            \SimpleSAML\Logger::error('authX509: no certificate found in LDAP for dn='.$dn);
             $state['authX509.error'] = "UNKNOWNCERT";
             $this->authFailed($state);
 
@@ -155,7 +159,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
         }
 
 
-        $merged_ldapcerts = array();
+        $merged_ldapcerts = [];
         foreach ($this->ldapusercert as $attr) {
             $merged_ldapcerts = array_merge($merged_ldapcerts, $ldap_certs[$attr]);
         }
@@ -165,7 +169,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
             $pem = \SimpleSAML\Utils\Crypto::der2pem($ldap_cert);
             $ldap_cert_data = openssl_x509_parse($pem);
             if ($ldap_cert_data === false) {
-                SimpleSAML\Logger::error('authX509: cert in LDAP is invalid for dn='.$dn);
+                \SimpleSAML\Logger::error('authX509: cert in LDAP is invalid for dn='.$dn);
                 continue;
             }
 
@@ -180,7 +184,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
             }
         }
 
-        SimpleSAML\Logger::error('authX509: no matching cert in LDAP for dn='.$dn);
+        \SimpleSAML\Logger::error('authX509: no matching cert in LDAP for dn='.$dn);
         $state['authX509.error'] = "UNKNOWNCERT";
         $this->authFailed($state);
 
@@ -198,7 +202,7 @@ class sspmod_authX509_Auth_Source_X509userCert extends SimpleSAML_Auth_Source
      */
     public function authSuccesful(&$state)
     {
-        SimpleSAML_Auth_Source::completeAuth($state);
+        \SimpleSAML\Auth\Source::completeAuth($state);
 
         assert(false); // should never be reached
         return;
diff --git a/modules/authX509/locales/da/LC_MESSAGES/authX509.po b/modules/authX509/locales/da/LC_MESSAGES/authX509.po
index 6e89789b11eeaedc1e17999179cc8e33806d6b24..a883034f930b787cb6816e7600cc31884625c17e 100644
--- a/modules/authX509/locales/da/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/da/LC_MESSAGES/authX509.po
@@ -34,20 +34,20 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "X509 certifikat authentifikation"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Dit certifikat udløber om %days% dage."
+msgstr "Dit certifikat udløber om %daysleft% dage."
 
 msgid "Please renew your certificate in time."
 msgstr "Forny venligst dit certifikat i tide."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Dit certifikat udløber om %days% dage."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Dit certifikat udløber om %daysleft% dage."
 
 msgid "X509 certificate authentication"
 msgstr "X509 certifikat authentifikation"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
+msgid "Please <a href='%renewurl%'>renew your certificate</a> in time."
 msgstr "<a href='%renewurl%'>Forny</a>, venligst dit certifikat før det udløber."
 
 msgid "Proceed"
diff --git a/modules/authX509/locales/el/LC_MESSAGES/authX509.po b/modules/authX509/locales/el/LC_MESSAGES/authX509.po
index 26cf3a027cbe01bb0a24cf710dda4127e44e0083..8fb335efc17d27d406955f0b34d1716b8a26bde5 100644
--- a/modules/authX509/locales/el/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/el/LC_MESSAGES/authX509.po
@@ -36,20 +36,20 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "Ταυτοποίηση μέσω πιστοποιητικού X.509"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Η ισχύς του πιστοποιητικού σας θα λήξει σε %days%."
+msgstr "Η ισχύς του πιστοποιητικού σας θα λήξει σε %daysleft%."
 
 msgid "Please renew your certificate in time."
 msgstr "Παρακαλείστε να προχωρήσετε σε ανανέωση του πιστοποιητικού σας έγκαιρα."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Η ισχύς του πιστοποιητικού σας θα λήξει σε %days%."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Η ισχύς του πιστοποιητικού σας θα λήξει σε %daysleft%."
 
 msgid "X509 certificate authentication"
 msgstr "Ταυτοποίηση μέσω πιστοποιητικού X.509"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
+msgid "Please <a href='%renewurl%'>renew your certificate</a> in time."
 msgstr ""
 "Παρακαλείστε να προχωρήσετε σε <a href=‘%renewurl%’>ανανέωση</a> του "
 "πιστοποιητικού σας έγκαιρα."
diff --git a/modules/authX509/locales/en/LC_MESSAGES/authX509.po b/modules/authX509/locales/en/LC_MESSAGES/authX509.po
index 6457d3edf9f73184fc4f7fa524fa0269a9badcde..6e317173c419d855cf6a408ec4f3760912be5f8e 100644
--- a/modules/authX509/locales/en/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/en/LC_MESSAGES/authX509.po
@@ -34,21 +34,21 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "X509 certificate authentication"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Your certificate will expire in %days% days."
+msgstr "Your certificate will expire in %daysleft% days."
 
 msgid "Please renew your certificate in time."
 msgstr "Please renew your certificate in time."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Your certificate will expire in %days% days."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Your certificate will expire in %daysleft% days."
 
 msgid "X509 certificate authentication"
 msgstr "X509 certificate authentication"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
-msgstr "Please  <a href='%renewurl%'>renew</a> your certificate in time."
+msgid "Please <a href='%renewurl%'>renew your certificate</a> in time."
+msgstr "Please <a href='%renewurl%'>renew your certificate</a> in time."
 
 msgid "Proceed"
 msgstr "Proceed"
diff --git a/modules/authX509/locales/es/LC_MESSAGES/authX509.po b/modules/authX509/locales/es/LC_MESSAGES/authX509.po
index 7256e926b8d3551b5a895d521743ba83bfc38b19..e25961f4ea500c71aac0d07059d3d0e247ef623a 100644
--- a/modules/authX509/locales/es/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/es/LC_MESSAGES/authX509.po
@@ -36,21 +36,21 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "AutenticaciĂłn mediante certificado X509"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Su certificado caduca en %days% dĂ­as."
+msgstr "Su certificado caduca en %daysleft% dĂ­as."
 
 msgid "Please renew your certificate in time."
 msgstr "Por favor, renueve su certificado a tiempo."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Su certificado caduca en %days% dĂ­as."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Su certificado caduca en %daysleft% dĂ­as."
 
 msgid "X509 certificate authentication"
 msgstr "AutenticaciĂłn mediante certificado X509"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
-msgstr "Por favor, <a href=‘%renewurl%’>renueve</a> su certificado a tiempo."
+msgid "Please <a href='%renewurl%'>renew your certificate</a> in time."
+msgstr "Por favor, <a href=‘%renewurl%’>renueve su certificado</a> a tiempo."
 
 msgid "Proceed"
 msgstr "Continuar"
diff --git a/modules/authX509/locales/nb/LC_MESSAGES/authX509.po b/modules/authX509/locales/nb/LC_MESSAGES/authX509.po
index 1a74b995c595348f39769573f7e147771bda08e3..6517289e0bb7986b1aec16c5d699b67b20f488ba 100644
--- a/modules/authX509/locales/nb/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/nb/LC_MESSAGES/authX509.po
@@ -36,20 +36,20 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "X509 sertifikatautentisering"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Sertifikatet ditt vil utløpe om %days% dager."
+msgstr "Sertifikatet ditt vil utløpe om %daysleft% dager."
 
 msgid "Please renew your certificate in time."
 msgstr "Vennligst forny sertifikatet ditt før det utløper."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Sertifikatet ditt vil utløpe om %days% dager."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Sertifikatet ditt vil utløpe om %daysleft% dager."
 
 msgid "X509 certificate authentication"
 msgstr "X509 sertifikatautentisering"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
+msgid "Please <a href='%renewurl%'>renew your certificate</a> in time."
 msgstr ""
 "Vennligst <a href=‘%renewurl%’>forny</a> sertifikatet ditt før det "
 "utløper."
diff --git a/modules/authX509/locales/nl/LC_MESSAGES/authX509.po b/modules/authX509/locales/nl/LC_MESSAGES/authX509.po
index 5e341db07117801add3c15160524396202c3e766..3515e80ead16e2a92048eebab00d274cef65441a 100644
--- a/modules/authX509/locales/nl/LC_MESSAGES/authX509.po
+++ b/modules/authX509/locales/nl/LC_MESSAGES/authX509.po
@@ -36,21 +36,21 @@ msgid "{authX509:X509error:certificate_header}"
 msgstr "Authenticatie via X509-certificaat"
 
 msgid "{authX509:X509warning:warning}"
-msgstr "Je certificaat verloopt over %days% dagen."
+msgstr "Je certificaat verloopt over %daysleft% dagen."
 
 msgid "Please renew your certificate in time."
 msgstr "Vervang tijdig je certificaat."
 
 #, python-format
-msgid "Your certificate will expire in %days% days."
-msgstr "Je certificaat verloopt over %days% dagen."
+msgid "Your certificate will expire in %daysleft% days."
+msgstr "Je certificaat verloopt over %daysleft% dagen."
 
 msgid "X509 certificate authentication"
 msgstr "Authenticatie via X509-certificaat"
 
 #, python-format
-msgid "Please  <a href='%renewurl%'>renew</a> your certificate in time."
-msgstr "<a href='%renewurl%'>Vervang</a> tijdig je certificaat."
+msgid "Please <a href=\"%renewurl%\">renew your certificate</a> in time."
+msgstr "<a href=\"%renewurl%\">Vervang tijdig je certificaat</a>."
 
 msgid "Proceed"
 msgstr "Verder"
diff --git a/modules/authX509/templates/X509error.php b/modules/authX509/templates/X509error.php
index 089128a65de7c4093d47abc372b5e5eeaddd5bad..b7f8d42802a9a48e5923fd52e0d577909e409dd2 100644
--- a/modules/authX509/templates/X509error.php
+++ b/modules/authX509/templates/X509error.php
@@ -3,39 +3,32 @@ $this->data['header'] = $this->t('{authX509:X509error:certificate_header}');
 
 $this->includeAtTemplateBase('includes/header.php');
 
-?>
-
-<?php
 if ($this->data['errorcode'] !== null) {
 ?>
-	<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
-		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l" style="margin: 15px" alt="" />
-		<h2><?php echo $this->t('{login:error_header}'); ?></h2>
-		<p><b><?php echo $this->t($this->data['errorcodes']['title'][$this->data['errorcode']]); ?></b></p>
-		<p><?php echo $this->t($this->data['errorcodes']['descr'][$this->data['errorcode']]); ?></p>
-	</div>
+    <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+        <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l" style="margin: 15px" alt="" />
+        <h2><?php echo $this->t('{login:error_header}'); ?></h2>
+        <p><b><?php echo $this->t($this->data['errorcodes']['title'][$this->data['errorcode']]); ?></b></p>
+        <p><?php echo $this->t($this->data['errorcodes']['descr'][$this->data['errorcode']]); ?></p>
+    </div>
 <?php
 }
 ?>
-	<h2 style="break: both"><?php echo $this->t('{authX509:X509error:certificate_header}'); ?></h2>
-
-	<p><?php echo $this->t('{authX509:X509error:certificate_text}'); ?></p>
+    <h2 style="break: both"><?php echo $this->t('{authX509:X509error:certificate_header}'); ?></h2>
 
-	<a href="<?php echo htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURL()); ?>">
-		<?php echo $this->t('{login:login_button}'); ?>
-	</a>
+    <p><?php echo $this->t('{authX509:X509error:certificate_text}'); ?></p>
 
+    <a href="<?php echo htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURL()); ?>">
+        <?php echo $this->t('{login:login_button}'); ?>
+    </a>
 <?php
 
-if(!empty($this->data['links'])) {
-	echo '<ul class="links" style="margin-top: 2em">';
-	foreach($this->data['links'] AS $l) {
-		echo '<li><a href="' . htmlspecialchars($l['href']) . '">' . htmlspecialchars($this->t($l['text'])) . '</a></li>';
-	}
-	echo '</ul>';
+if (!empty($this->data['links'])) {
+    echo '<ul class="links" style="margin-top: 2em">';
+    foreach ($this->data['links'] as $l) {
+        echo '<li><a href="'.htmlspecialchars($l['href']).'">'.htmlspecialchars($this->t($l['text'])).'</a></li>';
+    }
+    echo '</ul>';
 }
 
-
-
-
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/authX509/templates/X509error.twig b/modules/authX509/templates/X509error.twig
new file mode 100644
index 0000000000000000000000000000000000000000..becaebdb722c7d0067293661a350520a77df917a
--- /dev/null
+++ b/modules/authX509/templates/X509error.twig
@@ -0,0 +1,19 @@
+{% set pagetitle = 'X509 certificate authentication'|trans %}
+{% extends "base.twig" %}
+{% block content %}
+
+{% if errorcode -%}
+<h2>{% trans 'Error' %}</h2>
+<h3>{% trans errortitle %}</h3>
+<p>{% trans errordescr %}</p>
+{% endif -%}
+
+<h2>{% trans 'X509 certificate authentication' %}</h2>
+
+<p>{% trans 'X509 certificate authentication is required to access this service.' %}</p>
+
+<a href="{{ loginurl }}">
+{% trans 'Login' %}
+</a>
+
+{% endblock %}
diff --git a/modules/authX509/templates/X509warning.php b/modules/authX509/templates/X509warning.php
index 55b8b6281d7f6a2c2b86fed832aaad509a76a923..a25385ec9a97772712c0d962d28ba87f82089ee6 100644
--- a/modules/authX509/templates/X509warning.php
+++ b/modules/authX509/templates/X509warning.php
@@ -10,16 +10,16 @@
  * @package SimpleSAMLphp
  */
 
-$warning = $this->t('{authX509:X509warning:warning}', array(
-    '%days%' => htmlspecialchars($this->data['daysleft']),
-));
+$warning = $this->t('{authX509:X509warning:warning}', [
+    '%daysleft%' => htmlspecialchars($this->data['daysleft']),
+]);
 
-if( $this->data['renewurl']) {
-    $warning .= " " . $this->t('{authX509:X509warning:renew_url}', array(
+if ($this->data['renewurl']) {
+    $warning .= " ".$this->t('{authX509:X509warning:renew_url}', [
         '%renewurl%' => $this->data['renewurl'],
-    ));
+        ]);
 } else {
-    $warning .= " " . $this->t('{authX509:X509warning:renew}');
+    $warning .= " ".$this->t('{authX509:X509warning:renew}');
 }
 
 $this->data['header'] = $this->t('{authX509:X509warning:warning_header}');
@@ -32,10 +32,10 @@ $this->includeAtTemplateBase('includes/header.php');
 <form style="display: inline; margin: 0px; padding: 0px" action="<?php echo htmlspecialchars($this->data['target']); ?>">
 
     <?php
-        // Embed hidden fields...
-        foreach ($this->data['data'] as $name => $value) {
-            echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
-        }
+    // Embed hidden fields...
+    foreach ($this->data['data'] as $name => $value) {
+        echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
+    }
     ?>
     <p><?php echo $warning; ?></p>
 
diff --git a/modules/authX509/templates/X509warning.twig b/modules/authX509/templates/X509warning.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b75f7c370fd773ef4c52aa0a26114e7f5cb8893d
--- /dev/null
+++ b/modules/authX509/templates/X509warning.twig
@@ -0,0 +1,24 @@
+{% extends "base.twig" %}
+
+{% block content %}
+
+<h2>{% trans 'Your certificate is about to expire.' %}</h2>
+<form action="{{ target | escape }}">
+
+    {% for name, value in data -%}
+    <input type="hidden" name="{{ name }}" value="{{ value }}">
+    {%- endfor %}
+
+    <p>{% trans %}Your certificate will expire in {{ daysleft }} days.{% endtrans %}</p>
+
+    {% if renewurl -%}
+    <p>{% trans %}Please <a href="{{ renewurl }}">renew your certificate</a> in time.{% endtrans %}</p>
+    {% else -%}
+    <p>{% trans 'Please renew your certificate in time.' %}</p>
+    {% endif -%}
+
+    <p><input type="submit" name="proceed" id="proceedbutton" value="{% trans 'Proceed' %}" autofocus></p>
+
+</form>
+
+{% endblock %}
diff --git a/modules/authX509/www/expirywarning.php b/modules/authX509/www/expirywarning.php
index be6e4f664af3bbc1823947dc54b14cd6fbe0d5da..7bd36030d44a399fb59d510220078311d564d0a3 100644
--- a/modules/authX509/www/expirywarning.php
+++ b/modules/authX509/www/expirywarning.php
@@ -6,26 +6,26 @@
  * @package SimpleSAMLphp
  */
 
-SimpleSAML\Logger::info('AuthX509 - Showing expiry warning to user');
+\SimpleSAML\Logger::info('AuthX509 - Showing expiry warning to user');
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-    throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'warning:expire');
+$state = \SimpleSAML\Auth\State::loadState($id, 'warning:expire');
 
 
 if (array_key_exists('proceed', $_REQUEST)) {
     // The user has pressed the proceed-button
-    SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+    \SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'authX509:X509warning.php');
-$t->data['target'] = SimpleSAML\Module::getModuleURL('authX509/expirywarning.php');
-$t->data['data'] = array('StateId' => $id);
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'authX509:X509warning.php');
+$t->data['target'] = \SimpleSAML\Module::getModuleURL('authX509/expirywarning.php');
+$t->data['data'] = ['StateId' => $id];
 $t->data['daysleft'] = $state['daysleft'];
 $t->data['renewurl'] = $state['renewurl'];
-$t->data['errorcodes'] = SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
+$t->data['errorcodes'] = \SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
 $t->show();
diff --git a/modules/authYubiKey/lib/Auth/Process/OTP2YubiPrefix.php b/modules/authYubiKey/lib/Auth/Process/OTP2YubiPrefix.php
index 1c37c8c03fd2527705ed7500af698b65949daf51..42ef300f39b3c68bdbb23e1a1ae7a89620e707ef 100644
--- a/modules/authYubiKey/lib/Auth/Process/OTP2YubiPrefix.php
+++ b/modules/authYubiKey/lib/Auth/Process/OTP2YubiPrefix.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authYubiKey\Auth\Process;
+
 /*
  * Copyright (C) 2009  Simon Josefsson <simon@yubico.com>.
  *
@@ -35,42 +37,44 @@
  *
  * You use it by adding it as an authentication filter in config.php:
  *
- * 	'authproc.idp' => array(
+ *      'authproc.idp' => array(
  *    ...
  *          90 => 'authYubiKey:OTP2YubiPrefix',
  *    ...
  *      );
  *
  */
-class sspmod_authYubiKey_Auth_Process_OTP2YubiPrefix extends SimpleSAML_Auth_ProcessingFilter {
-
-
-	/**
-	 * Filter out YubiKey 'otp' attribute and replace it with
-         * a 'yubiPrefix' attribute that leaves out the dynamic part.
-	 *
-	 * @param array &$state  The state we should update.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-		assert(array_key_exists('Attributes', $state));
-		$attributes = $state['Attributes'];
 
-		SimpleSAML\Logger::debug('OTP2YubiPrefix: enter with attributes: ' . implode(',', array_keys($attributes)));
+class OTP2YubiPrefix extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Filter out YubiKey 'otp' attribute and replace it with
+     * a 'yubiPrefix' attribute that leaves out the dynamic part.
+     *
+     * @param array &$state  The state we should update.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+        assert(array_key_exists('Attributes', $state));
+        $attributes = $state['Attributes'];
 
-		$otps = $attributes['otp'];
-		$otp = $otps['0'];
+        \SimpleSAML\Logger::debug('OTP2YubiPrefix: enter with attributes: '.implode(',', array_keys($attributes)));
 
-		$token_size = 32;
-		$identity = substr ($otp, 0, strlen ($otp) - $token_size);
+        $otps = $attributes['otp'];
+        $otp = $otps['0'];
 
-		$attributes['yubiPrefix'] = array($identity);
+        $token_size = 32;
+        $identity = substr($otp, 0, strlen($otp) - $token_size);
 
-		SimpleSAML\Logger::info('OTP2YubiPrefix: otp: ' . $otp . ' identity: ' . $identity . ' (otp keys: ' . implode(',', array_keys($otps)) . ')');
+        $attributes['yubiPrefix'] = [$identity];
 
-		unset($attributes['otp']);
+        \SimpleSAML\Logger::info(
+            'OTP2YubiPrefix: otp: '.$otp.' identity: '.$identity.' (otp keys: '.implode(',', array_keys($otps)).')'
+        );
 
-		SimpleSAML\Logger::debug('OTP2YubiPrefix: leaving with attributes: ' . implode(',', array_keys($attributes)));
-	}
+        unset($attributes['otp']);
 
+        \SimpleSAML\Logger::debug('OTP2YubiPrefix: leaving with attributes: '.implode(',', array_keys($attributes)));
+    }
 }
diff --git a/modules/authYubiKey/lib/Auth/Source/YubiKey.php b/modules/authYubiKey/lib/Auth/Source/YubiKey.php
index 2d19aa507d2e0d52b675c254a01f37d0593e774e..65ddf84906d3de16f15fc0f04efc73100fe2cb0e 100644
--- a/modules/authYubiKey/lib/Auth/Source/YubiKey.php
+++ b/modules/authYubiKey/lib/Auth/Source/YubiKey.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authYubiKey\Auth\Source;
+
 /*
  * Copyright (C) 2009  Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * Copyright (C) 2009  Simon Josefsson <simon@yubico.com>.
@@ -25,14 +27,14 @@
 
 /**
  * YubiKey authentication module, see http://www.yubico.com/developers/intro/
- * *
+ *
  * Configure it by adding an entry to config/authsources.php such as this:
  *
- *	'yubikey' => array(
- *	    'authYubiKey:YubiKey',
- *	    'id' => 997,
- *	    'key' => 'b64hmackey',
- *	),
+ *    'yubikey' => array(
+ *        'authYubiKey:YubiKey',
+ *        'id' => 997,
+ *        'key' => 'b64hmackey',
+ *    ),
  *
  * To generate your own client id/key you will need one YubiKey, and then
  * go to http://yubico.com/developers/api/
@@ -40,12 +42,12 @@
  * @package SimpleSAMLphp
  */
 
-class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
+class YubiKey extends \SimpleSAML\Auth\Source
 {
     /**
      * The string used to identify our states.
      */
-    const STAGEID = 'sspmod_authYubiKey_Auth_Source_YubiKey.state';
+    const STAGEID = '\SimpleSAML\Module\authYubiKey\Auth\Source\YubiKey.state';
 
     /**
      * The number of characters of the OTP that is the secure token.
@@ -56,7 +58,7 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
     /**
      * The key of the AuthId field in the state.
      */
-    const AUTHID = 'sspmod_authYubiKey_Auth_Source_YubiKey.AuthId';
+    const AUTHID = '\SimpleSAML\Module\authYubiKey\Auth\Source\YubiKey.AuthId';
 
     /**
      * The client id/key for use with the Auth_Yubico PHP module.
@@ -103,9 +105,9 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
         // We are going to need the authId in order to retrieve this authentication source later
         $state[self::AUTHID] = $this->authId;
 
-        $id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
-        $url = SimpleSAML\Module::getModuleURL('authYubiKey/yubikeylogin.php');
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('AuthState' => $id));
+        $id = \SimpleSAML\Auth\State::saveState($state, self::STAGEID);
+        $url = \SimpleSAML\Module::getModuleURL('authYubiKey/yubikeylogin.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['AuthState' => $id]);
     }
 
 
@@ -119,7 +121,7 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
      *
      * @param string $authStateId  The identifier of the authentication state.
      * @param string $otp  The one time password entered-
-     * @return string  Error code in the case of an error.
+     * @return string|null  Error code in the case of an error.
      */
     public static function handleLogin($authStateId, $otp)
     {
@@ -127,19 +129,19 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
         assert(is_string($otp));
 
         /* Retrieve the authentication state. */
-        $state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
+        $state = \SimpleSAML\Auth\State::loadState($authStateId, self::STAGEID);
 
         /* Find authentication source. */
         assert(array_key_exists(self::AUTHID, $state));
-        $source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
+        $source = \SimpleSAML\Auth\Source::getById($state[self::AUTHID]);
         if ($source === null) {
-            throw new Exception('Could not find authentication source with id '.$state[self::AUTHID]);
+            throw new \Exception('Could not find authentication source with id '.$state[self::AUTHID]);
         }
 
         try {
             /* Attempt to log in. */
             $attributes = $source->login($otp);
-        } catch (SimpleSAML_Error_Error $e) {
+        } catch (\SimpleSAML\Error\Error $e) {
             /* An error occurred during login. Check if it is because of the wrong
              * username/password - if it is, we pass that error up to the login form,
              * if not, we let the generic error handler deal with it.
@@ -155,7 +157,9 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
         }
 
         $state['Attributes'] = $attributes;
-        SimpleSAML_Auth_Source::completeAuth($state);
+        \SimpleSAML\Auth\Source::completeAuth($state);
+
+        return null;
     }
 
     /**
@@ -163,7 +167,7 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
      */
     public static function getYubiKeyPrefix($otp)
     {
-        $uid = substr($otp, 0, strlen ($otp) - self::TOKENSIZE);
+        $uid = substr($otp, 0, strlen($otp) - self::TOKENSIZE);
         return $uid;
     }
 
@@ -172,7 +176,7 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
      *
      * On a successful login, this function should return the users attributes. On failure,
      * it should throw an exception. If the error was caused by the user entering the wrong
-     * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
      *
      * Note that both the username and the password are UTF-8 encoded.
      *
@@ -186,16 +190,20 @@ class sspmod_authYubiKey_Auth_Source_YubiKey extends SimpleSAML_Auth_Source
         require_once dirname(dirname(dirname(dirname(__FILE__)))).'/libextinc/Yubico.php';
 
         try {
-            $yubi = new Auth_Yubico($this->yubi_id, $this->yubi_key);
+            $yubi = new \Auth_Yubico($this->yubi_id, $this->yubi_key);
             $yubi->verify($otp);
             $uid = self::getYubiKeyPrefix($otp);
-            $attributes = array('uid' => array($uid));
-        } catch (Exception $e) {
-            SimpleSAML\Logger::info('YubiKey:'.$this->authId.': Validation error (otp '.$otp.'), debug output: '.$yubi->getLastResponse());
-            throw new SimpleSAML_Error_Error('WRONGUSERPASS', $e);
+            $attributes = ['uid' => [$uid]];
+        } catch (\Exception $e) {
+            \SimpleSAML\Logger::info(
+                'YubiKey:'.$this->authId.': Validation error (otp '.$otp.'), debug output: '.$yubi->getLastResponse()
+            );
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS', $e);
         }
 
-        SimpleSAML\Logger::info('YubiKey:'.$this->authId.': YubiKey otp '.$otp.' validated successfully: '.$yubi->getLastResponse());
+        \SimpleSAML\Logger::info(
+            'YubiKey:'.$this->authId.': YubiKey otp '.$otp.' validated successfully: '.$yubi->getLastResponse()
+        );
         return $attributes;
     }
 }
diff --git a/modules/authYubiKey/libextinc/Yubico.php b/modules/authYubiKey/libextinc/Yubico.php
index ca7f2690c9da0def07a2d4fa5b22eda5e9510db4..d6f4c709aafe84ea19f5ff1a6724a8b322d49c59 100644
--- a/modules/authYubiKey/libextinc/Yubico.php
+++ b/modules/authYubiKey/libextinc/Yubico.php
@@ -1,44 +1,44 @@
 <?php
-  /**
-   * Class for verifying Yubico One-Time-Passcodes
-   *
-   * LICENSE:
-   *
-   * Copyright (c) 2007, 2008  Simon Josefsson.  All rights reserved.
-   *
-   * Redistribution and use in source and binary forms, with or without
-   * modification, are permitted provided that the following conditions
-   * are met:
-   *
-   * o Redistributions of source code must retain the above copyright
-   *   notice, this list of conditions and the following disclaimer.
-   * o Redistributions in binary form must reproduce the above copyright
-   *   notice, this list of conditions and the following disclaimer in the
-   *   documentation and/or other materials provided with the distribution.
-   * o The names of the authors may not be used to endorse or promote
-   *   products derived from this software without specific prior written
-   *   permission.
-   *
-   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-   *
-   * @category    Auth
-   * @package     Auth_Yubico
-   * @author      Simon Josefsson <simon@yubico.com>
-   * @copyright   2008 Simon Josefsson
-   * @license     http://opensource.org/licenses/bsd-license.php New BSD License
-   * @version     CVS: $Id: Yubico.php,v 1.7 2007-10-22 12:56:14 jas Exp $
-   * @link        http://yubico.com/
-   */
+/**
+ * Class for verifying Yubico One-Time-Passcodes
+ *
+ * LICENSE:
+ *
+ * Copyright (c) 2007, 2008  Simon Josefsson.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * o Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * o The names of the authors may not be used to endorse or promote
+ *   products derived from this software without specific prior written
+ *   permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @category    Auth
+ * @package     Auth_Yubico
+ * @author      Simon Josefsson <simon@yubico.com>
+ * @copyright   2008 Simon Josefsson
+ * @license     http://opensource.org/licenses/bsd-license.php New BSD License
+ * @version     CVS: $Id: Yubico.php,v 1.7 2007-10-22 12:56:14 jas Exp $
+ * @link        http://yubico.com/
+ */
 
 /**
  * Class for verifying Yubico One-Time-Passcodes
@@ -58,104 +58,104 @@
  */
 class Auth_Yubico
 {
-	/**#@+
-	 * @access private
-	 */
-
-	/**
-	 * Yubico client ID
-	 * @var string
-	 */
-	private $_id;
-
-	/**
-	 * Yubico client key
-	 * @var string
-	 */
-	private $_key;
-
-	/**
-	 * Response from server
-	 * @var string
-	 */
-	private $_response;
-
-	/**
-	 * Constructor
-	 *
-	 * Sets up the object
-	 * @param    string  The client identity
-	 * @param    string  The client MAC key (optional)
-	 * @access public
-	 */
-	public function __construct($id, $key = '')
-	{
-		$this->_id =  $id;
-		$this->_key = base64_decode($key);
-	}
-
-	/**
-	 * Return the last data received from the server, if any.
-	 *
-	 * @return string		Output from server.
-	 * @access public
-	 */
-	public function getLastResponse()
-	{
-		return $this->_response;
-	}
-
-	// TODO? Add functions to get parsed parts of server response?
-
-	/**
-	 * Verify Yubico OTP
-	 *
-	 * @param string $token     Yubico OTP
-	 * @return mixed            PEAR error on error, true otherwise
-	 * @access public
-	 */
-	public function verify($token)
-	{
-		$parameters = "id=" . $this->_id . "&otp=" . $token;
-		// Generate signature
-		if ($this->_key <> "") {
-			$signature = base64_encode(hash_hmac('sha1', $parameters, $this->_key, true));
-			$parameters .= '&h=' . $signature;
-		}
-		/* Support https. */
-		$url = "https://api.yubico.com/wsapi/verify?" . $parameters;
-
-		$responseMsg = \SimpleSAML\Utils\HTTP::fetch($url);
-		
-		if (!preg_match("/status=([a-zA-Z0-9_]+)/", $responseMsg, $out)) {
-			throw new Exception('Could not parse response');
-		}
-
-		$status = $out[1];
-		
-		/* Verify signature. */
-		if ($this->_key <> "") {
-			$rows = explode("\r\n", $responseMsg);
-            $response = array();
-			while (list(, $val) = each($rows)) {
-				// = is also used in BASE64 encoding so we only replace the first = by # which is not used in BASE64
-				$val = preg_replace('/=/', '#', $val, 1);
-				$row = explode("#", $val);
-				$response[$row[0]] = (isset($row[1])) ? $row[1] : "";
-			}
-
-			$check = 'status=' . $response['status'] . '&t='. $response['t'];
-			$checksignature = base64_encode(hash_hmac('sha1', $check, $this->_key, true));
-			
-			if ($response['h'] != $checksignature) {
-				throw new Exception('Checked Signature failed');
-			}
-		}
-		
-		if ($status != 'OK') {
-			throw new Exception('Status was not OK: ' . $status);
-		}
-
-		return true;
-	}
+    /**#@+
+     * @access private
+     */
+
+    /**
+     * Yubico client ID
+     * @var string
+     */
+    private $id;
+
+    /**
+     * Yubico client key
+     * @var string
+     */
+    private $key;
+
+    /**
+     * Response from server
+     * @var string
+     */
+    private $response;
+
+    /**
+     * Constructor
+     *
+     * Sets up the object
+     * @param string $id    The client identity
+     * @param string $key   The client MAC key (optional)
+     * @access public
+     */
+    public function __construct($id, $key = '')
+    {
+        $this->id = $id;
+        $this->key = base64_decode($key);
+    }
+
+    /**
+     * Return the last data received from the server, if any.
+     *
+     * @return string Output from server.
+     * @access public
+     */
+    public function getLastResponse()
+    {
+        return $this->response;
+    }
+
+    // TODO? Add functions to get parsed parts of server response?
+
+    /**
+     * Verify Yubico OTP
+     *
+     * @param string $token     Yubico OTP
+     * @return mixed            PEAR error on error, true otherwise
+     * @access public
+     */
+    public function verify($token)
+    {
+        $parameters = "id=".$this->id."&otp=".$token;
+        // Generate signature
+        if ($this->key <> "") {
+            $signature = base64_encode(hash_hmac('sha1', $parameters, $this->key, true));
+            $parameters .= '&h='.$signature;
+        }
+        // Support https
+        $url = "https://api.yubico.com/wsapi/verify?".$parameters;
+
+        $responseMsg = \SimpleSAML\Utils\HTTP::fetch($url);
+
+        if (!preg_match("/status=([a-zA-Z0-9_]+)/", $responseMsg, $out)) {
+            throw new Exception('Could not parse response');
+        }
+
+        $status = $out[1];
+
+        // Verify signature
+        if ($this->key <> "") {
+            $rows = explode("\r\n", $responseMsg);
+            $response = [];
+            foreach ($rows as $val) {
+                // = is also used in BASE64 encoding so we only replace the first = by # which is not used in BASE64
+                $val = preg_replace('/=/', '#', $val, 1);
+                $row = explode("#", $val);
+                $response[$row[0]] = (isset($row[1])) ? $row[1] : "";
+            }
+
+            $check = 'status='.$response['status'].'&t='.$response['t'];
+            $checksignature = base64_encode(hash_hmac('sha1', $check, $this->key, true));
+
+            if ($response['h'] != $checksignature) {
+                throw new Exception('Checked Signature failed');
+            }
+        }
+
+        if ($status != 'OK') {
+            throw new Exception('Status was not OK: '.$status);
+        }
+
+        return true;
+    }
 }
diff --git a/modules/authYubiKey/templates/yubikeylogin.php b/modules/authYubiKey/templates/yubikeylogin.php
index 0c9f3e48e31475a9cd202a1bb7973d0695f99d73..693e4c374c60eda7fa69608daef796e1a0f19927 100644
--- a/modules/authYubiKey/templates/yubikeylogin.php
+++ b/modules/authYubiKey/templates/yubikeylogin.php
@@ -1,47 +1,35 @@
 <?php
-$this->data['header'] = $this->t('{authYubiKey:yubikey:header}');
-$this->data['autofocus'] = 'otp';
 
 $this->includeAtTemplateBase('includes/header.php');
 
+if ($this->data['errorCode'] !== null) {
 ?>
-
-<?php
-if ($this->data['errorcode'] !== NULL) {
-?>
-	<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
-		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l" style="margin: 15px" alt="" />
-		<h2><?php echo $this->t('{login:error_header}'); ?></h2>
-		<p><b><?php echo $this->t($this->data['errorcodes']['title'][$this->data['errorcode']]); ?></b></p>
-		<p><?php echo $this->t($this->data['errorcodes']['descr'][$this->data['errorcode']]); ?></p>
-	</div>
+    <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+        <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l" style="margin: 15px" alt="" />
+        <h2><?php echo $this->t('{login:error_header}'); ?></h2>
+        <p><b><?php echo $this->t($this->data['errorcodes']['title'][$this->data['errorcode']]); ?></b></p>
+        <p><?php echo $this->t($this->data['errorcodes']['descr'][$this->data['errorcode']]); ?></p>
+    </div>
 <?php
 }
 ?>
+    <img style="float: right" src="<?php echo($this->data['logoUrl']); ?>" alt="" />
+    <img style="clear: right; float: right" src="<?php echo($this->data['devicepicUrl']); ?>" alt="YubiKey" />
 
-	<img style="float: right" src="<?php echo($this->data['logo_url']); ?>" alt="" />
-	<img style="clear: right; float: right" src="<?php echo($this->data['devicepic_url']); ?>" alt="YubiKey" />
-
-
-	<h2 style=""><?php echo $this->t('{authYubiKey:yubikey:header}'); ?></h2>
-
-	<form action="?" method="post" name="f">
-
-		<p><?php echo $this->t('{authYubiKey:yubikey:intro}'); ?></p>
-	
-		<p><input id="otp" style="border: 1px solid #ccc; background: #eee; padding: .5em; font-size: medium; width: 70%; color: #aaa" type="text" tabindex="2" name="otp" /></p>
+    <h2 style=""><?php echo $this->data['header']; ?></h2>
 
+    <form action="?" method="post" name="f">
 
+        <p><?php echo $this->t('{authYubiKey:yubikey:intro}'); ?></p>
 
+        <p><input id="otp" style="border: 1px solid #ccc; background: #eee; padding: .5em; font-size: medium; width: 70%; color: #aaa" type="text" tabindex="2" name="otp" /></p>
 
 <?php
-foreach ($this->data['stateparams'] as $name => $value) {
-	echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
+foreach ($this->data['stateParams'] as $name => $value) {
+    echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
 }
 ?>
-
-	</form>
-
+    </form>
 <?php
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/authYubiKey/templates/yubikeylogin.twig b/modules/authYubiKey/templates/yubikeylogin.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e01432c0103afe8eb9b5ab9e94de38f97e366f51
--- /dev/null
+++ b/modules/authYubiKey/templates/yubikeylogin.twig
@@ -0,0 +1,33 @@
+{% set pagetitle = header|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link rel="stylesheet" type="text/css" href="{{ baseurlpath }}assets/css/yubikey.css">
+{% endblock %}
+
+{% block postload %}
+    <script src="{{ baseurlpath }}assets/js/autofocus.js"></script>
+{% endblock %}
+
+{% block content %}
+    {% if errorCode != null %}
+    <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+        <img src="/{{ baseurlpath }}resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l" style="margin: 15px;" alt="">
+        <h2>{{ '{login:error_header}'|trans }}</h2>
+        <p><span style="text-decoration: bold;">{{ errorTitle }}</p>
+        <p>{{ errorDesc }}</p>
+    </div>
+    {% endif %}
+
+    <img style="float: right" src="{{ logoUrl }}" alt="">
+    <img style="clear: right; float: right" src="{{ devicepicUrl }}" alt="YubiKey">
+
+    <h2>{{ '{authYubiKey:yubikey:header}'|trans }}</h2>
+    <form action="?" method="post" name="f">
+        <p>{{ '{authYubiKey:yubikey:intro}'|trans }}</p>
+        <p><input id="otp" type="text" tabindex="2" name="otp" autofocus></p>
+    {% for key, value in stateParams %}
+        <input type="hidden" name="{{ key|escape('html') }}" value="{{ value|escape('html') }}">
+    {% endfor %}
+    </form>
+{% endblock %}
diff --git a/modules/authYubiKey/www/assets/css/yubikey.css b/modules/authYubiKey/www/assets/css/yubikey.css
new file mode 100644
index 0000000000000000000000000000000000000000..6b033d025270a659f6cd6d1c107123b6451e6695
--- /dev/null
+++ b/modules/authYubiKey/www/assets/css/yubikey.css
@@ -0,0 +1,7 @@
+input#otp {
+    border: 1px solid #ccc;
+    background: #eee; padding: .5em;
+    font-size: medium;
+    width: 70%;
+    color: #aaa;
+}
diff --git a/modules/authYubiKey/www/assets/js/autofocus.js b/modules/authYubiKey/www/assets/js/autofocus.js
new file mode 100644
index 0000000000000000000000000000000000000000..c846eb302d48da7e138035f5998d761a70dbb42b
--- /dev/null
+++ b/modules/authYubiKey/www/assets/js/autofocus.js
@@ -0,0 +1 @@
+SimpleSAML_focus('otp');
diff --git a/modules/authYubiKey/www/resources/logo.jpg b/modules/authYubiKey/www/resources/logo.jpg
index 3b7e7f360ddb176fd383a8bea0d6b500fff95cf5..e2fded1a931f2d0ad604be69c7722002f9bb71fe 100644
Binary files a/modules/authYubiKey/www/resources/logo.jpg and b/modules/authYubiKey/www/resources/logo.jpg differ
diff --git a/modules/authYubiKey/www/yubikeylogin.php b/modules/authYubiKey/www/yubikeylogin.php
index 1d0c7597adf31d8400c9b4cb1e2582e2f07290e9..c484282515376306d2f2ea7b28cd52c3fed4d0c1 100644
--- a/modules/authYubiKey/www/yubikeylogin.php
+++ b/modules/authYubiKey/www/yubikeylogin.php
@@ -2,7 +2,7 @@
 
 /**
  * This page shows a username/password login form, and passes information from it
- * to the sspmod_core_Auth_UserPassBase class, which is a generic class for
+ * to the \SimpleSAML\Module\core\Auth\UserPassBase class, which is a generic class for
  * username/password authentication.
  *
  * @author Olav Morken, UNINETT AS.
@@ -10,29 +10,27 @@
  */
 
 if (!array_key_exists('AuthState', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthState parameter.');
 }
 $authStateId = $_REQUEST['AuthState'];
 
-if (array_key_exists('otp', $_REQUEST)) {
-	$otp = $_REQUEST['otp'];
-} else {
-	$otp = '';
-}
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'authYubiKey:yubikeylogin.php');
+$translator = $t->getTranslator();
 
-if (!empty($otp)) {
-	// attempt to log in
-	$errorCode = sspmod_authYubiKey_Auth_Source_YubiKey::handleLogin($authStateId, $otp);
-} else {
-	$errorCode = NULL;
+$errorCode = null;
+if (array_key_exists('otp', $_REQUEST)) {
+    // attempt to log in
+    $errorCode = \SimpleSAML\Module\authYubiKey\Auth\Source\YubiKey::handleLogin($authStateId, $_REQUEST['otp']);
+    $errorCodes = \SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
+    $t->data['errorTitle'] = $errorCodes['title'][$errorCode];
+    $t->data['errorDesc'] = $errorCodes['desc'][$errorCode];
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'authYubiKey:yubikeylogin.php');
-$t->data['stateparams'] = array('AuthState' => $authStateId);
-$t->data['errorcode'] = $errorCode;
-$t->data['errorcodes'] = SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
-$t->data['logo_url'] = SimpleSAML\Module::getModuleURL('authYubiKey/resources/logo.jpg');
-$t->data['devicepic_url'] = SimpleSAML\Module::getModuleURL('authYubiKey/resources/yubikey.jpg');
+$t->data['header'] = $translator->t('{authYubiKey:yubikey:header}');
+$t->data['autofocus'] = 'otp';
+$t->data['errorCode'] = $errorCode;
+$t->data['stateParams'] = ['AuthState' => $authStateId];
+$t->data['logoUrl'] = \SimpleSAML\Module::getModuleURL('authYubiKey/resources/logo.jpg');
+$t->data['devicepicUrl'] = \SimpleSAML\Module::getModuleURL('authYubiKey/resources/yubikey.jpg');
 $t->show();
-exit();
diff --git a/modules/authcrypt/lib/Auth/Source/Hash.php b/modules/authcrypt/lib/Auth/Source/Hash.php
index 1aca115745fddf89ddbfb2d4951cc8b827021594..aa17adcf68849033f114df0bf76b02e24295d6b0 100644
--- a/modules/authcrypt/lib/Auth/Source/Hash.php
+++ b/modules/authcrypt/lib/Auth/Source/Hash.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Module\authcrypt\Auth\Source;
 
 /**
  * Authentication source for username & hashed password.
@@ -10,10 +11,9 @@
  * @author Dyonisius Visser, TERENA.
  * @package SimpleSAMLphp
  */
-class sspmod_authcrypt_Auth_Source_Hash extends sspmod_core_Auth_UserPassBase
-{
-
 
+class Hash extends \SimpleSAML\Module\core\Auth\UserPassBase
+{
     /**
      * Our users, stored in an associative array. The key of the array is "<username>:<passwordhash>",
      * while the value of each element is a new array with the attributes for each user.
@@ -37,27 +37,27 @@ class sspmod_authcrypt_Auth_Source_Hash extends sspmod_core_Auth_UserPassBase
         // Call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        $this->users = array();
+        $this->users = [];
 
         // Validate and parse our configuration
         foreach ($config as $userpass => $attributes) {
             if (!is_string($userpass)) {
-                throw new Exception('Invalid <username>:<passwordhash> for authentication source '.
+                throw new \Exception('Invalid <username>:<passwordhash> for authentication source '.
                     $this->authId.': '.$userpass);
             }
 
             $userpass = explode(':', $userpass, 2);
             if (count($userpass) !== 2) {
-                throw new Exception('Invalid <username>:<passwordhash> for authentication source '.
+                throw new \Exception('Invalid <username>:<passwordhash> for authentication source '.
                     $this->authId.': '.$userpass[0]);
             }
             $username = $userpass[0];
             $passwordhash = $userpass[1];
 
             try {
-                $attributes = SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
-            } catch (Exception $e) {
-                throw new Exception('Invalid attributes for user '.$username.
+                $attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
+            } catch (\Exception $e) {
+                throw new \Exception('Invalid attributes for user '.$username.
                     ' in authentication source '.$this->authId.': '.
                     $e->getMessage());
             }
@@ -72,7 +72,7 @@ class sspmod_authcrypt_Auth_Source_Hash extends sspmod_core_Auth_UserPassBase
      *
      * On a successful login, this function should return the users attributes. On failure,
      * it should throw an exception. If the error was caused by the user entering the wrong
-     * username OR password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
+     * username OR password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
      *
      * The username is UTF-8 encoded, and the hash is base64 encoded.
      *
@@ -81,7 +81,7 @@ class sspmod_authcrypt_Auth_Source_Hash extends sspmod_core_Auth_UserPassBase
      *
      * @return array  Associative array with the users attributes.
      *
-     * @throws SimpleSAML_Error_Error if authentication fails.
+     * @throws \SimpleSAML\Error\Error if authentication fails.
      */
     protected function login($username, $password)
     {
@@ -91,13 +91,13 @@ class sspmod_authcrypt_Auth_Source_Hash extends sspmod_core_Auth_UserPassBase
         foreach ($this->users as $userpass => $attrs) {
             $matches = explode(':', $userpass, 2);
             if ($matches[0] === $username) {
-                if (SimpleSAML\Utils\Crypto::pwValid($matches[1], $password)) {
+                if (\SimpleSAML\Utils\Crypto::pwValid($matches[1], $password)) {
                     return $attrs;
                 } else {
-                    SimpleSAML\Logger::debug('Incorrect password "'.$password.'" for user '.$username);
+                    \SimpleSAML\Logger::debug('Incorrect password "'.$password.'" for user '.$username);
                 }
             }
         }
-        throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+        throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
     }
 }
diff --git a/modules/authcrypt/lib/Auth/Source/Htpasswd.php b/modules/authcrypt/lib/Auth/Source/Htpasswd.php
index 84bc7ea3efdd1fc0d05d2eacaab6c4e755eada19..03084b08b1a9628d3cd301e1d57ab219a5cb9933 100644
--- a/modules/authcrypt/lib/Auth/Source/Htpasswd.php
+++ b/modules/authcrypt/lib/Auth/Source/Htpasswd.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authcrypt\Auth\Source;
+
 /**
  * Authentication source for Apache 'htpasswd' files.
  *
@@ -9,10 +11,8 @@
 
 use WhiteHat101\Crypt\APR1_MD5;
 
-class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBase
+class Htpasswd extends \SimpleSAML\Module\core\Auth\UserPassBase
 {
-
-
     /**
      * Our users, stored in an array, where each value is "<username>:<passwordhash>".
      *
@@ -25,7 +25,7 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
      *
      * @var array
      */
-    private $attributes = array();
+    private $attributes = [];
 
 
     /**
@@ -44,18 +44,18 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
         // Call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        $this->users = array();
+        $this->users = [];
 
         if (!$htpasswd = file_get_contents($config['htpasswd_file'])) {
-            throw new Exception('Could not read '.$config['htpasswd_file']);
+            throw new \Exception('Could not read '.$config['htpasswd_file']);
         }
 
         $this->users = explode("\n", trim($htpasswd));
 
         try {
-            $this->attributes = SimpleSAML\Utils\Attributes::normalizeAttributesArray($config['static_attributes']);
-        } catch (Exception $e) {
-            throw new Exception('Invalid static_attributes in authentication source '.
+            $this->attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($config['static_attributes']);
+        } catch (\Exception $e) {
+            throw new \Exception('Invalid static_attributes in authentication source '.
                 $this->authId.': '.$e->getMessage());
         }
     }
@@ -66,7 +66,7 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
      *
      * On a successful login, this function should return the username as 'uid' attribute,
      * and merged attributes from the configuration file.
-     * On failure, it should throw an exception. A SimpleSAML_Error_Error('WRONGUSERPASS')
+     * On failure, it should throw an exception. A \SimpleSAML\Error\Error('WRONGUSERPASS')
      * should be thrown in case of a wrong username OR a wrong password, to prevent the
      * enumeration of usernames.
      *
@@ -75,7 +75,7 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
      *
      * @return array Associative array with the users attributes.
      *
-     * @throws SimpleSAML_Error_Error if authentication fails.
+     * @throws \SimpleSAML\Error\Error if authentication fails.
      */
     protected function login($username, $password)
     {
@@ -88,12 +88,12 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
                 $crypted = $matches[1];
 
                 // This is about the only attribute we can add
-                $attributes = array_merge(array('uid' => array($username)), $this->attributes);
+                $attributes = array_merge(['uid' => [$username]], $this->attributes);
 
                 // Traditional crypt(3)
-                if (SimpleSAML\Utils\Crypto::secureCompare($crypted, crypt($password, $crypted))) {
-                    SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
-                    SimpleSAML\Logger::warning(
+                if (\SimpleSAML\Utils\Crypto::secureCompare($crypted, crypt($password, $crypted))) {
+                    \SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
+                    \SimpleSAML\Logger::warning(
                         'CRYPT authentication is insecure. Please consider using something else.'
                     );
                     return $attributes;
@@ -101,21 +101,21 @@ class sspmod_authcrypt_Auth_Source_Htpasswd extends sspmod_core_Auth_UserPassBas
 
                 // Apache's custom MD5
                 if (APR1_MD5::check($password, $crypted)) {
-                    SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
+                    \SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
                     return $attributes;
                 }
 
                 // SHA1 or plain-text
-                if (SimpleSAML\Utils\Crypto::pwValid($crypted, $password)) {
-                    SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
-                    SimpleSAML\Logger::warning(
+                if (\SimpleSAML\Utils\Crypto::pwValid($crypted, $password)) {
+                    \SimpleSAML\Logger::debug('User '.$username.' authenticated successfully');
+                    \SimpleSAML\Logger::warning(
                         'SHA1 and PLAIN TEXT authentication are insecure. Please consider using something else.'
                     );
                     return $attributes;
                 }
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
         }
-        throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+        throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
     }
 }
diff --git a/modules/authfacebook/extlibinc/base_facebook.php b/modules/authfacebook/extlibinc/base_facebook.php
index cd4536db1a59b5b48fe8b396a78aa356b229defd..aa1a23efb24e0139820037d699d1809a0d82b509 100644
--- a/modules/authfacebook/extlibinc/base_facebook.php
+++ b/modules/authfacebook/extlibinc/base_facebook.php
@@ -16,10 +16,10 @@
  */
 
 if (!function_exists('curl_init')) {
-  throw new Exception('Facebook needs the CURL PHP extension.');
+    throw new Exception('Facebook needs the CURL PHP extension.');
 }
 if (!function_exists('json_decode')) {
-  throw new Exception('Facebook needs the JSON PHP extension.');
+    throw new Exception('Facebook needs the JSON PHP extension.');
 }
 
 /**
@@ -29,81 +29,85 @@ if (!function_exists('json_decode')) {
  */
 class FacebookApiException extends Exception
 {
-  /**
-   * The result from the API server that represents the exception information.
-   */
-  protected $result;
-
-  /**
-   * Make a new API Exception with the given result.
-   *
-   * @param array $result The result from the API server
-   */
-  public function __construct($result) {
-    $this->result = $result;
-
-    $code = isset($result['error_code']) ? $result['error_code'] : 0;
-
-    if (isset($result['error_description'])) {
-      // OAuth 2.0 Draft 10 style
-      $msg = $result['error_description'];
-    } else if (isset($result['error']) && is_array($result['error'])) {
-      // OAuth 2.0 Draft 00 style
-      $msg = $result['error']['message'];
-    } else if (isset($result['error_msg'])) {
-      // Rest server style
-      $msg = $result['error_msg'];
-    } else {
-      $msg = 'Unknown Error. Check getResult()';
+    /**
+     * The result from the API server that represents the exception information.
+     */
+    protected $result;
+
+    /**
+     * Make a new API Exception with the given result.
+     *
+     * @param array $result The result from the API server
+     */
+    public function __construct($result)
+    {
+        $this->result = $result;
+
+        $code = isset($result['error_code']) ? $result['error_code'] : 0;
+
+        if (isset($result['error_description'])) {
+            // OAuth 2.0 Draft 10 style
+            $msg = $result['error_description'];
+        } elseif (isset($result['error']) && is_array($result['error'])) {
+            // OAuth 2.0 Draft 00 style
+            $msg = $result['error']['message'];
+        } elseif (isset($result['error_msg'])) {
+            // Rest server style
+            $msg = $result['error_msg'];
+        } else {
+            $msg = 'Unknown Error. Check getResult()';
+        }
+
+        parent::__construct($msg, $code);
     }
 
-    parent::__construct($msg, $code);
-  }
-
-  /**
-   * Return the associated result object returned by the API server.
-   *
-   * @return array The result from the API server
-   */
-  public function getResult() {
-    return $this->result;
-  }
-
-  /**
-   * Returns the associated type for the error. This will default to
-   * 'Exception' when a type is not available.
-   *
-   * @return string
-   */
-  public function getType() {
-    if (isset($this->result['error'])) {
-      $error = $this->result['error'];
-      if (is_string($error)) {
-        // OAuth 2.0 Draft 10 style
-        return $error;
-      } else if (is_array($error)) {
-        // OAuth 2.0 Draft 00 style
-        if (isset($error['type'])) {
-          return $error['type'];
+    /**
+     * Return the associated result object returned by the API server.
+     *
+     * @return array The result from the API server
+     */
+    public function getResult()
+    {
+        return $this->result;
+    }
+
+    /**
+     * Returns the associated type for the error. This will default to
+     * 'Exception' when a type is not available.
+     *
+     * @return string
+     */
+    public function getType()
+    {
+        if (isset($this->result['error'])) {
+            $error = $this->result['error'];
+            if (is_string($error)) {
+                // OAuth 2.0 Draft 10 style
+                return $error;
+            } elseif (is_array($error)) {
+                // OAuth 2.0 Draft 00 style
+                if (isset($error['type'])) {
+                    return $error['type'];
+                }
+            }
         }
-      }
+
+        return 'Exception';
     }
 
-    return 'Exception';
-  }
-
-  /**
-   * To make debugging easier.
-   *
-   * @return string The string representation of the error
-   */
-  public function __toString() {
-    $str = $this->getType() . ': ';
-    if ($this->code != 0) {
-      $str .= $this->code . ': ';
+    /**
+     * To make debugging easier.
+     *
+     * @return string The string representation of the error
+     */
+    public function __toString()
+    {
+        $str = $this->getType().': ';
+        if ($this->code != 0) {
+            $str .= $this->code.': ';
+        }
+        return $str.$this->message;
     }
-    return $str . $this->message;
-  }
 }
 
 /**
@@ -117,1320 +121,1340 @@ class FacebookApiException extends Exception
  */
 abstract class BaseFacebook
 {
-  /**
-   * Version.
-   */
-  const VERSION = '3.2.2';
-
-  /**
-   * Signed Request Algorithm.
-   */
-  const SIGNED_REQUEST_ALGORITHM = 'HMAC-SHA256';
-
-  /**
-   * Default options for curl.
-   */
-  public static $CURL_OPTS = array(
-    CURLOPT_CONNECTTIMEOUT => 10,
-    CURLOPT_RETURNTRANSFER => true,
-    CURLOPT_TIMEOUT        => 60,
-    CURLOPT_USERAGENT      => 'facebook-php-3.2',
-  );
-
-  /**
-   * List of query parameters that get automatically dropped when rebuilding
-   * the current URL.
-   */
-  protected static $DROP_QUERY_PARAMS = array(
-    'code',
-    'state',
-    'signed_request',
-  );
-
-  /**
-   * Maps aliases to Facebook domains.
-   */
-  public static $DOMAIN_MAP = array(
-    'api'         => 'https://api.facebook.com/',
-    'api_video'   => 'https://api-video.facebook.com/',
-    'api_read'    => 'https://api-read.facebook.com/',
-    'graph'       => 'https://graph.facebook.com/',
-    'graph_video' => 'https://graph-video.facebook.com/',
-    'www'         => 'https://www.facebook.com/',
-  );
-
-  /**
-   * The Application ID.
-   *
-   * @var string
-   */
-  protected $appId;
-
-  /**
-   * The Application App Secret.
-   *
-   * @var string
-   */
-  protected $appSecret;
-
-  /**
-   * The ID of the Facebook user, or 0 if the user is logged out.
-   *
-   * @var integer
-   */
-  protected $user;
-
-  /**
-   * The data from the signed_request token.
-   */
-  protected $signedRequest;
-
-  /**
-   * A CSRF state variable to assist in the defense against CSRF attacks.
-   */
-  protected $state;
-
-  /**
-   * The OAuth access token received in exchange for a valid authorization
-   * code.  null means the access token has yet to be determined.
-   *
-   * @var string
-   */
-  protected $accessToken = null;
-
-  /**
-   * Indicates if the CURL based @ syntax for file uploads is enabled.
-   *
-   * @var boolean
-   */
-  protected $fileUploadSupport = false;
-
-  /**
-   * Indicates if we trust HTTP_X_FORWARDED_* headers.
-   *
-   * @var boolean
-   */
-  protected $trustForwarded = false;
-
-  /**
-   * Initialize a Facebook Application.
-   *
-   * The configuration:
-   * - appId: the application ID
-   * - secret: the application secret
-   * - fileUpload: (optional) boolean indicating if file uploads are enabled
-   *
-   * @param array $config The application configuration
-   */
-  public function __construct($config) {
-    $this->setAppId($config['appId']);
-    $this->setAppSecret($config['secret']);
-    if (isset($config['fileUpload'])) {
-      $this->setFileUploadSupport($config['fileUpload']);
+    /**
+     * Version.
+     */
+    const VERSION = '3.2.2';
+
+    /**
+     * Signed Request Algorithm.
+     */
+    const SIGNED_REQUEST_ALGORITHM = 'HMAC-SHA256';
+
+    /**
+     * Default options for curl.
+     */
+    public static $CURL_OPTS = [
+        CURLOPT_CONNECTTIMEOUT => 10,
+        CURLOPT_RETURNTRANSFER => true,
+        CURLOPT_TIMEOUT        => 60,
+        CURLOPT_USERAGENT      => 'facebook-php-3.2',
+    ];
+
+    /**
+     * Maps aliases to Facebook domains.
+     */
+    public static $DOMAIN_MAP = [
+        'api'         => 'https://api.facebook.com/',
+        'api_video'   => 'https://api-video.facebook.com/',
+        'api_read'    => 'https://api-read.facebook.com/',
+        'graph'       => 'https://graph.facebook.com/',
+        'graph_video' => 'https://graph-video.facebook.com/',
+        'www'         => 'https://www.facebook.com/',
+    ];
+
+    /**
+     * The Application ID.
+     *
+     * @var string
+     */
+    protected $appId;
+
+    /**
+     * The Application App Secret.
+     *
+     * @var string
+     */
+    protected $appSecret;
+
+    /**
+     * The ID of the Facebook user, or 0 if the user is logged out.
+     *
+     * @var integer
+     */
+    protected $user;
+
+    /**
+     * The data from the signed_request token.
+     */
+    protected $signedRequest;
+
+    /**
+     * A CSRF state variable to assist in the defense against CSRF attacks.
+     */
+    protected $state;
+
+    /**
+     * The OAuth access token received in exchange for a valid authorization
+     * code.  null means the access token has yet to be determined.
+     *
+     * @var string
+     */
+    protected $accessToken = null;
+
+    /**
+     * Indicates if the CURL based @ syntax for file uploads is enabled.
+     *
+     * @var boolean
+     */
+    protected $fileUploadSupport = false;
+
+    /**
+     * Indicates if we trust HTTP_X_FORWARDED_* headers.
+     *
+     * @var boolean
+     */
+    protected $trustForwarded = false;
+
+    /**
+     * Initialize a Facebook Application.
+     *
+     * The configuration:
+     * - appId: the application ID
+     * - secret: the application secret
+     * - fileUpload: (optional) boolean indicating if file uploads are enabled
+     *
+     * @param array $config The application configuration
+     */
+    public function __construct($config)
+    {
+        $this->setAppId($config['appId']);
+        $this->setAppSecret($config['secret']);
+        if (isset($config['fileUpload'])) {
+            $this->setFileUploadSupport($config['fileUpload']);
+        }
+        if (isset($config['trustForwarded']) && $config['trustForwarded']) {
+            $this->trustForwarded = true;
+        }
+        $state = $this->getPersistentData('state');
+        if (!empty($state)) {
+            $this->state = $state;
+        }
     }
-    if (isset($config['trustForwarded']) && $config['trustForwarded']) {
-      $this->trustForwarded = true;
+
+    /**
+     * Set the Application ID.
+     *
+     * @param string $appId The Application ID
+     * @return BaseFacebook
+     */
+    public function setAppId($appId)
+    {
+        $this->appId = $appId;
+        return $this;
     }
-    $state = $this->getPersistentData('state');
-    if (!empty($state)) {
-      $this->state = $state;
+
+    /**
+     * Get the Application ID.
+     *
+     * @return string the Application ID
+     */
+    public function getAppId()
+    {
+        return $this->appId;
     }
-  }
-
-  /**
-   * Set the Application ID.
-   *
-   * @param string $appId The Application ID
-   * @return BaseFacebook
-   */
-  public function setAppId($appId) {
-    $this->appId = $appId;
-    return $this;
-  }
-
-  /**
-   * Get the Application ID.
-   *
-   * @return string the Application ID
-   */
-  public function getAppId() {
-    return $this->appId;
-  }
-
-  /**
-   * Set the App Secret.
-   *
-   * @param string $apiSecret The App Secret
-   * @return BaseFacebook
-   * @deprecated
-   */
-  public function setApiSecret($apiSecret) {
-    $this->setAppSecret($apiSecret);
-    return $this;
-  }
-
-  /**
-   * Set the App Secret.
-   *
-   * @param string $appSecret The App Secret
-   * @return BaseFacebook
-   */
-  public function setAppSecret($appSecret) {
-    $this->appSecret = $appSecret;
-    return $this;
-  }
-
-  /**
-   * Get the App Secret.
-   *
-   * @return string the App Secret
-   * @deprecated
-   */
-  public function getApiSecret() {
-    return $this->getAppSecret();
-  }
-
-  /**
-   * Get the App Secret.
-   *
-   * @return string the App Secret
-   */
-  public function getAppSecret() {
-    return $this->appSecret;
-  }
-
-  /**
-   * Set the file upload support status.
-   *
-   * @param boolean $fileUploadSupport The file upload support status.
-   * @return BaseFacebook
-   */
-  public function setFileUploadSupport($fileUploadSupport) {
-    $this->fileUploadSupport = $fileUploadSupport;
-    return $this;
-  }
-
-  /**
-   * Get the file upload support status.
-   *
-   * @return boolean true if and only if the server supports file upload.
-   */
-  public function getFileUploadSupport() {
-    return $this->fileUploadSupport;
-  }
-
-  /**
-   * DEPRECATED! Please use getFileUploadSupport instead.
-   *
-   * Get the file upload support status.
-   *
-   * @return boolean true if and only if the server supports file upload.
-   */
-  public function useFileUploadSupport() {
-    return $this->getFileUploadSupport();
-  }
-
-  /**
-   * Sets the access token for api calls.  Use this if you get
-   * your access token by other means and just want the SDK
-   * to use it.
-   *
-   * @param string $access_token an access token.
-   * @return BaseFacebook
-   */
-  public function setAccessToken($access_token) {
-    $this->accessToken = $access_token;
-    return $this;
-  }
-
-  /**
-   * Extend an access token, while removing the short-lived token that might
-   * have been generated via client-side flow. Thanks to http://bit.ly/b0Pt0H
-   * for the workaround.
-   */
-  public function setExtendedAccessToken() {
-    try {
-      // need to circumvent json_decode by calling _oauthRequest
-      // directly, since response isn't JSON format
-      $access_token_response = $this->_oauthRequest(
-        $this->getUrl('graph', '/oauth/access_token'),
-        $params = array(
-          'client_id' => $this->getAppId(),
-          'client_secret' => $this->getAppSecret(),
-          'grant_type' => 'fb_exchange_token',
-          'fb_exchange_token' => $this->getAccessToken(),
-        )
-      );
+
+    /**
+     * Set the App Secret.
+     *
+     * @param string $apiSecret The App Secret
+     * @return BaseFacebook
+     * @deprecated
+     */
+    public function setApiSecret($apiSecret)
+    {
+        $this->setAppSecret($apiSecret);
+        return $this;
     }
-    catch (FacebookApiException $e) {
-      // most likely that user very recently revoked authorization
-      // In any event, we don't have an access token, so say so
-      return false;
+
+    /**
+     * Set the App Secret.
+     *
+     * @param string $appSecret The App Secret
+     * @return BaseFacebook
+     */
+    public function setAppSecret($appSecret)
+    {
+        $this->appSecret = $appSecret;
+        return $this;
     }
 
-    if (empty($access_token_response)) {
-      return false;
+    /**
+     * Get the App Secret.
+     *
+     * @return string the App Secret
+     * @deprecated
+     */
+    public function getApiSecret()
+    {
+        return $this->getAppSecret();
     }
 
-    $response_params = array();
-    parse_str($access_token_response, $response_params);
+    /**
+     * Get the App Secret.
+     *
+     * @return string the App Secret
+     */
+    public function getAppSecret()
+    {
+        return $this->appSecret;
+    }
 
-    if (!isset($response_params['access_token'])) {
-      return false;
+    /**
+     * Set the file upload support status.
+     *
+     * @param boolean $fileUploadSupport The file upload support status.
+     * @return BaseFacebook
+     */
+    public function setFileUploadSupport($fileUploadSupport)
+    {
+        $this->fileUploadSupport = $fileUploadSupport;
+        return $this;
     }
 
-    $this->destroySession();
-
-    $this->setPersistentData(
-      'access_token', $response_params['access_token']
-    );
-  }
-
-  /**
-   * Determines the access token that should be used for API calls.
-   * The first time this is called, $this->accessToken is set equal
-   * to either a valid user access token, or it's set to the application
-   * access token if a valid user access token wasn't available.  Subsequent
-   * calls return whatever the first call returned.
-   *
-   * @return string The access token
-   */
-  public function getAccessToken() {
-    if ($this->accessToken !== null) {
-      // we've done this already and cached it.  Just return.
-      return $this->accessToken;
+    /**
+     * Get the file upload support status.
+     *
+     * @return boolean true if and only if the server supports file upload.
+     */
+    public function getFileUploadSupport()
+    {
+        return $this->fileUploadSupport;
     }
 
-    // first establish access token to be the application
-    // access token, in case we navigate to the /oauth/access_token
-    // endpoint, where SOME access token is required
-    $this->setAccessToken($this->getApplicationAccessToken());
-    $user_access_token = $this->getUserAccessToken();
-    if ($user_access_token) {
-      $this->setAccessToken($user_access_token);
+    /**
+     * DEPRECATED! Please use getFileUploadSupport instead.
+     *
+     * Get the file upload support status.
+     *
+     * @return boolean true if and only if the server supports file upload.
+     */
+    public function useFileUploadSupport()
+    {
+        return $this->getFileUploadSupport();
     }
 
-    return $this->accessToken;
-  }
-
-  /**
-   * Determines and returns the user access token, first using
-   * the signed request if present, and then falling back on
-   * the authorization code if present.  The intent is to
-   * return a valid user access token, or false if one is determined
-   * to not be available.
-   *
-   * @return string A valid user access token, or false if one
-   *                could not be determined.
-   */
-  protected function getUserAccessToken() {
-    // first, consider a signed request if it's supplied
-    // if there is a signed request, then it alone determines
-    // the access token
-    $signed_request = $this->getSignedRequest();
-    if ($signed_request) {
-      // apps.facebook.com hands the access_token in the signed_request
-      if (array_key_exists('oauth_token', $signed_request)) {
-        $access_token = $signed_request['oauth_token'];
-        $this->setPersistentData('access_token', $access_token);
-        return $access_token;
-      }
-
-      // the JS SDK puts a code in with the redirect_uri of ''
-      if (array_key_exists('code', $signed_request)) {
-        $code = $signed_request['code'];
-        if ($code && $code == $this->getPersistentData('code')) {
-          // short-circuit if the code we have is the same as the one presented
-          return $this->getPersistentData('access_token');
+    /**
+     * Sets the access token for api calls.  Use this if you get
+     * your access token by other means and just want the SDK
+     * to use it.
+     *
+     * @param string $access_token an access token.
+     * @return BaseFacebook
+     */
+    public function setAccessToken($access_token)
+    {
+        $this->accessToken = $access_token;
+        return $this;
+    }
+
+    /**
+     * Extend an access token, while removing the short-lived token that might
+     * have been generated via client-side flow. Thanks to http://bit.ly/b0Pt0H
+     * for the workaround.
+     *
+     * @return boolean Return true is the access token is set.
+     */
+    public function setExtendedAccessToken()
+    {
+        try {
+            // need to circumvent json_decode by calling _oauthRequest
+            // directly, since response isn't JSON format
+            $access_token_response = $this->_oauthRequest(
+                $this->getUrl('graph', '/oauth/access_token'),
+                $params = [
+                    'client_id' => $this->getAppId(),
+                    'client_secret' => $this->getAppSecret(),
+                    'grant_type' => 'fb_exchange_token',
+                    'fb_exchange_token' => $this->getAccessToken(),
+                ]
+            );
+        } catch (FacebookApiException $e) {
+            // most likely that user very recently revoked authorization
+            // In any event, we don't have an access token, so say so
+            return false;
         }
 
-        $access_token = $this->getAccessTokenFromCode($code, '');
-        if ($access_token) {
-          $this->setPersistentData('code', $code);
-          $this->setPersistentData('access_token', $access_token);
-          return $access_token;
+        if (empty($access_token_response)) {
+            return false;
         }
-      }
 
-      // signed request states there's no access token, so anything
-      // stored should be cleared
-      $this->clearAllPersistentData();
-      return false; // respect the signed request's data, even
-                    // if there's an authorization code or something else
-    }
+        $response_params = [];
+        parse_str($access_token_response, $response_params);
 
-    $code = $this->getCode();
-    if ($code && $code != $this->getPersistentData('code')) {
-      $access_token = $this->getAccessTokenFromCode($code);
-      if ($access_token) {
-        $this->setPersistentData('code', $code);
-        $this->setPersistentData('access_token', $access_token);
-        return $access_token;
-      }
-
-      // code was bogus, so everything based on it should be invalidated
-      $this->clearAllPersistentData();
-      return false;
-    }
+        if (!isset($response_params['access_token'])) {
+            return false;
+        }
+
+        $this->destroySession();
 
-    // as a fallback, just return whatever is in the persistent
-    // store, knowing nothing explicit (signed request, authorization
-    // code, etc.) was present to shadow it (or we saw a code in $_REQUEST,
-    // but it's the same as what's in the persistent store)
-    return $this->getPersistentData('access_token');
-  }
-
-  /**
-   * Retrieve the signed request, either from a request parameter or,
-   * if not present, from a cookie.
-   *
-   * @return string the signed request, if available, or null otherwise.
-   */
-  public function getSignedRequest() {
-    if (!$this->signedRequest) {
-      if (!empty($_REQUEST['signed_request'])) {
-        $this->signedRequest = $this->parseSignedRequest(
-          $_REQUEST['signed_request']);
-      } else if (!empty($_COOKIE[$this->getSignedRequestCookieName()])) {
-        $this->signedRequest = $this->parseSignedRequest(
-          $_COOKIE[$this->getSignedRequestCookieName()]);
-      }
+        $this->setPersistentData(
+            'access_token',
+            $response_params['access_token']
+        );
+        return true;
     }
-    return $this->signedRequest;
-  }
-
-  /**
-   * Get the UID of the connected user, or 0
-   * if the Facebook user is not connected.
-   *
-   * @return string the UID if available.
-   */
-  public function getUser() {
-    if ($this->user !== null) {
-      // we've already determined this and cached the value
-      return $this->user;
+
+    /**
+     * Determines the access token that should be used for API calls.
+     * The first time this is called, $this->accessToken is set equal
+     * to either a valid user access token, or it's set to the application
+     * access token if a valid user access token wasn't available.  Subsequent
+     * calls return whatever the first call returned.
+     *
+     * @return string The access token
+     */
+    public function getAccessToken()
+    {
+        if ($this->accessToken !== null) {
+            // we've done this already and cached it.  Just return.
+            return $this->accessToken;
+        }
+
+        // first establish access token to be the application
+        // access token, in case we navigate to the /oauth/access_token
+        // endpoint, where SOME access token is required
+        $this->setAccessToken($this->getApplicationAccessToken());
+        $user_access_token = $this->getUserAccessToken();
+        if ($user_access_token) {
+            $this->setAccessToken($user_access_token);
+        }
+
+        return $this->accessToken;
     }
 
-    return $this->user = $this->getUserFromAvailableData();
-  }
-
-  /**
-   * Determines the connected user by first examining any signed
-   * requests, then considering an authorization code, and then
-   * falling back to any persistent store storing the user.
-   *
-   * @return integer The id of the connected Facebook user,
-   *                 or 0 if no such user exists.
-   */
-  protected function getUserFromAvailableData() {
-    // if a signed request is supplied, then it solely determines
-    // who the user is
-    $signed_request = $this->getSignedRequest();
-    if ($signed_request) {
-      if (array_key_exists('user_id', $signed_request)) {
-        $user = $signed_request['user_id'];
-
-        if($user != $this->getPersistentData('user_id')){
-          $this->clearAllPersistentData();
+    /**
+     * Determines and returns the user access token, first using
+     * the signed request if present, and then falling back on
+     * the authorization code if present.  The intent is to
+     * return a valid user access token, or false if one is determined
+     * to not be available.
+     *
+     * @return false|string A valid user access token, or false if one
+     *                could not be determined.
+     */
+    protected function getUserAccessToken()
+    {
+        // first, consider a signed request if it's supplied
+        // if there is a signed request, then it alone determines
+        // the access token
+        $signed_request = $this->getSignedRequest();
+        if ($signed_request) {
+            // apps.facebook.com hands the access_token in the signed_request
+            if (array_key_exists('oauth_token', $signed_request)) {
+                $access_token = $signed_request['oauth_token'];
+                $this->setPersistentData('access_token', $access_token);
+                return $access_token;
+            }
+
+            // the JS SDK puts a code in with the redirect_uri of ''
+            if (array_key_exists('code', $signed_request)) {
+                $code = $signed_request['code'];
+                if ($code && $code == $this->getPersistentData('code')) {
+                    // short-circuit if the code we have is the same as the one presented
+                    return $this->getPersistentData('access_token');
+                }
+
+                $access_token = $this->getAccessTokenFromCode($code, '');
+                if ($access_token) {
+                    $this->setPersistentData('code', $code);
+                    $this->setPersistentData('access_token', $access_token);
+                    return $access_token;
+                }
+            }
+
+            // signed request states there's no access token, so anything
+            // stored should be cleared
+            $this->clearAllPersistentData();
+            return false;
+            // respect the signed request's data, even if there's an authorization code or something else
         }
 
-        $this->setPersistentData('user_id', $signed_request['user_id']);
-        return $user;
-      }
+        $code = $this->getCode();
+        if ($code && $code != $this->getPersistentData('code')) {
+            $access_token = $this->getAccessTokenFromCode($code);
+            if ($access_token) {
+                $this->setPersistentData('code', $code);
+                $this->setPersistentData('access_token', $access_token);
+                return $access_token;
+            }
+
+            // code was bogus, so everything based on it should be invalidated
+            $this->clearAllPersistentData();
+            return false;
+        }
 
-      // if the signed request didn't present a user id, then invalidate
-      // all entries in any persistent store
-      $this->clearAllPersistentData();
-      return 0;
+        // as a fallback, just return whatever is in the persistent
+        // store, knowing nothing explicit (signed request, authorization
+        // code, etc.) was present to shadow it (or we saw a code in $_REQUEST,
+        // but it's the same as what's in the persistent store)
+        return $this->getPersistentData('access_token');
     }
 
-    $user = $this->getPersistentData('user_id', $default = 0);
-    $persisted_access_token = $this->getPersistentData('access_token');
-
-    // use access_token to fetch user id if we have a user access_token, or if
-    // the cached access token has changed
-    $access_token = $this->getAccessToken();
-    if ($access_token &&
-        $access_token != $this->getApplicationAccessToken() &&
-        !($user && $persisted_access_token == $access_token)) {
-      $user = $this->getUserFromAccessToken();
-      if ($user) {
-        $this->setPersistentData('user_id', $user);
-      } else {
-        $this->clearAllPersistentData();
-      }
+    /**
+     * Retrieve the signed request, either from a request parameter or,
+     * if not present, from a cookie.
+     *
+     * @return array the signed request, if available, or null otherwise.
+     */
+    public function getSignedRequest()
+    {
+        if (!$this->signedRequest) {
+            if (!empty($_REQUEST['signed_request'])) {
+                $this->signedRequest = $this->parseSignedRequest(
+                    $_REQUEST['signed_request']
+                );
+            } elseif (!empty($_COOKIE[$this->getSignedRequestCookieName()])) {
+                $this->signedRequest = $this->parseSignedRequest(
+                    $_COOKIE[$this->getSignedRequestCookieName()]
+                );
+            }
+        }
+        return $this->signedRequest;
     }
 
-    return $user;
-  }
-
-  /**
-   * Get a Login URL for use with redirects. By default, full page redirect is
-   * assumed. If you are using the generated URL with a window.open() call in
-   * JavaScript, you can pass in display=popup as part of the $params.
-   *
-   * The parameters:
-   * - redirect_uri: the URL to go to after a successful login
-   * - scope: comma separated list of requested extended perms
-   *
-   * @param array $params Provide custom parameters
-   * @return string The URL for the login flow
-   */
-  public function getLoginUrl($params=array()) {
-    $this->establishCSRFTokenState();
-    $currentUrl = $this->getCurrentUrl();
-
-    // if 'scope' is passed as an array, convert to comma separated list
-    $scopeParams = isset($params['scope']) ? $params['scope'] : null;
-    if ($scopeParams && is_array($scopeParams)) {
-      $params['scope'] = implode(',', $scopeParams);
+    /**
+     * Get the UID of the connected user, or 0
+     * if the Facebook user is not connected.
+     *
+     * @return string the UID if available.
+     */
+    public function getUser()
+    {
+        if ($this->user !== null) {
+            // we've already determined this and cached the value
+            return $this->user;
+        }
+
+        return $this->user = $this->getUserFromAvailableData();
     }
 
-    return $this->getUrl(
-      'www',
-      'dialog/oauth',
-      array_merge(array(
+    /**
+     * Determines the connected user by first examining any signed
+     * requests, then considering an authorization code, and then
+     * falling back to any persistent store storing the user.
+     *
+     * @return integer The id of the connected Facebook user,
+     *                 or 0 if no such user exists.
+     */
+    protected function getUserFromAvailableData()
+    {
+        // if a signed request is supplied, then it solely determines
+        // who the user is
+        $signed_request = $this->getSignedRequest();
+        if ($signed_request) {
+            if (array_key_exists('user_id', $signed_request)) {
+                $user = $signed_request['user_id'];
+
+                if ($user != $this->getPersistentData('user_id')) {
+                    $this->clearAllPersistentData();
+                }
+
+                $this->setPersistentData('user_id', $signed_request['user_id']);
+                return $user;
+            }
+
+            // if the signed request didn't present a user id, then invalidate
+            // all entries in any persistent store
+            $this->clearAllPersistentData();
+            return 0;
+        }
+
+        $user = $this->getPersistentData('user_id', $default = 0);
+        $persisted_access_token = $this->getPersistentData('access_token');
+
+        // use access_token to fetch user id if we have a user access_token, or if
+        // the cached access token has changed
+        $access_token = $this->getAccessToken();
+        if ($access_token &&
+            $access_token != $this->getApplicationAccessToken() &&
+            !($user && $persisted_access_token == $access_token)) {
+            $user = $this->getUserFromAccessToken();
+            if ($user) {
+                $this->setPersistentData('user_id', $user);
+            } else {
+                $this->clearAllPersistentData();
+            }
+        }
+
+        return $user;
+    }
+
+    /**
+     * Get a Login URL for use with redirects. By default, full page redirect is
+     * assumed. If you are using the generated URL with a window.open() call in
+     * JavaScript, you can pass in display=popup as part of the $params.
+     *
+     * The parameters:
+     * - redirect_uri: the URL to go to after a successful login
+     * - scope: comma separated list of requested extended perms
+     *
+     * @param array $params Provide custom parameters
+     * @return string The URL for the login flow
+     */
+    public function getLoginUrl($params = [])
+    {
+        $this->establishCSRFTokenState();
+        $currentUrl = $this->getCurrentUrl();
+
+        // if 'scope' is passed as an array, convert to comma separated list
+        $scopeParams = isset($params['scope']) ? $params['scope'] : null;
+        if ($scopeParams && is_array($scopeParams)) {
+            $params['scope'] = implode(',', $scopeParams);
+        }
+
+        return $this->getUrl(
+            'www',
+            'dialog/oauth',
+            array_merge(
+                [
                     'client_id' => $this->getAppId(),
                     'redirect_uri' => $currentUrl, // possibly overwritten
-                    'state' => $this->state),
-                  $params));
-  }
-
-  /**
-   * Get a Logout URL suitable for use with redirects.
-   *
-   * The parameters:
-   * - next: the URL to go to after a successful logout
-   *
-   * @param array $params Provide custom parameters
-   * @return string The URL for the logout flow
-   */
-  public function getLogoutUrl($params=array()) {
-    return $this->getUrl(
-      'www',
-      'logout.php',
-      array_merge(array(
-        'next' => $this->getCurrentUrl(),
-        'access_token' => $this->getUserAccessToken(),
-      ), $params)
-    );
-  }
-
-  /**
-   * Get a login status URL to fetch the status from Facebook.
-   *
-   * The parameters:
-   * - ok_session: the URL to go to if a session is found
-   * - no_session: the URL to go to if the user is not connected
-   * - no_user: the URL to go to if the user is not signed into facebook
-   *
-   * @param array $params Provide custom parameters
-   * @return string The URL for the logout flow
-   */
-  public function getLoginStatusUrl($params=array()) {
-    return $this->getUrl(
-      'www',
-      'extern/login_status.php',
-      array_merge(array(
-        'api_key' => $this->getAppId(),
-        'no_session' => $this->getCurrentUrl(),
-        'no_user' => $this->getCurrentUrl(),
-        'ok_session' => $this->getCurrentUrl(),
-        'session_version' => 3,
-      ), $params)
-    );
-  }
-
-  /**
-   * Make an API call.
-   *
-   * @return mixed The decoded response
-   */
-  public function api(/* polymorphic */) {
-    $args = func_get_args();
-    if (is_array($args[0])) {
-      return $this->_restserver($args[0]);
-    } else {
-      return call_user_func_array(array($this, '_graph'), $args);
-    }
-  }
-
-  /**
-   * Constructs and returns the name of the cookie that
-   * potentially houses the signed request for the app user.
-   * The cookie is not set by the BaseFacebook class, but
-   * it may be set by the JavaScript SDK.
-   *
-   * @return string the name of the cookie that would house
-   *         the signed request value.
-   */
-  protected function getSignedRequestCookieName() {
-    return 'fbsr_'.$this->getAppId();
-  }
-
-  /**
-   * Constructs and returns the name of the coookie that potentially contain
-   * metadata. The cookie is not set by the BaseFacebook class, but it may be
-   * set by the JavaScript SDK.
-   *
-   * @return string the name of the cookie that would house metadata.
-   */
-  protected function getMetadataCookieName() {
-    return 'fbm_'.$this->getAppId();
-  }
-
-  /**
-   * Get the authorization code from the query parameters, if it exists,
-   * and otherwise return false to signal no authorization code was
-   * discoverable.
-   *
-   * @return mixed The authorization code, or false if the authorization
-   *               code could not be determined.
-   */
-  protected function getCode() {
-    if (isset($_REQUEST['code'])) {
-      if ($this->state !== null &&
-          isset($_REQUEST['state']) &&
-          $this->state === $_REQUEST['state']) {
-
-        // CSRF state has done its job, so clear it
-        $this->state = null;
-        $this->clearPersistentData('state');
-        return $_REQUEST['code'];
-      } else {
-        self::errorLog('CSRF state token does not match one provided. ' . $this->state . '!=' . $_REQUEST['state']);
-        return false;
-      }
+                    'state' => $this->state
+                ],
+                $params
+            )
+        );
     }
 
-    return false;
-  }
-
-  /**
-   * Retrieves the UID with the understanding that
-   * $this->accessToken has already been set and is
-   * seemingly legitimate.  It relies on Facebook's Graph API
-   * to retrieve user information and then extract
-   * the user ID.
-   *
-   * @return integer Returns the UID of the Facebook user, or 0
-   *                 if the Facebook user could not be determined.
-   */
-  protected function getUserFromAccessToken() {
-    try {
-      $user_info = $this->api('/me');
-      return $user_info['id'];
-    } catch (FacebookApiException $e) {
-      return 0;
-    }
-  }
-
-  /**
-   * Returns the access token that should be used for logged out
-   * users when no authorization code is available.
-   *
-   * @return string The application access token, useful for gathering
-   *                public information about users and applications.
-   */
-  protected function getApplicationAccessToken() {
-    return $this->appId.'|'.$this->appSecret;
-  }
-
-  /**
-   * Lays down a CSRF state token for this process.
-   *
-   * @return void
-   */
-  protected function establishCSRFTokenState() {
-    if ($this->state === null) {
-      $this->state = md5(uniqid(mt_rand(), true));
-      $this->setPersistentData('state', $this->state);
-    }
-  }
-
-  /**
-   * Retrieves an access token for the given authorization code
-   * (previously generated from www.facebook.com on behalf of
-   * a specific user).  The authorization code is sent to graph.facebook.com
-   * and a legitimate access token is generated provided the access token
-   * and the user for which it was generated all match, and the user is
-   * either logged in to Facebook or has granted an offline access permission.
-   *
-   * @param string $code An authorization code.
-   * @return mixed An access token exchanged for the authorization code, or
-   *               false if an access token could not be generated.
-   */
-  protected function getAccessTokenFromCode($code, $redirect_uri = null) {
-    if (empty($code)) {
-      return false;
+    /**
+     * Get a Logout URL suitable for use with redirects.
+     *
+     * The parameters:
+     * - next: the URL to go to after a successful logout
+     *
+     * @param array $params Provide custom parameters
+     * @return string The URL for the logout flow
+     */
+    public function getLogoutUrl($params = [])
+    {
+        return $this->getUrl(
+            'www',
+            'logout.php',
+            array_merge([
+                'next' => $this->getCurrentUrl(),
+                'access_token' => $this->getUserAccessToken(),
+            ], $params)
+        );
     }
 
-    if ($redirect_uri === null) {
-      $redirect_uri = $this->getCurrentUrl();
+    /**
+     * Get a login status URL to fetch the status from Facebook.
+     *
+     * The parameters:
+     * - ok_session: the URL to go to if a session is found
+     * - no_session: the URL to go to if the user is not connected
+     * - no_user: the URL to go to if the user is not signed into facebook
+     *
+     * @param array $params Provide custom parameters
+     * @return string The URL for the logout flow
+     */
+    public function getLoginStatusUrl($params = [])
+    {
+        return $this->getUrl(
+            'www',
+            'extern/login_status.php',
+            array_merge([
+                'api_key' => $this->getAppId(),
+                'no_session' => $this->getCurrentUrl(),
+                'no_user' => $this->getCurrentUrl(),
+                'ok_session' => $this->getCurrentUrl(),
+                'session_version' => 3,
+            ], $params)
+        );
     }
 
-    try {
-      // need to circumvent json_decode by calling _oauthRequest
-      // directly, since response isn't JSON format
-      $access_token_response =
-        $this->_oauthRequest(
-          $this->getUrl('graph', '/oauth/access_token'),
-          $params = array('client_id' => $this->getAppId(),
-                          'client_secret' => $this->getAppSecret(),
-                          'redirect_uri' => $redirect_uri,
-                          'code' => $code));
-    } catch (FacebookApiException $e) {
-      // most likely that user very recently revoked authorization.
-      // In any event, we don't have an access token, so say so.
-      return false;
+    /**
+     * Make an API call.
+     *
+     * @return mixed The decoded response
+     */
+    public function api(/* polymorphic */)
+    {
+        $args = func_get_args();
+        if (is_array($args[0])) {
+            return $this->_restserver($args[0]);
+        } else {
+            return call_user_func_array([$this, '_graph'], $args);
+        }
     }
 
-    if (empty($access_token_response)) {
-      return false;
+    /**
+     * Constructs and returns the name of the cookie that
+     * potentially houses the signed request for the app user.
+     * The cookie is not set by the BaseFacebook class, but
+     * it may be set by the JavaScript SDK.
+     *
+     * @return string the name of the cookie that would house
+     *         the signed request value.
+     */
+    protected function getSignedRequestCookieName()
+    {
+        return 'fbsr_'.$this->getAppId();
     }
 
-    $response_params = json_decode($access_token_response, true);
-    if (!isset($response_params['access_token'])) {
-      return false;
+    /**
+     * Constructs and returns the name of the coookie that potentially contain
+     * metadata. The cookie is not set by the BaseFacebook class, but it may be
+     * set by the JavaScript SDK.
+     *
+     * @return string the name of the cookie that would house metadata.
+     */
+    protected function getMetadataCookieName()
+    {
+        return 'fbm_'.$this->getAppId();
     }
 
-    return $response_params['access_token'];
-  }
-
-  /**
-   * Invoke the old restserver.php endpoint.
-   *
-   * @param array $params Method call object
-   *
-   * @return mixed The decoded response object
-   * @throws FacebookApiException
-   */
-  protected function _restserver($params) {
-    // generic application level parameters
-    $params['api_key'] = $this->getAppId();
-    $params['format'] = 'json-strings';
-
-    $result = json_decode($this->_oauthRequest(
-      $this->getApiUrl($params['method']),
-      $params
-    ), true);
-
-    // results are returned, errors are thrown
-    if (is_array($result) && isset($result['error_code'])) {
-      $this->throwAPIException($result);
-      // @codeCoverageIgnoreStart
-    }
-    // @codeCoverageIgnoreEnd
+    /**
+     * Get the authorization code from the query parameters, if it exists,
+     * and otherwise return false to signal no authorization code was
+     * discoverable.
+     *
+     * @return mixed The authorization code, or false if the authorization
+     *               code could not be determined.
+     */
+    protected function getCode()
+    {
+        if (isset($_REQUEST['code'])) {
+            if ($this->state !== null &&
+                isset($_REQUEST['state']) &&
+                $this->state === $_REQUEST['state']
+            ) {
+                // CSRF state has done its job, so clear it
+                $this->state = null;
+                $this->clearPersistentData('state');
+                return $_REQUEST['code'];
+            } else {
+                self::errorLog('CSRF state token does not match one provided. '.$this->state.'!='.$_REQUEST['state']);
+                return false;
+            }
+        }
 
-    $method = strtolower($params['method']);
-    if ($method === 'auth.expiresession' ||
-        $method === 'auth.revokeauthorization') {
-      $this->destroySession();
+        return false;
     }
 
-    return $result;
-  }
-
-  /**
-   * Return true if this is video post.
-   *
-   * @param string $path The path
-   * @param string $method The http method (default 'GET')
-   *
-   * @return boolean true if this is video post
-   */
-  protected function isVideoPost($path, $method = 'GET') {
-    if ($method == 'POST' && preg_match("/^(\/)(.+)(\/)(videos)$/", $path)) {
-      return true;
+    /**
+     * Retrieves the UID with the understanding that
+     * $this->accessToken has already been set and is
+     * seemingly legitimate.  It relies on Facebook's Graph API
+     * to retrieve user information and then extract
+     * the user ID.
+     *
+     * @return integer Returns the UID of the Facebook user, or 0
+     *                 if the Facebook user could not be determined.
+     */
+    protected function getUserFromAccessToken()
+    {
+        try {
+            $user_info = $this->api('/me');
+            return $user_info['id'];
+        } catch (FacebookApiException $e) {
+            return 0;
+        }
     }
-    return false;
-  }
-
-  /**
-   * Invoke the Graph API.
-   *
-   * @param string $path The path (required)
-   * @param string $method The http method (default 'GET')
-   * @param array $params The query/post data
-   *
-   * @return mixed The decoded response object
-   * @throws FacebookApiException
-   */
-  protected function _graph($path, $method = 'GET', $params = array()) {
-    if (is_array($method) && empty($params)) {
-      $params = $method;
-      $method = 'GET';
+
+    /**
+     * Returns the access token that should be used for logged out
+     * users when no authorization code is available.
+     *
+     * @return string The application access token, useful for gathering
+     *                public information about users and applications.
+     */
+    protected function getApplicationAccessToken()
+    {
+        return $this->appId.'|'.$this->appSecret;
     }
-    $params['method'] = $method; // method override as we always do a POST
 
-    if ($this->isVideoPost($path, $method)) {
-      $domainKey = 'graph_video';
-    } else {
-      $domainKey = 'graph';
+    /**
+     * Lays down a CSRF state token for this process.
+     *
+     * @return void
+     */
+    protected function establishCSRFTokenState()
+    {
+        if ($this->state === null) {
+            $this->state = md5(uniqid(mt_rand(), true));
+            $this->setPersistentData('state', $this->state);
+        }
     }
 
-    $result = json_decode($this->_oauthRequest(
-      $this->getUrl($domainKey, $path),
-      $params
-    ), true);
+    /**
+     * Retrieves an access token for the given authorization code
+     * (previously generated from www.facebook.com on behalf of
+     * a specific user).  The authorization code is sent to graph.facebook.com
+     * and a legitimate access token is generated provided the access token
+     * and the user for which it was generated all match, and the user is
+     * either logged in to Facebook or has granted an offline access permission.
+     *
+     * @param string $code An authorization code.
+     * @return mixed An access token exchanged for the authorization code, or
+     *               false if an access token could not be generated.
+     */
+    protected function getAccessTokenFromCode($code, $redirect_uri = null)
+    {
+        if (empty($code)) {
+            return false;
+        }
 
-    // results are returned, errors are thrown
-    if (is_array($result) && isset($result['error'])) {
-      $this->throwAPIException($result);
-      // @codeCoverageIgnoreStart
-    }
-    // @codeCoverageIgnoreEnd
-
-    return $result;
-  }
-
-  /**
-   * Make a OAuth Request.
-   *
-   * @param string $url The path (required)
-   * @param array $params The query/post data
-   *
-   * @return string The decoded response object
-   * @throws FacebookApiException
-   */
-  protected function _oauthRequest($url, $params) {
-    if (!isset($params['access_token'])) {
-      $params['access_token'] = $this->getAccessToken();
-    }
+        if ($redirect_uri === null) {
+            $redirect_uri = $this->getCurrentUrl();
+        }
+
+        try {
+            //self::errorLog('Redirect uri is ' . $redirect_uri);
+            // need to circumvent json_decode by calling _oauthRequest
+            // directly, since response isn't JSON format
+            $access_token_response =
+                $this->_oauthRequest(
+                    $this->getUrl('graph', '/oauth/access_token'),
+                    $params = [
+                        'client_id' => $this->getAppId(),
+                        'client_secret' => $this->getAppSecret(),
+                        'redirect_uri' => $redirect_uri,
+                        'code' => $code
+                    ]
+                );
+        } catch (FacebookApiException $e) {
+            self::errorLog($e->getMessage());
+            // most likely that user very recently revoked authorization.
+            // In any event, we don't have an access token, so say so.
+            return false;
+        }
 
-    // json_encode all params values that are not strings
-    foreach ($params as $key => $value) {
-      if (!is_string($value)) {
-        $params[$key] = json_encode($value);
-      }
+        if (empty($access_token_response)) {
+            self::errorLog('No access token response');
+            return false;
+        }
+
+        $response_params = json_decode($access_token_response, true);
+        if (!isset($response_params['access_token'])) {
+            self::errorLog('No access token in response. '.$access_token_response);
+            return false;
+        }
+
+        return $response_params['access_token'];
     }
 
-    return $this->makeRequest($url, $params);
-  }
-
-  /**
-   * Makes an HTTP request. This method can be overridden by subclasses if
-   * developers want to do fancier things or use something other than curl to
-   * make the request.
-   *
-   * @param string $url The URL to make the request to
-   * @param array $params The parameters to use for the POST body
-   * @param CurlHandler $ch Initialized curl handle
-   *
-   * @return string The response text
-   */
-  protected function makeRequest($url, $params, $ch=null) {
-    if (!$ch) {
-      $ch = curl_init();
+    /**
+     * Invoke the old restserver.php endpoint.
+     *
+     * @param array $params Method call object
+     *
+     * @return mixed The decoded response object
+     * @throws FacebookApiException
+     */
+    protected function _restserver($params)
+    {
+        // generic application level parameters
+        $params['api_key'] = $this->getAppId();
+        $params['format'] = 'json-strings';
+
+        $result = json_decode(
+            $this->_oauthRequest(
+                $this->getApiUrl($params['method']),
+                $params
+            ),
+            true
+        );
+
+        // results are returned, errors are thrown
+        if (is_array($result) && isset($result['error_code'])) {
+            $this->throwAPIException($result);
+            // @codeCoverageIgnoreStart
+        }
+        // @codeCoverageIgnoreEnd
+
+        $method = strtolower($params['method']);
+        if ($method === 'auth.expiresession' ||
+            $method === 'auth.revokeauthorization') {
+            $this->destroySession();
+        }
+
+        return $result;
     }
 
-    $opts = self::$CURL_OPTS;
-    if ($this->getFileUploadSupport()) {
-      $opts[CURLOPT_POSTFIELDS] = $params;
-    } else {
-      $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
+    /**
+     * Return true if this is video post.
+     *
+     * @param string $path The path
+     * @param string $method The http method (default 'GET')
+     *
+     * @return boolean true if this is video post
+     */
+    protected function isVideoPost($path, $method = 'GET')
+    {
+        if ($method == 'POST' && preg_match("/^(\/)(.+)(\/)(videos)$/", $path)) {
+            return true;
+        }
+        return false;
     }
-    $opts[CURLOPT_URL] = $url;
-
-    // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
-    // for 2 seconds if the server does not support this header
-    if (isset($opts[CURLOPT_HTTPHEADER])) {
-      $existing_headers = $opts[CURLOPT_HTTPHEADER];
-      $existing_headers[] = 'Expect:';
-      $opts[CURLOPT_HTTPHEADER] = $existing_headers;
-    } else {
-      $opts[CURLOPT_HTTPHEADER] = array('Expect:');
+
+    /**
+     * Invoke the Graph API.
+     *
+     * @param string $path The path (required)
+     * @param string $method The http method (default 'GET')
+     * @param array $params The query/post data
+     *
+     * @return mixed The decoded response object
+     * @throws FacebookApiException
+     */
+    protected function _graph($path, $method = 'GET', $params = [])
+    {
+        if (is_array($method) && empty($params)) {
+            $params = $method;
+            $method = 'GET';
+        }
+        $params['method'] = $method; // method override as we always do a POST
+
+        if ($this->isVideoPost($path, $method)) {
+            $domainKey = 'graph_video';
+        } else {
+            $domainKey = 'graph';
+        }
+
+        $result = json_decode(
+            $this->_oauthRequest(
+                $this->getUrl($domainKey, $path),
+                $params
+            ),
+            true
+        );
+
+        // results are returned, errors are thrown
+        if (is_array($result) && isset($result['error'])) {
+            $this->throwAPIException($result);
+            // @codeCoverageIgnoreStart
+        }
+        // @codeCoverageIgnoreEnd
+
+        return $result;
     }
 
-    curl_setopt_array($ch, $opts);
-    $result = curl_exec($ch);
+    /**
+     * Make a OAuth Request.
+     *
+     * @param string $url The path (required)
+     * @param array $params The query/post data
+     *
+     * @return string The decoded response object
+     * @throws FacebookApiException
+     */
+    protected function _oauthRequest($url, $params)
+    {
+        if (!isset($params['access_token'])) {
+            $params['access_token'] = $this->getAccessToken();
+        }
+
+        // json_encode all params values that are not strings
+        foreach ($params as $key => $value) {
+            if (!is_string($value)) {
+                $params[$key] = json_encode($value);
+            }
+        }
 
-    if (curl_errno($ch) == 60) { // CURLE_SSL_CACERT
-      self::errorLog('Invalid or no certificate authority found, '.
-                     'using bundled information');
-      curl_setopt($ch, CURLOPT_CAINFO,
-                  dirname(__FILE__) . '/fb_ca_chain_bundle.crt');
-      $result = curl_exec($ch);
+        return $this->makeRequest($url, $params);
     }
 
-    // With dual stacked DNS responses, it's possible for a server to
-    // have IPv6 enabled but not have IPv6 connectivity.  If this is
-    // the case, curl will try IPv4 first and if that fails, then it will
-    // fall back to IPv6 and the error EHOSTUNREACH is returned by the
-    // operating system
-    if ($result === false && empty($opts[CURLOPT_IPRESOLVE])) {
-        $matches = array();
-        $regex = '/Failed to connect to ([^:].*): Network is unreachable/';
-        if (preg_match($regex, curl_error($ch), $matches)) {
-          if (strlen(@inet_pton($matches[1])) === 16) {
-            self::errorLog('Invalid IPv6 configuration on server, '.
-                           'Please disable or get native IPv6 on your server.');
-            self::$CURL_OPTS[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
-            curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+    /**
+     * Makes an HTTP request. This method can be overridden by subclasses if
+     * developers want to do fancier things or use something other than curl to
+     * make the request.
+     *
+     * @param string $url The URL to make the request to
+     * @param array $params The parameters to use for the POST body
+     * @param CurlHandler $ch Initialized curl handle
+     *
+     * @return string The response text
+     */
+    protected function makeRequest($url, $params, $ch = null)
+    {
+        if (!$ch) {
+            $ch = curl_init();
+        }
+
+        $opts = self::$CURL_OPTS;
+        if ($this->getFileUploadSupport()) {
+            $opts[CURLOPT_POSTFIELDS] = $params;
+        } else {
+            $opts[CURLOPT_POSTFIELDS] = http_build_query($params, null, '&');
+        }
+        $opts[CURLOPT_URL] = $url;
+
+        // disable the 'Expect: 100-continue' behaviour. This causes CURL to wait
+        // for 2 seconds if the server does not support this header
+        if (isset($opts[CURLOPT_HTTPHEADER])) {
+            $existing_headers = $opts[CURLOPT_HTTPHEADER];
+            $existing_headers[] = 'Expect:';
+            $opts[CURLOPT_HTTPHEADER] = $existing_headers;
+        } else {
+            $opts[CURLOPT_HTTPHEADER] = ['Expect:'];
+        }
+
+        curl_setopt_array($ch, $opts);
+        $result = curl_exec($ch);
+
+        if (curl_errno($ch) == 60) {
+            // CURLE_SSL_CACERT
+            self::errorLog('Invalid or no certificate authority found, using bundled information');
+            curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__).'/fb_ca_chain_bundle.crt');
             $result = curl_exec($ch);
-          }
         }
-    }
 
-    if ($result === false) {
-      $e = new FacebookApiException(array(
-        'error_code' => curl_errno($ch),
-        'error' => array(
-        'message' => curl_error($ch),
-        'type' => 'CurlException',
-        ),
-      ));
-      curl_close($ch);
-      throw $e;
-    }
-    curl_close($ch);
-    return $result;
-  }
-
-  /**
-   * Parses a signed_request and validates the signature.
-   *
-   * @param string $signed_request A signed token
-   * @return array The payload inside it or null if the sig is wrong
-   */
-  protected function parseSignedRequest($signed_request) {
-    list($encoded_sig, $payload) = explode('.', $signed_request, 2);
-
-    // decode the data
-    $sig = self::base64UrlDecode($encoded_sig);
-    $data = json_decode(self::base64UrlDecode($payload), true);
-
-    if (strtoupper($data['algorithm']) !== self::SIGNED_REQUEST_ALGORITHM) {
-      self::errorLog(
-        'Unknown algorithm. Expected ' . self::SIGNED_REQUEST_ALGORITHM);
-      return null;
-    }
+        // With dual stacked DNS responses, it's possible for a server to
+        // have IPv6 enabled but not have IPv6 connectivity.  If this is
+        // the case, curl will try IPv4 first and if that fails, then it will
+        // fall back to IPv6 and the error EHOSTUNREACH is returned by the
+        // operating system
+        if ($result === false && empty($opts[CURLOPT_IPRESOLVE])) {
+            $matches = [];
+            $regex = '/Failed to connect to ([^:].*): Network is unreachable/';
+            if (preg_match($regex, curl_error($ch), $matches)) {
+                if (strlen(@inet_pton($matches[1])) === 16) {
+                    self::errorLog('Invalid IPv6 configuration on server, '.
+                            'Please disable or get native IPv6 on your server.');
+                    self::$CURL_OPTS[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
+                    curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+                    $result = curl_exec($ch);
+                }
+            }
+        }
 
-    // check sig
-    $expected_sig = hash_hmac('sha256', $payload,
-                              $this->getAppSecret(), $raw = true);
-    if ($sig !== $expected_sig) {
-      self::errorLog('Bad Signed JSON signature!');
-      return null;
+        if ($result === false) {
+            $e = new FacebookApiException([
+                'error_code' => curl_errno($ch),
+                'error' => [
+                    'message' => curl_error($ch),
+                    'type' => 'CurlException',
+                ],
+            ]);
+            curl_close($ch);
+            throw $e;
+        }
+        curl_close($ch);
+        return $result;
     }
 
-    return $data;
-  }
-
-  /**
-   * Makes a signed_request blob using the given data.
-   *
-   * @param array The data array.
-   * @return string The signed request.
-   */
-  protected function makeSignedRequest($data) {
-    if (!is_array($data)) {
-      throw new InvalidArgumentException(
-        'makeSignedRequest expects an array. Got: ' . print_r($data, true));
-    }
-    $data['algorithm'] = self::SIGNED_REQUEST_ALGORITHM;
-    $data['issued_at'] = time();
-    $json = json_encode($data);
-    $b64 = self::base64UrlEncode($json);
-    $raw_sig = hash_hmac('sha256', $b64, $this->getAppSecret(), $raw = true);
-    $sig = self::base64UrlEncode($raw_sig);
-    return $sig.'.'.$b64;
-  }
-
-  /**
-   * Build the URL for api given parameters.
-   *
-   * @param $method String the method name.
-   * @return string The URL for the given parameters
-   */
-  protected function getApiUrl($method) {
-    static $READ_ONLY_CALLS =
-      array('admin.getallocation' => 1,
-            'admin.getappproperties' => 1,
-            'admin.getbannedusers' => 1,
-            'admin.getlivestreamvialink' => 1,
-            'admin.getmetrics' => 1,
-            'admin.getrestrictioninfo' => 1,
-            'application.getpublicinfo' => 1,
-            'auth.getapppublickey' => 1,
-            'auth.getsession' => 1,
-            'auth.getsignedpublicsessiondata' => 1,
-            'comments.get' => 1,
-            'connect.getunconnectedfriendscount' => 1,
-            'dashboard.getactivity' => 1,
-            'dashboard.getcount' => 1,
-            'dashboard.getglobalnews' => 1,
-            'dashboard.getnews' => 1,
-            'dashboard.multigetcount' => 1,
-            'dashboard.multigetnews' => 1,
-            'data.getcookies' => 1,
-            'events.get' => 1,
-            'events.getmembers' => 1,
-            'fbml.getcustomtags' => 1,
-            'feed.getappfriendstories' => 1,
-            'feed.getregisteredtemplatebundlebyid' => 1,
-            'feed.getregisteredtemplatebundles' => 1,
-            'fql.multiquery' => 1,
-            'fql.query' => 1,
-            'friends.arefriends' => 1,
-            'friends.get' => 1,
-            'friends.getappusers' => 1,
-            'friends.getlists' => 1,
-            'friends.getmutualfriends' => 1,
-            'gifts.get' => 1,
-            'groups.get' => 1,
-            'groups.getmembers' => 1,
-            'intl.gettranslations' => 1,
-            'links.get' => 1,
-            'notes.get' => 1,
-            'notifications.get' => 1,
-            'pages.getinfo' => 1,
-            'pages.isadmin' => 1,
-            'pages.isappadded' => 1,
-            'pages.isfan' => 1,
-            'permissions.checkavailableapiaccess' => 1,
-            'permissions.checkgrantedapiaccess' => 1,
-            'photos.get' => 1,
-            'photos.getalbums' => 1,
-            'photos.gettags' => 1,
-            'profile.getinfo' => 1,
-            'profile.getinfooptions' => 1,
-            'stream.get' => 1,
-            'stream.getcomments' => 1,
-            'stream.getfilters' => 1,
-            'users.getinfo' => 1,
-            'users.getloggedinuser' => 1,
-            'users.getstandardinfo' => 1,
-            'users.hasapppermission' => 1,
-            'users.isappuser' => 1,
-            'users.isverified' => 1,
-            'video.getuploadlimits' => 1);
-    $name = 'api';
-    if (isset($READ_ONLY_CALLS[strtolower($method)])) {
-      $name = 'api_read';
-    } else if (strtolower($method) == 'video.upload') {
-      $name = 'api_video';
-    }
-    return self::getUrl($name, 'restserver.php');
-  }
-
-  /**
-   * Build the URL for given domain alias, path and parameters.
-   *
-   * @param $name string The name of the domain
-   * @param $path string Optional path (without a leading slash)
-   * @param $params array Optional query parameters
-   *
-   * @return string The URL for the given parameters
-   */
-  protected function getUrl($name, $path='', $params=array()) {
-    $url = self::$DOMAIN_MAP[$name];
-    if ($path) {
-      if ($path[0] === '/') {
-        $path = substr($path, 1);
-      }
-      $url .= $path;
-    }
-    if ($params) {
-      $url .= '?' . http_build_query($params, null, '&');
-    }
+    /**
+     * Parses a signed_request and validates the signature.
+     *
+     * @param string $signed_request A signed token
+     * @return array The payload inside it or null if the sig is wrong
+     */
+    protected function parseSignedRequest($signed_request)
+    {
+        list($encoded_sig, $payload) = explode('.', $signed_request, 2);
+
+        // decode the data
+        $sig = self::base64UrlDecode($encoded_sig);
+        $data = json_decode(self::base64UrlDecode($payload), true);
+
+        if (strtoupper($data['algorithm']) !== self::SIGNED_REQUEST_ALGORITHM) {
+            self::errorLog('Unknown algorithm. Expected '.self::SIGNED_REQUEST_ALGORITHM);
+            return null;
+        }
 
-    return $url;
-  }
+        // check sig
+        $expected_sig = hash_hmac('sha256', $payload, $this->getAppSecret(), $raw = true);
+        if ($sig !== $expected_sig) {
+            self::errorLog('Bad Signed JSON signature!');
+            return null;
+        }
 
-  protected function getHttpHost() {
-    if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
-      return $_SERVER['HTTP_X_FORWARDED_HOST'];
-    }
-    return $_SERVER['HTTP_HOST'];
-  }
-
-  protected function getHttpProtocol() {
-    if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
-      if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
-        return 'https';
-      }
-      return 'http';
-    }
-    /*apache + variants specific way of checking for https*/
-    if (isset($_SERVER['HTTPS']) &&
-        ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] == 1)) {
-      return 'https';
+        return $data;
     }
-    /*nginx way of checking for https*/
-    if (isset($_SERVER['SERVER_PORT']) &&
-        ($_SERVER['SERVER_PORT'] === '443')) {
-      return 'https';
+
+    /**
+     * Makes a signed_request blob using the given data.
+     *
+     * @param $data array The data array.
+     * @return string The signed request.
+     */
+    protected function makeSignedRequest($data)
+    {
+        if (!is_array($data)) {
+            throw new InvalidArgumentException(
+                'makeSignedRequest expects an array. Got: '.print_r($data, true)
+            );
+        }
+        $data['algorithm'] = self::SIGNED_REQUEST_ALGORITHM;
+        $data['issued_at'] = time();
+        $json = json_encode($data);
+        $b64 = self::base64UrlEncode($json);
+        $raw_sig = hash_hmac('sha256', $b64, $this->getAppSecret(), $raw = true);
+        $sig = self::base64UrlEncode($raw_sig);
+        return $sig.'.'.$b64;
     }
-    return 'http';
-  }
-
-  /**
-   * Get the base domain used for the cookie.
-   */
-  protected function getBaseDomain() {
-    // The base domain is stored in the metadata cookie if not we fallback
-    // to the current hostname
-    $metadata = $this->getMetadataCookie();
-    if (array_key_exists('base_domain', $metadata) &&
-        !empty($metadata['base_domain'])) {
-      return trim($metadata['base_domain'], '.');
+
+    /**
+     * Build the URL for api given parameters.
+     *
+     * @param $method String the method name.
+     * @return string The URL for the given parameters
+     */
+    protected function getApiUrl($method)
+    {
+        static $READ_ONLY_CALLS =
+            [
+                'admin.getallocation' => 1,
+                'admin.getappproperties' => 1,
+                'admin.getbannedusers' => 1,
+                'admin.getlivestreamvialink' => 1,
+                'admin.getmetrics' => 1,
+                'admin.getrestrictioninfo' => 1,
+                'application.getpublicinfo' => 1,
+                'auth.getapppublickey' => 1,
+                'auth.getsession' => 1,
+                'auth.getsignedpublicsessiondata' => 1,
+                'comments.get' => 1,
+                'connect.getunconnectedfriendscount' => 1,
+                'dashboard.getactivity' => 1,
+                'dashboard.getcount' => 1,
+                'dashboard.getglobalnews' => 1,
+                'dashboard.getnews' => 1,
+                'dashboard.multigetcount' => 1,
+                'dashboard.multigetnews' => 1,
+                'data.getcookies' => 1,
+                'events.get' => 1,
+                'events.getmembers' => 1,
+                'fbml.getcustomtags' => 1,
+                'feed.getappfriendstories' => 1,
+                'feed.getregisteredtemplatebundlebyid' => 1,
+                'feed.getregisteredtemplatebundles' => 1,
+                'fql.multiquery' => 1,
+                'fql.query' => 1,
+                'friends.arefriends' => 1,
+                'friends.get' => 1,
+                'friends.getappusers' => 1,
+                'friends.getlists' => 1,
+                'friends.getmutualfriends' => 1,
+                'gifts.get' => 1,
+                'groups.get' => 1,
+                'groups.getmembers' => 1,
+                'intl.gettranslations' => 1,
+                'links.get' => 1,
+                'notes.get' => 1,
+                'notifications.get' => 1,
+                'pages.getinfo' => 1,
+                'pages.isadmin' => 1,
+                'pages.isappadded' => 1,
+                'pages.isfan' => 1,
+                'permissions.checkavailableapiaccess' => 1,
+                'permissions.checkgrantedapiaccess' => 1,
+                'photos.get' => 1,
+                'photos.getalbums' => 1,
+                'photos.gettags' => 1,
+                'profile.getinfo' => 1,
+                'profile.getinfooptions' => 1,
+                'stream.get' => 1,
+                'stream.getcomments' => 1,
+                'stream.getfilters' => 1,
+                'users.getinfo' => 1,
+                'users.getloggedinuser' => 1,
+                'users.getstandardinfo' => 1,
+                'users.hasapppermission' => 1,
+                'users.isappuser' => 1,
+                'users.isverified' => 1,
+                'video.getuploadlimits' => 1
+            ];
+        $name = 'api';
+        if (isset($READ_ONLY_CALLS[strtolower($method)])) {
+            $name = 'api_read';
+        } elseif (strtolower($method) == 'video.upload') {
+            $name = 'api_video';
+        }
+        return $this->getUrl($name, 'restserver.php');
     }
-    return $this->getHttpHost();
-  }
-
-  /**
-   * Returns the Current URL, stripping it of known FB parameters that should
-   * not persist.
-   *
-   * @return string The current URL
-   */
-  protected function getCurrentUrl() {
-    $protocol = $this->getHttpProtocol() . '://';
-    $host = $this->getHttpHost();
-    $currentUrl = $protocol.$host.$_SERVER['REQUEST_URI'];
-    $parts = parse_url($currentUrl);
-
-    $query = '';
-    if (!empty($parts['query'])) {
-      // drop known fb params
-      $params = explode('&', $parts['query']);
-      $retained_params = array();
-      foreach ($params as $param) {
-        if ($this->shouldRetainParam($param)) {
-          $retained_params[] = $param;
+
+    /**
+     * Build the URL for given domain alias, path and parameters.
+     *
+     * @param $name string The name of the domain
+     * @param $path string Optional path (without a leading slash)
+     * @param $params array Optional query parameters
+     *
+     * @return string The URL for the given parameters
+     */
+    protected function getUrl($name, $path = '', $params = [])
+    {
+        $url = self::$DOMAIN_MAP[$name];
+        if ($path) {
+            if ($path[0] === '/') {
+                $path = substr($path, 1);
+            }
+            $url .= $path;
+        }
+        if ($params) {
+            $url .= '?'.http_build_query($params, null, '&');
         }
-      }
 
-      if (!empty($retained_params)) {
-        $query = '?'.implode($retained_params, '&');
-      }
+        return $url;
     }
 
-    // use port if non default
-    $port =
-      isset($parts['port']) &&
-      (($protocol === 'http://' && $parts['port'] !== 80) ||
-       ($protocol === 'https://' && $parts['port'] !== 443))
-      ? ':' . $parts['port'] : '';
-
-    // rebuild
-    return $protocol . $parts['host'] . $port . $parts['path'] . $query;
-  }
-
-  /**
-   * Returns true if and only if the key or key/value pair should
-   * be retained as part of the query string.  This amounts to
-   * a brute-force search of the very small list of Facebook-specific
-   * params that should be stripped out.
-   *
-   * @param string $param A key or key/value pair within a URL's query (e.g.
-   *                     'foo=a', 'foo=', or 'foo'.
-   *
-   * @return boolean
-   */
-  protected function shouldRetainParam($param) {
-    foreach (self::$DROP_QUERY_PARAMS as $drop_query_param) {
-      if (strpos($param, $drop_query_param.'=') === 0) {
-        return false;
-      }
+    protected function getHttpHost()
+    {
+        if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
+            return $_SERVER['HTTP_X_FORWARDED_HOST'];
+        }
+        return $_SERVER['HTTP_HOST'];
+    }
+
+    protected function getHttpProtocol()
+    {
+        if ($this->trustForwarded && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
+            if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
+                return 'https';
+            }
+            return 'http';
+        }
+        /*apache + variants specific way of checking for https*/
+        if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] === 'on' || $_SERVER['HTTPS'] == 1)) {
+            return 'https';
+        }
+        /*nginx way of checking for https*/
+        if (isset($_SERVER['SERVER_PORT']) && ($_SERVER['SERVER_PORT'] === '443')) {
+            return 'https';
+        }
+        return 'http';
     }
 
-    return true;
-  }
-
-  /**
-   * Analyzes the supplied result to see if it was thrown
-   * because the access token is no longer valid.  If that is
-   * the case, then we destroy the session.
-   *
-   * @param $result array A record storing the error message returned
-   *                      by a failed API call.
-   */
-  protected function throwAPIException($result) {
-    $e = new FacebookApiException($result);
-    switch ($e->getType()) {
-      // OAuth 2.0 Draft 00 style
-      case 'OAuthException':
-        // OAuth 2.0 Draft 10 style
-      case 'invalid_token':
-        // REST server errors are just Exceptions
-      case 'Exception':
-        $message = $e->getMessage();
-        if ((strpos($message, 'Error validating access token') !== false) ||
-            (strpos($message, 'Invalid OAuth access token') !== false) ||
-            (strpos($message, 'An active access token must be used') !== false)
-        ) {
-          $this->destroySession();
+    /**
+     * Get the base domain used for the cookie.
+     */
+    protected function getBaseDomain()
+    {
+        // The base domain is stored in the metadata cookie if not we fallback
+        // to the current hostname
+        $metadata = $this->getMetadataCookie();
+        if (array_key_exists('base_domain', $metadata) && !empty($metadata['base_domain'])) {
+            return trim($metadata['base_domain'], '.');
         }
-        break;
+        return $this->getHttpHost();
     }
 
-    throw $e;
-  }
+    /**
+     * Returns the Current URL, stripping it of known FB parameters that should
+     * not persist.
+     *
+     * @return string The current URL
+     */
+    protected function getCurrentUrl()
+    {
+        $protocol = $this->getHttpProtocol().'://';
+        $host = $this->getHttpHost();
+        $currentUrl = $protocol.$host.$_SERVER['REQUEST_URI'];
+        $parts = parse_url($currentUrl);
+
+        // use port if non default
+        $port =
+            isset($parts['port']) &&
+            (($protocol === 'http://' && $parts['port'] !== 80) ||
+            ($protocol === 'https://' && $parts['port'] !== 443))
+            ? ':'.$parts['port'] : '';
+
+        // rebuild
+        return $protocol.$parts['host'].$port.$parts['path'];
+    }
 
+    /**
+     * Analyzes the supplied result to see if it was thrown
+     * because the access token is no longer valid.  If that is
+     * the case, then we destroy the session.
+     *
+     * @param $result array A record storing the error message returned
+     *                      by a failed API call.
+     */
+    protected function throwAPIException($result)
+    {
+        $e = new FacebookApiException($result);
+        switch ($e->getType()) {
+            // OAuth 2.0 Draft 00 style
+            case 'OAuthException':
+            // OAuth 2.0 Draft 10 style
+            case 'invalid_token':
+            // REST server errors are just Exceptions
+            case 'Exception':
+                $message = $e->getMessage();
+                if ((strpos($message, 'Error validating access token') !== false) ||
+                    (strpos($message, 'Invalid OAuth access token') !== false) ||
+                    (strpos($message, 'An active access token must be used') !== false)
+                ) {
+                    $this->destroySession();
+                }
+                break;
+        }
 
-  /**
-   * Prints to the error log if you aren't in command line mode.
-   *
-   * @param string $msg Log message
-   */
-  protected static function errorLog($msg) {
-    // disable error log if we are running in a CLI environment
-    // @codeCoverageIgnoreStart
-    if (php_sapi_name() != 'cli') {
-      error_log($msg);
+        throw $e;
     }
-    // @codeCoverageIgnoreEnd
-  }
-
-  /**
-   * Base64 encoding that doesn't need to be urlencode()ed.
-   * Exactly the same as base64_encode except it uses
-   *   - instead of +
-   *   _ instead of /
-   *   No padded =
-   *
-   * @param string $input base64UrlEncoded string
-   * @return string
-   */
-  protected static function base64UrlDecode($input) {
-    return base64_decode(strtr($input, '-_', '+/'));
-  }
-
-  /**
-   * Base64 encoding that doesn't need to be urlencode()ed.
-   * Exactly the same as base64_encode except it uses
-   *   - instead of +
-   *   _ instead of /
-   *
-   * @param string $input string
-   * @return string base64Url encoded string
-   */
-  protected static function base64UrlEncode($input) {
-    $str = strtr(base64_encode($input), '+/', '-_');
-    $str = str_replace('=', '', $str);
-    return $str;
-  }
-
-  /**
-   * Destroy the current session
-   */
-  public function destroySession() {
-    $this->accessToken = null;
-    $this->signedRequest = null;
-    $this->user = null;
-    $this->clearAllPersistentData();
-
-    // Javascript sets a cookie that will be used in getSignedRequest that we
-    // need to clear if we can
-    $cookie_name = $this->getSignedRequestCookieName();
-    if (array_key_exists($cookie_name, $_COOKIE)) {
-      unset($_COOKIE[$cookie_name]);
-      if (!headers_sent()) {
-        $base_domain = $this->getBaseDomain();
-        setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
-      } else {
+
+
+    /**
+     * Prints to the error log if you aren't in command line mode.
+     *
+     * @param string $msg Log message
+     */
+    protected static function errorLog($msg)
+    {
+        // disable error log if we are running in a CLI environment
         // @codeCoverageIgnoreStart
-        self::errorLog(
-          'There exists a cookie that we wanted to clear that we couldn\'t '.
-          'clear because headers was already sent. Make sure to do the first '.
-          'API call before outputing anything.'
-        );
+        if (php_sapi_name() != 'cli') {
+            error_log($msg);
+        }
         // @codeCoverageIgnoreEnd
-      }
-    }
-  }
-
-  /**
-   * Parses the metadata cookie that our Javascript API set
-   *
-   * @return  an array mapping key to value
-   */
-  protected function getMetadataCookie() {
-    $cookie_name = $this->getMetadataCookieName();
-    if (!array_key_exists($cookie_name, $_COOKIE)) {
-      return array();
     }
 
-    // The cookie value can be wrapped in "-characters so remove them
-    $cookie_value = trim($_COOKIE[$cookie_name], '"');
+    /**
+     * Base64 encoding that doesn't need to be urlencode()ed.
+     * Exactly the same as base64_encode except it uses
+     *   - instead of +
+     *   _ instead of /
+     *   No padded =
+     *
+     * @param string $input base64UrlEncoded string
+     * @return string
+     */
+    protected static function base64UrlDecode($input)
+    {
+        return base64_decode(strtr($input, '-_', '+/'));
+    }
 
-    if (empty($cookie_value)) {
-      return array();
+    /**
+     * Base64 encoding that doesn't need to be urlencode()ed.
+     * Exactly the same as base64_encode except it uses
+     *   - instead of +
+     *   _ instead of /
+     *
+     * @param string $input string
+     * @return string base64Url encoded string
+     */
+    protected static function base64UrlEncode($input)
+    {
+        $str = strtr(base64_encode($input), '+/', '-_');
+        $str = str_replace('=', '', $str);
+        return $str;
     }
 
-    $parts = explode('&', $cookie_value);
-    $metadata = array();
-    foreach ($parts as $part) {
-      $pair = explode('=', $part, 2);
-      if (!empty($pair[0])) {
-        $metadata[urldecode($pair[0])] =
-          (count($pair) > 1) ? urldecode($pair[1]) : '';
-      }
+    /**
+     * Destroy the current session
+     */
+    public function destroySession()
+    {
+        $this->accessToken = null;
+        $this->signedRequest = null;
+        $this->user = null;
+        $this->clearAllPersistentData();
+
+        // Javascript sets a cookie that will be used in getSignedRequest that we
+        // need to clear if we can
+        $cookie_name = $this->getSignedRequestCookieName();
+        if (array_key_exists($cookie_name, $_COOKIE)) {
+            unset($_COOKIE[$cookie_name]);
+            if (!headers_sent()) {
+                $base_domain = $this->getBaseDomain();
+                setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
+            } else {
+                // @codeCoverageIgnoreStart
+                self::errorLog(
+                    'There exists a cookie that we wanted to clear that we couldn\'t '.
+                    'clear because headers was already sent. Make sure to do the first '.
+                    'API call before outputing anything.'
+                );
+                // @codeCoverageIgnoreEnd
+            }
+        }
     }
 
-    return $metadata;
-  }
+    /**
+     * Parses the metadata cookie that our Javascript API set
+     *
+     * @return array an array mapping key to value
+     */
+    protected function getMetadataCookie()
+    {
+        $cookie_name = $this->getMetadataCookieName();
+        if (!array_key_exists($cookie_name, $_COOKIE)) {
+            return [];
+        }
+
+        // The cookie value can be wrapped in "-characters so remove them
+        $cookie_value = trim($_COOKIE[$cookie_name], '"');
 
-  protected static function isAllowedDomain($big, $small) {
-    if ($big === $small) {
-      return true;
+        if (empty($cookie_value)) {
+            return [];
+        }
+
+        $parts = explode('&', $cookie_value);
+        $metadata = [];
+        foreach ($parts as $part) {
+            $pair = explode('=', $part, 2);
+            if (!empty($pair[0])) {
+                $metadata[urldecode($pair[0])] = (count($pair) > 1) ? urldecode($pair[1]) : '';
+            }
+        }
+
+        return $metadata;
+    }
+
+    protected static function isAllowedDomain($big, $small)
+    {
+        if ($big === $small) {
+            return true;
+        }
+        return self::endsWith($big, '.'.$small);
     }
-    return self::endsWith($big, '.'.$small);
-  }
 
-  protected static function endsWith($big, $small) {
-    $len = strlen($small);
-    if ($len === 0) {
-      return true;
+    protected static function endsWith($big, $small)
+    {
+        $len = strlen($small);
+        if ($len === 0) {
+            return true;
+        }
+        return substr($big, -$len) === $small;
     }
-    return substr($big, -$len) === $small;
-  }
-
-  /**
-   * Each of the following four methods should be overridden in
-   * a concrete subclass, as they are in the provided Facebook class.
-   * The Facebook class uses PHP sessions to provide a primitive
-   * persistent store, but another subclass--one that you implement--
-   * might use a database, memcache, or an in-memory cache.
-   *
-   * @see Facebook
-   */
-
-  /**
-   * Stores the given ($key, $value) pair, so that future calls to
-   * getPersistentData($key) return $value. This call may be in another request.
-   *
-   * @param string $key
-   * @param array $value
-   *
-   * @return void
-   */
-  abstract protected function setPersistentData($key, $value);
-
-  /**
-   * Get the data for $key, persisted by BaseFacebook::setPersistentData()
-   *
-   * @param string $key The key of the data to retrieve
-   * @param boolean $default The default value to return if $key is not found
-   *
-   * @return mixed
-   */
-  abstract protected function getPersistentData($key, $default = false);
-
-  /**
-   * Clear the data with $key from the persistent storage
-   *
-   * @param string $key
-   * @return void
-   */
-  abstract protected function clearPersistentData($key);
-
-  /**
-   * Clear all data from the persistent storage
-   *
-   * @return void
-   */
-  abstract protected function clearAllPersistentData();
+
+    /**
+     * Each of the following four methods should be overridden in
+     * a concrete subclass, as they are in the provided Facebook class.
+     * The Facebook class uses PHP sessions to provide a primitive
+     * persistent store, but another subclass--one that you implement--
+     * might use a database, memcache, or an in-memory cache.
+     *
+     * @see Facebook
+     */
+
+    /**
+     * Stores the given ($key, $value) pair, so that future calls to
+     * getPersistentData($key) return $value. This call may be in another request.
+     *
+     * @param string $key
+     * @param array $value
+     *
+     * @return void
+     */
+    abstract protected function setPersistentData($key, $value);
+
+    /**
+     * Get the data for $key, persisted by BaseFacebook::setPersistentData()
+     *
+     * @param string $key The key of the data to retrieve
+     * @param boolean $default The default value to return if $key is not found
+     *
+     * @return mixed
+     */
+    abstract protected function getPersistentData($key, $default = false);
+
+    /**
+     * Clear the data with $key from the persistent storage
+     *
+     * @param string $key
+     * @return void
+     */
+    abstract protected function clearPersistentData($key);
+
+    /**
+     * Clear all data from the persistent storage
+     *
+     * @return void
+     */
+    abstract protected function clearAllPersistentData();
 }
diff --git a/modules/authfacebook/lib/Auth/Source/Facebook.php b/modules/authfacebook/lib/Auth/Source/Facebook.php
index 865e152c38db35e7569b7678e3ea4ce627c76c56..a2bee6a7a368d460d2998aef16d72810a834ab97 100644
--- a/modules/authfacebook/lib/Auth/Source/Facebook.php
+++ b/modules/authfacebook/lib/Auth/Source/Facebook.php
@@ -1,143 +1,158 @@
 <?php
 
+namespace SimpleSAML\Module\authfacebook\Auth\Source;
+
+use SimpleSAML\Module;
+
 /**
  * Authenticate using Facebook Platform.
  *
  * @author Andreas Ă…kre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_authfacebook_Auth_Source_Facebook extends SimpleSAML_Auth_Source {
-
-
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGE_INIT = 'facebook:init';
-
-
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'facebook:AuthId';
-
-
-	/**
-	 * Facebook App ID or API Key
-	 */
-	private $api_key;
-
-
-	/**
-	 * Facebook App Secret
-	 */
-	private $secret;
-
-
-	/**
-	 * Which additional data permissions to request from user
-	 */
-	private $req_perms;
-
-
-	/**
-	 * A comma-separated list of user profile fields to request.
-	 *
-	 * Note that some user fields require appropriate permissions. For
-	 * example, to retrieve the user's primary email address, "email" must
-	 * be specified in both the req_perms and the user_fields parameter.
-	 *
-	 * When empty, only the app-specific user id and name will be returned.
-	 *
-	 * See the Graph API specification for all available user fields:
-	 * https://developers.facebook.com/docs/graph-api/reference/v2.6/user
-	 */
-	private $user_fields;
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		$cfgParse = SimpleSAML_Configuration::loadFromArray($config, 'authsources[' . var_export($this->authId, TRUE) . ']');
-		
-		$this->api_key = $cfgParse->getString('api_key');
-		$this->secret = $cfgParse->getString('secret');
-		$this->req_perms = $cfgParse->getString('req_perms', NULL);
-		$this->user_fields = $cfgParse->getString('user_fields', NULL);
-	}
-
-
-	/**
-	 * Log-in using Facebook platform
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		// We are going to need the authId in order to retrieve this authentication source later
-		$state[self::AUTHID] = $this->authId;
-		SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-		
-		$facebook = new sspmod_authfacebook_Facebook(array('appId' => $this->api_key, 'secret' => $this->secret), $state);
-		$facebook->destroySession();
-
-		$linkback = SimpleSAML\Module::getModuleURL('authfacebook/linkback.php');
-		$url = $facebook->getLoginUrl(array('redirect_uri' => $linkback, 'scope' => $this->req_perms));
-		SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url);
-	}
-		
-
-	public function finalStep(&$state) {
-		assert(is_array($state));
-
-		$facebook = new sspmod_authfacebook_Facebook(array('appId' => $this->api_key, 'secret' => $this->secret), $state);
-		$uid = $facebook->getUser();
-
-		if (isset($uid) && $uid) {
-			try {
-				$info = $facebook->api("/" . $uid . ($this->user_fields ? "?fields=" . $this->user_fields : ""));
-			} catch (FacebookApiException $e) {
-				throw new SimpleSAML_Error_AuthSource($this->authId, 'Error getting user profile.', $e);
-			}
-		}
-
-		if (!isset($info)) {
-			throw new SimpleSAML_Error_AuthSource($this->authId, 'Error getting user profile.');
-		}
-		
-		$attributes = array();
-		foreach($info AS $key => $value) {
-			if (is_string($value) && !empty($value)) {
-				$attributes['facebook.' . $key] = array((string)$value);
-			}
-		}
-
-		if (array_key_exists('third_party_id', $info)) {
-			$attributes['facebook_user'] = array($info['third_party_id'] . '@facebook.com');
-		} else {
-			$attributes['facebook_user'] = array($uid . '@facebook.com');
-		}
-
-		$attributes['facebook_targetedID'] = array('http://facebook.com!' . $uid);
-		$attributes['facebook_cn'] = array($info['name']);
-
-		SimpleSAML\Logger::debug('Facebook Returned Attributes: '. implode(", ", array_keys($attributes)));
-
-		$state['Attributes'] = $attributes;
-	
-		$facebook->destroySession();
-	}
 
+class Facebook extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The string used to identify our states.
+     */
+    const STAGE_INIT = 'facebook:init';
+
+
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = 'facebook:AuthId';
+
+
+    /**
+     * Facebook App ID or API Key
+     */
+    private $api_key;
+
+
+    /**
+     * Facebook App Secret
+     */
+    private $secret;
+
+
+    /**
+     * Which additional data permissions to request from user
+     */
+    private $req_perms;
+
+
+    /**
+     * A comma-separated list of user profile fields to request.
+     *
+     * Note that some user fields require appropriate permissions. For
+     * example, to retrieve the user's primary email address, "email" must
+     * be specified in both the req_perms and the user_fields parameter.
+     *
+     * When empty, only the app-specific user id and name will be returned.
+     *
+     * See the Graph API specification for all available user fields:
+     * https://developers.facebook.com/docs/graph-api/reference/v2.6/user
+     */
+    private $user_fields;
+
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        $cfgParse = \SimpleSAML\Configuration::loadFromArray(
+            $config,
+            'authsources['.var_export($this->authId, true).']'
+        );
+
+        $this->api_key = $cfgParse->getString('api_key');
+        $this->secret = $cfgParse->getString('secret');
+        $this->req_perms = $cfgParse->getString('req_perms', null);
+        $this->user_fields = $cfgParse->getString('user_fields', null);
+    }
+
+
+    /**
+     * Log-in using Facebook platform
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+
+        // We are going to need the authId in order to retrieve this authentication source later
+        $state[self::AUTHID] = $this->authId;
+        \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
+
+        $facebook = new Module\authfacebook\Facebook(
+            ['appId' => $this->api_key, 'secret' => $this->secret],
+            $state
+        );
+        $facebook->destroySession();
+
+        $linkback = Module::getModuleURL('authfacebook/linkback.php');
+        $url = $facebook->getLoginUrl(['redirect_uri' => $linkback, 'scope' => $this->req_perms]);
+        \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
+
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url);
+    }
+
+
+    public function finalStep(&$state)
+    {
+        assert(is_array($state));
+
+        $facebook = new Module\authfacebook\Facebook(
+            ['appId' => $this->api_key, 'secret' => $this->secret],
+            $state
+        );
+        $uid = $facebook->getUser();
+
+        if (isset($uid) && $uid) {
+            try {
+                $info = $facebook->api("/".$uid.($this->user_fields ? "?fields=".$this->user_fields : ""));
+            } catch (\FacebookApiException $e) {
+                throw new \SimpleSAML\Error\AuthSource($this->authId, 'Error getting user profile.', $e);
+            }
+        }
+
+        if (!isset($info)) {
+            throw new \SimpleSAML\Error\AuthSource($this->authId, 'Error getting user profile.');
+        }
+
+        $attributes = [];
+        foreach ($info as $key => $value) {
+            if (is_string($value) && !empty($value)) {
+                $attributes['facebook.'.$key] = [(string) $value];
+            }
+        }
+
+        if (array_key_exists('third_party_id', $info)) {
+            $attributes['facebook_user'] = [$info['third_party_id'].'@facebook.com'];
+        } else {
+            $attributes['facebook_user'] = [$uid.'@facebook.com'];
+        }
+
+        $attributes['facebook_targetedID'] = ['http://facebook.com!'.$uid];
+        $attributes['facebook_cn'] = [$info['name']];
+
+        \SimpleSAML\Logger::debug('Facebook Returned Attributes: '.implode(", ", array_keys($attributes)));
+
+        $state['Attributes'] = $attributes;
+
+        $facebook->destroySession();
+    }
 }
diff --git a/modules/authfacebook/lib/Facebook.php b/modules/authfacebook/lib/Facebook.php
index 42153933c2fb2a23ca526067514a7ecbb1ceedf6..cf68d348a52d3530b98879a284977efc120cbf61 100644
--- a/modules/authfacebook/lib/Facebook.php
+++ b/modules/authfacebook/lib/Facebook.php
@@ -1,156 +1,170 @@
 <?php
 
-require_once(dirname(dirname(__FILE__)) . '/extlibinc/base_facebook.php');
+namespace SimpleSAML\Module\authfacebook;
+
+require_once(dirname(dirname(__FILE__)).'/extlibinc/base_facebook.php');
 
 /**
  * Extends the BaseFacebook class with the intent of using
  * PHP sessions to store user ids and access tokens.
  */
-class sspmod_authfacebook_Facebook extends BaseFacebook
+
+class Facebook extends \BaseFacebook
 {
-  const FBSS_COOKIE_NAME = 'fbss';
-
-  // We can set this to a high number because the main session
-  // expiration will trump this
-  const FBSS_COOKIE_EXPIRE = 31556926; // 1 year
-
-  // Stores the shared session ID if one is set
-  protected $sharedSessionID;
-
-  // SimpleSAMLphp state array
-  protected $ssp_state;
-
-  /**
-   * Identical to the parent constructor, except that
-   * we start a PHP session to store the user ID and
-   * access token if during the course of execution
-   * we discover them.
-   *
-   * @param Array $config the application configuration. Additionally
-   * accepts "sharedSession" as a boolean to turn on a secondary
-   * cookie for environments with a shared session (that is, your app
-   * shares the domain with other apps).
-   * @see BaseFacebook::__construct in base_facebook.php
-   */
-  public function __construct(array $config, &$ssp_state) {
-    $this->ssp_state = &$ssp_state;
-
-    parent::__construct($config);
-    if (!empty($config['sharedSession'])) {
-      $this->initSharedSession();
+    const FBSS_COOKIE_NAME = 'fbss';
+
+    // We can set this to a high number because the main session
+    // expiration will trump this
+    const FBSS_COOKIE_EXPIRE = 31556926; // 1 year
+
+    // Stores the shared session ID if one is set
+    protected $sharedSessionID;
+
+    // SimpleSAMLphp state array
+    protected $ssp_state;
+
+    // \SimpleSAML\Auth\State
+    protected $state;
+
+    /**
+     * Identical to the parent constructor, except that
+     * we start a PHP session to store the user ID and
+     * access token if during the course of execution
+     * we discover them.
+     *
+     * @param Array $config the application configuration. Additionally
+     * accepts "sharedSession" as a boolean to turn on a secondary
+     * cookie for environments with a shared session (that is, your app
+     * shares the domain with other apps).
+     * @see BaseFacebook::__construct in base_facebook.php
+     */
+    public function __construct(array $config, &$ssp_state)
+    {
+        $this->ssp_state = &$ssp_state;
+
+        parent::__construct($config);
+        if (!empty($config['sharedSession'])) {
+            $this->initSharedSession();
+        }
     }
-  }
-
-  protected static $kSupportedKeys =
-    array('state', 'code', 'access_token', 'user_id');
-
-  protected function initSharedSession() {
-    $cookie_name = $this->getSharedSessionCookieName();
-    if (isset($_COOKIE[$cookie_name])) {
-      $data = $this->parseSignedRequest($_COOKIE[$cookie_name]);
-      if (!empty($data) && !empty($data['domain']) &&
-          self::isAllowedDomain($this->getHttpHost(), $data['domain'])) {
-        // good case
-        $this->sharedSessionID = $data['id'];
-        return;
-      }
-      // ignoring potentially unreachable data
-    }
-    // evil/corrupt/missing case
-    $base_domain = $this->getBaseDomain();
-    $this->sharedSessionID = md5(uniqid(mt_rand(), true));
-    $cookie_value = $this->makeSignedRequest(
-      array(
-        'domain' => $base_domain,
-        'id' => $this->sharedSessionID,
-      )
-    );
-    $_COOKIE[$cookie_name] = $cookie_value;
-    if (!headers_sent()) {
-      $expire = time() + self::FBSS_COOKIE_EXPIRE;
-      setcookie($cookie_name, $cookie_value, $expire, '/', '.'.$base_domain);
-    } else {
-      // @codeCoverageIgnoreStart
-      SimpleSAML\Logger::debug(
-        'Shared session ID cookie could not be set! You must ensure you '.
-        'create the Facebook instance before headers have been sent. This '.
-        'will cause authentication issues after the first request.'
-      );
-      // @codeCoverageIgnoreEnd
+
+    protected static $kSupportedKeys = ['state', 'code', 'access_token', 'user_id'];
+
+    protected function initSharedSession()
+    {
+        $cookie_name = $this->getSharedSessionCookieName();
+        if (isset($_COOKIE[$cookie_name])) {
+            $data = $this->parseSignedRequest($_COOKIE[$cookie_name]);
+            if (!empty($data) && !empty($data['domain']) &&
+                self::isAllowedDomain($this->getHttpHost(), $data['domain'])) {
+                // good case
+                $this->sharedSessionID = $data['id'];
+                return;
+            }
+            // ignoring potentially unreachable data
+        }
+        // evil/corrupt/missing case
+        $base_domain = $this->getBaseDomain();
+        $this->sharedSessionID = md5(uniqid(mt_rand(), true));
+        $cookie_value = $this->makeSignedRequest(
+            [
+                'domain' => $base_domain,
+                'id' => $this->sharedSessionID,
+            ]
+        );
+        $_COOKIE[$cookie_name] = $cookie_value;
+        if (!headers_sent()) {
+            $expire = time() + self::FBSS_COOKIE_EXPIRE;
+            setcookie($cookie_name, $cookie_value, $expire, '/', '.'.$base_domain);
+        } else {
+            // @codeCoverageIgnoreStart
+            \SimpleSAML\Logger::debug(
+                'Shared session ID cookie could not be set! You must ensure you '.
+                'create the Facebook instance before headers have been sent. This '.
+                'will cause authentication issues after the first request.'
+            );
+            // @codeCoverageIgnoreEnd
+        }
     }
-  }
-
-  /**
-   * Provides the implementations of the inherited abstract
-   * methods.  The implementation uses PHP sessions to maintain
-   * a store for authorization codes, user ids, CSRF states, and
-   * access tokens.
-   */
-  protected function setPersistentData($key, $value) {
-    if (!in_array($key, self::$kSupportedKeys)) {
-      SimpleSAML\Logger::debug("Unsupported key passed to setPersistentData: " . var_export($key, TRUE));
-      return;
+
+    /**
+     * Provides the implementations of the inherited abstract
+     * methods.  The implementation uses PHP sessions to maintain
+     * a store for authorization codes, user ids, CSRF states, and
+     * access tokens.
+     */
+    protected function setPersistentData($key, $value)
+    {
+        if (!in_array($key, self::$kSupportedKeys)) {
+            \SimpleSAML\Logger::debug("Unsupported key passed to setPersistentData: ".var_export($key, true));
+            return;
+        }
+
+        $session_var_name = $this->constructSessionVariableName($key);
+        $this->ssp_state[$session_var_name] = $value;
     }
 
-    $session_var_name = $this->constructSessionVariableName($key);
-    $this->ssp_state[$session_var_name] = $value;
-  }
+    protected function getPersistentData($key, $default = false)
+    {
+        if (!in_array($key, self::$kSupportedKeys)) {
+            \SimpleSAML\Logger::debug("Unsupported key passed to getPersistentData: ".var_export($key, true));
+            return $default;
+        }
 
-  protected function getPersistentData($key, $default = false) {
-    if (!in_array($key, self::$kSupportedKeys)) {
-      SimpleSAML\Logger::debug("Unsupported key passed to getPersistentData: " . var_export($key, TRUE));
-      return $default;
+        $session_var_name = $this->constructSessionVariableName($key);
+        return isset($this->ssp_state[$session_var_name]) ? $this->ssp_state[$session_var_name] : $default;
     }
 
-    $session_var_name = $this->constructSessionVariableName($key);
-    return isset($this->ssp_state[$session_var_name]) ?
-      $this->ssp_state[$session_var_name] : $default;
-  }
+    protected function clearPersistentData($key)
+    {
+        if (!in_array($key, self::$kSupportedKeys)) {
+            \SimpleSAML\Logger::debug("Unsupported key passed to clearPersistentData: ".var_export($key, true));
+            return;
+        }
+
+        $session_var_name = $this->constructSessionVariableName($key);
+        if (isset($this->ssp_state[$session_var_name])) {
+            unset($this->ssp_state[$session_var_name]);
+        }
+    }
 
-  protected function clearPersistentData($key) {
-    if (!in_array($key, self::$kSupportedKeys)) {
-      SimpleSAML\Logger::debug("Unsupported key passed to clearPersistentData: " . var_export($key, TRUE));
-      return;
+    protected function clearAllPersistentData()
+    {
+        foreach (self::$kSupportedKeys as $key) {
+            $this->clearPersistentData($key);
+        }
+        if ($this->sharedSessionID) {
+            $this->deleteSharedSessionCookie();
+        }
     }
 
-    $session_var_name = $this->constructSessionVariableName($key);
-    if (isset($this->ssp_state[$session_var_name])) {
-      unset($this->ssp_state[$session_var_name]);
+    protected function deleteSharedSessionCookie()
+    {
+        $cookie_name = $this->getSharedSessionCookieName();
+        unset($_COOKIE[$cookie_name]);
+        $base_domain = $this->getBaseDomain();
+        setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
     }
-  }
 
-  protected function clearAllPersistentData() {
-    foreach (self::$kSupportedKeys as $key) {
-      $this->clearPersistentData($key);
+    protected function getSharedSessionCookieName()
+    {
+        return self::FBSS_COOKIE_NAME.'_'.$this->getAppId();
     }
-    if ($this->sharedSessionID) {
-      $this->deleteSharedSessionCookie();
+
+    protected function constructSessionVariableName($key)
+    {
+        $parts = ['authfacebook:authdata:fb', $this->getAppId(), $key];
+        if ($this->sharedSessionID) {
+            array_unshift($parts, $this->sharedSessionID);
+        }
+        return implode('_', $parts);
     }
-  }
-
-  protected function deleteSharedSessionCookie() {
-    $cookie_name = $this->getSharedSessionCookieName();
-    unset($_COOKIE[$cookie_name]);
-    $base_domain = $this->getBaseDomain();
-    setcookie($cookie_name, '', 1, '/', '.'.$base_domain);
-  }
-
-  protected function getSharedSessionCookieName() {
-    return self::FBSS_COOKIE_NAME . '_' . $this->getAppId();
-  }
-
-  protected function constructSessionVariableName($key) {
-    $parts = array('authfacebook:authdata:fb', $this->getAppId(), $key);
-    if ($this->sharedSessionID) {
-      array_unshift($parts, $this->sharedSessionID);
+
+    protected function establishCSRFTokenState()
+    {
+        if ($this->state === null) {
+            $this->state = \SimpleSAML\Auth\State::getStateId($this->ssp_state);
+            $this->setPersistentData('state', $this->state);
+        }
     }
-    return implode('_', $parts);
-  }
-
-  protected function establishCSRFTokenState() {
-     if ($this->state === null) {
-          $this->state = SimpleSAML_Auth_State::getStateId($this->ssp_state);
-          $this->setPersistentData('state', $this->state);
-     }
-  }
 }
diff --git a/modules/authfacebook/www/linkback.php b/modules/authfacebook/www/linkback.php
index 94adb167289de6490ed6cc6083121b194aad2f18..6a24590194e4ec6a3e390386b5f937853fec4e86 100644
--- a/modules/authfacebook/www/linkback.php
+++ b/modules/authfacebook/www/linkback.php
@@ -6,34 +6,47 @@
 
 // For backwards compatability look for AuthState first
 if (array_key_exists('AuthState', $_REQUEST) && !empty($_REQUEST['AuthState'])) {
-    $state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], sspmod_authfacebook_Auth_Source_Facebook::STAGE_INIT);
+    $state = \SimpleSAML\Auth\State::loadState(
+        $_REQUEST['AuthState'],
+        \SimpleSAML\Module\authfacebook\Auth\Source\Facebook::STAGE_INIT
+    );
 } elseif (array_key_exists('state', $_REQUEST) && !empty($_REQUEST['state'])) {
-    $state = SimpleSAML_Auth_State::loadState($_REQUEST['state'], sspmod_authfacebook_Auth_Source_Facebook::STAGE_INIT);
+    $state = \SimpleSAML\Auth\State::loadState(
+        $_REQUEST['state'],
+        \SimpleSAML\Module\authfacebook\Auth\Source\Facebook::STAGE_INIT
+    );
 } else {
-    throw new SimpleSAML_Error_BadRequest('Missing state parameter on facebook linkback endpoint.');
+    throw new \SimpleSAML\Error\BadRequest('Missing state parameter on facebook linkback endpoint.');
 }
 
 // Find authentication source
-if (!array_key_exists(sspmod_authfacebook_Auth_Source_Facebook::AUTHID, $state)) {
-	throw new SimpleSAML_Error_BadRequest('No data in state for ' . sspmod_authfacebook_Auth_Source_Facebook::AUTHID);
+if (!array_key_exists(\SimpleSAML\Module\authfacebook\Auth\Source\Facebook::AUTHID, $state)) {
+    throw new \SimpleSAML\Error\BadRequest(
+        'No data in state for '.\SimpleSAML\Module\authfacebook\Auth\Source\Facebook::AUTHID
+    );
 }
-$sourceId = $state[sspmod_authfacebook_Auth_Source_Facebook::AUTHID];
+$sourceId = $state[\SimpleSAML\Module\authfacebook\Auth\Source\Facebook::AUTHID];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new SimpleSAML_Error_BadRequest('Could not find authentication source with id ' . var_export($sourceId, TRUE));
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new \SimpleSAML\Error\BadRequest(
+        'Could not find authentication source with id '.var_export($sourceId, true)
+    );
 }
 
 try {
-	if (isset($_REQUEST['error_reason']) && $_REQUEST['error_reason'] == 'user_denied') {
-		throw new SimpleSAML_Error_UserAborted();
-	}
+    if (isset($_REQUEST['error_reason']) && $_REQUEST['error_reason'] == 'user_denied') {
+        throw new \SimpleSAML\Error\UserAborted();
+    }
 
-	$source->finalStep($state);
-} catch (SimpleSAML_Error_Exception $e) {
-	SimpleSAML_Auth_State::throwException($state, $e);
-} catch (Exception $e) {
-	SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_AuthSource($sourceId, 'Error on facebook linkback endpoint.', $e));
+    $source->finalStep($state);
+} catch (\SimpleSAML\Error\Exception $e) {
+    \SimpleSAML\Auth\State::throwException($state, $e);
+} catch (\Exception $e) {
+    \SimpleSAML\Auth\State::throwException(
+        $state,
+        new \SimpleSAML\Error\AuthSource($sourceId, 'Error on facebook linkback endpoint.', $e)
+    );
 }
 
-SimpleSAML_Auth_Source::completeAuth($state);
+\SimpleSAML\Auth\Source::completeAuth($state);
diff --git a/modules/authlinkedin/lib/Auth/Source/LinkedIn.php b/modules/authlinkedin/lib/Auth/Source/LinkedIn.php
index ff961df0c66492fe1d03c0ed10ceedb7f350aa16..0716d8663f296366c247fb46ae22801ccab9b6cf 100644
--- a/modules/authlinkedin/lib/Auth/Source/LinkedIn.php
+++ b/modules/authlinkedin/lib/Auth/Source/LinkedIn.php
@@ -1,6 +1,8 @@
 <?php
 
-require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/libextinc/OAuth.php');
+namespace SimpleSAML\Module\authlinkedin\Auth\Source;
+
+require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))).'/oauth/libextinc/OAuth.php');
 
 /**
  * Authenticate using LinkedIn.
@@ -8,9 +10,9 @@ require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/lib
  * @author Brook Schofield, TERENA.
  * @package SimpleSAMLphp
  */
-class sspmod_authlinkedin_Auth_Source_LinkedIn extends SimpleSAML_Auth_Source 
-{
 
+class LinkedIn extends \SimpleSAML\Auth\Source
+{
     /**
      * The string used to identify our states.
      */
@@ -40,13 +42,15 @@ class sspmod_authlinkedin_Auth_Source_LinkedIn extends SimpleSAML_Auth_Source
         // Call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        if (!array_key_exists('key', $config))
-            throw new Exception('LinkedIn authentication source is not properly configured: missing [key]');
+        if (!array_key_exists('key', $config)) {
+            throw new \Exception('LinkedIn authentication source is not properly configured: missing [key]');
+        }
 
         $this->key = $config['key'];
 
-        if (!array_key_exists('secret', $config))
-            throw new Exception('LinkedIn authentication source is not properly configured: missing [secret]');
+        if (!array_key_exists('secret', $config)) {
+            throw new \Exception('LinkedIn authentication source is not properly configured: missing [secret]');
+        }
 
         $this->secret = $config['secret'];
 
@@ -72,58 +76,61 @@ class sspmod_authlinkedin_Auth_Source_LinkedIn extends SimpleSAML_Auth_Source
         // We are going to need the authId in order to retrieve this authentication source later
         $state[self::AUTHID] = $this->authId;
 
-        $stateID = SimpleSAML_Auth_State::getStateId($state);
-        SimpleSAML\Logger::debug('authlinkedin auth state id = ' . $stateID);
+        $stateID = \SimpleSAML\Auth\State::getStateId($state);
+        \SimpleSAML\Logger::debug('authlinkedin auth state id = '.$stateID);
 
-        $consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
+        $consumer = new \SimpleSAML\Module\oauth\Consumer($this->key, $this->secret);
 
         // Get the request token
         $requestToken = $consumer->getRequestToken(
             'https://api.linkedin.com/uas/oauth/requestToken',
-            array('oauth_callback' => SimpleSAML\Module::getModuleUrl('authlinkedin') . '/linkback.php?stateid=' . $stateID)
+            [
+                'oauth_callback' => \SimpleSAML\Module::getModuleUrl('authlinkedin').'/linkback.php?stateid='.$stateID
+            ]
         );
 
-        SimpleSAML\Logger::debug(
-            "Got a request token from the OAuth service provider [" .
-            $requestToken->key . "] with the secret [" . $requestToken->secret . "]"
+        \SimpleSAML\Logger::debug(
+            "Got a request token from the OAuth service provider [".
+            $requestToken->key."] with the secret [".$requestToken->secret."]"
         );
 
         $state['authlinkedin:requestToken'] = $requestToken;
 
         // Update the state
-        SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
+        \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
 
         // Authorize the request token
         $consumer->getAuthorizeRequest('https://www.linkedin.com/uas/oauth/authenticate', $requestToken);
     }
 
 
-    public function finalStep(&$state) 
+    public function finalStep(&$state)
     {
         $requestToken = $state['authlinkedin:requestToken'];
 
-        $consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
+        $consumer = new \SimpleSAML\Module\oauth\Consumer($this->key, $this->secret);
 
-        SimpleSAML\Logger::debug(
-            "oauth: Using this request token [" .
-            $requestToken->key . "] with the secret [" . $requestToken->secret . "]"
+        \SimpleSAML\Logger::debug(
+            "oauth: Using this request token [".
+            $requestToken->key."] with the secret [".$requestToken->secret."]"
         );
 
         // Replace the request token with an access token (via GET method)
         $accessToken = $consumer->getAccessToken(
-            'https://api.linkedin.com/uas/oauth/accessToken', $requestToken,
-            array('oauth_verifier' => $state['authlinkedin:oauth_verifier'])
+            'https://api.linkedin.com/uas/oauth/accessToken',
+            $requestToken,
+            ['oauth_verifier' => $state['authlinkedin:oauth_verifier']]
         );
 
-        SimpleSAML\Logger::debug(
-            "Got an access token from the OAuth service provider [" .
-            $accessToken->key . "] with the secret [" . $accessToken->secret . "]"
+        \SimpleSAML\Logger::debug(
+            "Got an access token from the OAuth service provider [".
+            $accessToken->key."] with the secret [".$accessToken->secret."]"
         );
 
         $userdata = $consumer->getUserInfo(
-            'https://api.linkedin.com/v1/people/~:(' . $this->attributes . ')',
-            $accessToken, 
-            array('http' => array('header' => 'x-li-format: json'))
+            'https://api.linkedin.com/v1/people/~:('.$this->attributes.')',
+            $accessToken,
+            ['http' => ['header' => 'x-li-format: json']]
         );
 
         $attributes = $this->flatten($userdata, 'linkedin.');
@@ -131,11 +138,11 @@ class sspmod_authlinkedin_Auth_Source_LinkedIn extends SimpleSAML_Auth_Source
         // TODO: pass accessToken: key, secret + expiry as attributes?
 
         if (array_key_exists('id', $userdata)) {
-            $attributes['linkedin_targetedID'] = array('http://linkedin.com!' . $userdata['id']);
-            $attributes['linkedin_user'] = array($userdata['id'] . '@linkedin.com');
+            $attributes['linkedin_targetedID'] = ['http://linkedin.com!'.$userdata['id']];
+            $attributes['linkedin_user'] = [$userdata['id'].'@linkedin.com'];
         }
 
-        SimpleSAML\Logger::debug('LinkedIn Returned Attributes: '. implode(", ",array_keys($attributes)));
+        \SimpleSAML\Logger::debug('LinkedIn Returned Attributes: '.implode(", ", array_keys($attributes)));
 
         $state['Attributes'] = $attributes;
     }
@@ -169,12 +176,12 @@ class sspmod_authlinkedin_Auth_Source_LinkedIn extends SimpleSAML_Auth_Source
      */
     protected function flatten($array, $prefix = '')
     {
-        $result = array();
+        $result = [];
         foreach ($array as $key => $value) {
             if (is_array($value)) {
-                $result = $result + $this->flatten($value, $prefix . $key . '.');
+                $result = $result + $this->flatten($value, $prefix.$key.'.');
             } else {
-                $result[$prefix . $key] = array($value);
+                $result[$prefix.$key] = [$value];
             }
         }
         return $result;
diff --git a/modules/authlinkedin/www/linkback.php b/modules/authlinkedin/www/linkback.php
index ee6731f1e71330d96bae7d76f17af941596087d4..157525ab29b505ada5462f70bd368fb4b74495c8 100644
--- a/modules/authlinkedin/www/linkback.php
+++ b/modules/authlinkedin/www/linkback.php
@@ -5,27 +5,29 @@
  */
 
 if (!array_key_exists('stateid', $_REQUEST)) {
-    throw new Exception('Lost OAuth Client State');
+    throw new \Exception('Lost OAuth Client State');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['stateid'], sspmod_authlinkedin_Auth_Source_LinkedIn::STAGE_INIT);
+$state = \SimpleSAML\Auth\State::loadState(
+    $_REQUEST['stateid'],
+    \SimpleSAML\Module\authlinkedin\Auth\Source\LinkedIn::STAGE_INIT
+);
 
 // http://developer.linkedin.com/docs/DOC-1008#2_Redirect_the_User_to_our_Authorization_Server
 if (array_key_exists('oauth_verifier', $_REQUEST)) {
-	$state['authlinkedin:oauth_verifier'] = $_REQUEST['oauth_verifier'];
+    $state['authlinkedin:oauth_verifier'] = $_REQUEST['oauth_verifier'];
 } else {
-	throw new Exception('OAuth verifier not returned.');;
+    throw new Exception('OAuth verifier not returned.');
 }
 
 // Find authentication source
-assert(array_key_exists(sspmod_authlinkedin_Auth_Source_LinkedIn::AUTHID, $state));
-$sourceId = $state[sspmod_authlinkedin_Auth_Source_LinkedIn::AUTHID];
+assert(array_key_exists(\SimpleSAML\Module\authlinkedin\Auth\Source\LinkedIn::AUTHID, $state));
+$sourceId = $state[\SimpleSAML\Module\authlinkedin\Auth\Source\LinkedIn::AUTHID];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new \Exception('Could not find authentication source with id '.$sourceId);
 }
 
 $source->finalStep($state);
 
-SimpleSAML_Auth_Source::completeAuth($state);
-
+\SimpleSAML\Auth\Source::completeAuth($state);
diff --git a/modules/authmyspace/docs/oauthmyspace.md b/modules/authmyspace/docs/oauthmyspace.md
deleted file mode 100644
index 98b97b805a83545e2f3f560b853be4a1af213fe8..0000000000000000000000000000000000000000
--- a/modules/authmyspace/docs/oauthmyspace.md
+++ /dev/null
@@ -1,25 +0,0 @@
-Using the MySpace authentication source with SimpleSAMLphp
-==========================================================
-
-Remember to configure `authsources.php`, with both your Client ID and Secret key.
-
-To get an API key and a secret, register the application at:
-
- * <http://developer.myspace.com/Modules/Apps/Pages/CreateAppAccount.aspx>
-
-Create a MySpace ID App and set the callback evaluation URL to be:
-
- * `http://sp.example.org/`
-
-Replace `sp.example.org` with your hostname.
-
-## Testing authentication
-
-On the SimpleSAMLphp frontpage, go to the *Authentication* tab, and use the link:
-
-  * *Test configured authentication sources*
-
-Then choose the *myspace* authentication source.
-
-Expected behaviour would then be that you are sent to MySpace, and asked to login.
-There is no consent screen for attribute release.
diff --git a/modules/authmyspace/lib/Auth/Source/MySpace.php b/modules/authmyspace/lib/Auth/Source/MySpace.php
deleted file mode 100644
index 26b8a1c57d39114e0098f8a636daeb12fc5fba55..0000000000000000000000000000000000000000
--- a/modules/authmyspace/lib/Auth/Source/MySpace.php
+++ /dev/null
@@ -1,137 +0,0 @@
-<?php
-
-require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/libextinc/OAuth.php');
-
-/**
- * Authenticate using MySpace.
- *
- * @author Brook Schofield, TERENA.
- * @package SimpleSAMLphp
- */
-class sspmod_authmyspace_Auth_Source_MySpace extends SimpleSAML_Auth_Source {
-
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGE_INIT = 'authmyspace:init';
-
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'authmyspace:AuthId';
-
-	private $key;
-	private $secret;
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		if (!array_key_exists('key', $config))
-			throw new Exception('MySpace authentication source is not properly configured: missing [key]');
-
-		$this->key = $config['key'];
-
-		if (!array_key_exists('secret', $config))
-			throw new Exception('MySpace authentication source is not properly configured: missing [secret]');
-
-		$this->secret = $config['secret'];
-	}
-
-
-	/**
-	 * Log-in using MySpace platform
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		// We are going to need the authId in order to retrieve this authentication source later
-		$state[self::AUTHID] = $this->authId;
-
-		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
-
-		// Get the request token
-		$requestToken = $consumer->getRequestToken('http://api.myspace.com/request_token');
-		SimpleSAML\Logger::debug("Got a request token from the OAuth service provider [" .
-			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
-
-		$state['authmyspace:requestToken'] = $requestToken;
-
-		$stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-		SimpleSAML\Logger::debug('authmyspace auth state id = ' . $stateID);
-
-		// Authorize the request token
-		$consumer->getAuthorizeRequest('http://api.myspace.com/authorize', $requestToken, TRUE, SimpleSAML\Module::getModuleUrl('authmyspace') . '/linkback.php?stateid=' . $stateID);
-
-	}
-
-
-
-	public function finalStep(&$state) {
-
-		$requestToken = $state['authmyspace:requestToken'];
-
-		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
-
-		SimpleSAML\Logger::debug("oauth: Using this request token [" .
-			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
-
-		// Replace the request token with an access token
-		$accessToken = $consumer->getAccessToken('http://api.myspace.com/access_token', $requestToken);
-		SimpleSAML\Logger::debug("Got an access token from the OAuth service provider [" .
-			$accessToken->key . "] with the secret [" . $accessToken->secret . "]");
-
-		// People API -  http://developerwiki.myspace.com/index.php?title=People_API
-		$userdata = $consumer->getUserInfo('http://api.myspace.com/1.0/people/@me/@self?fields=@all', $accessToken);
-
-		$attributes = array();
-
-		if (is_array($userdata['person'])) {
-			foreach($userdata['person'] AS $key => $value) {
-				if (is_string($value) || is_int($value))
-					$attributes['myspace.' . $key] = array((string)$value);
-
-				if (is_array($value)) {
-					foreach($value AS $key2 => $value2) {
-						if (is_string($value2) || is_int($value2))
-							$attributes['myspace.' . $key . '.' . $key2] = array((string)$value2);
-					}
-				}
-			}
-
-			if (array_key_exists('id', $userdata['person']) ) {
-
-				// person-id in the format of myspace.com.person.1234567890
-				if (preg_match('/(\d+)$/',$userdata['person']['id'],$matches)) {
-					$attributes['myspace_targetedID'] = array('http://myspace.com!' . $matches[1]);
-					$attributes['myspace_uid'] = array($matches[1]);
-					$attributes['myspace_user'] = array($matches[1] . '@myspace.com');
-				}
-			}
-
-			// profileUrl in the format http://www.myspace.com/username
-			if (array_key_exists('profileUrl', $userdata['person']) ) {
-				if (preg_match('@/([^/]+)$@',$userdata['person']['profileUrl'],$matches)) {
-					$attributes['myspace_username'] = array($matches[1]);
-					$attributes['myspace_user'] = array($matches[1] . '@myspace.com');
-				}
-			}
-		}
-
-		SimpleSAML\Logger::debug('MySpace Returned Attributes: '. implode(", ",array_keys($attributes)));
-
-		$state['Attributes'] = $attributes;
-	}
-}
diff --git a/modules/authmyspace/www/linkback.php b/modules/authmyspace/www/linkback.php
deleted file mode 100644
index 296807844bbe3ceea677da673e362e682e643cf4..0000000000000000000000000000000000000000
--- a/modules/authmyspace/www/linkback.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-
-/**
- * Handle linkback() response from MySpace.
- */
-
-if (!array_key_exists('stateid', $_REQUEST)) {
-	throw new Exception('State Lost - not returned by MySpace Auth');
-}
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['stateid'], sspmod_authmyspace_Auth_Source_MySpace::STAGE_INIT);
-
-if (array_key_exists('oauth_problem', $_REQUEST)) {
-	// oauth_problem of 'user_refused' means user chose not to login with MySpace
-	if (strcmp($_REQUEST['oauth_problem'],'user_refused') == 0) {
-		$e = new SimpleSAML_Error_UserAborted();
-		SimpleSAML_Auth_State::throwException($state, $e);
-	}
-
-	// Error
-	$e = new SimpleSAML_Error_Error('Authentication failed: ' . $_REQUEST['oauth_problem']);
-	SimpleSAML_Auth_State::throwException($state, $e);
-}
-
-if (array_key_exists('oauth_verifier', $_REQUEST)) {
-	$state['authmyspace:oauth_verifier'] = $_REQUEST['oauth_verifier'];
-} else {
-	throw new Exception('OAuth verifier not returned.');;
-}
-
-// Find authentication source
-assert(array_key_exists(sspmod_authmyspace_Auth_Source_MySpace::AUTHID, $state));
-$sourceId = $state[sspmod_authmyspace_Auth_Source_MySpace::AUTHID];
-
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $sourceId);
-}
-
-$source->finalStep($state);
-
-SimpleSAML_Auth_Source::completeAuth($state);
-
diff --git a/modules/authorize/lib/Auth/Process/Authorize.php b/modules/authorize/lib/Auth/Process/Authorize.php
index 68c5ad009f1f712359baf7878934847593e032af..151bee965279e0e1156d02daac90c9252a995e1a 100644
--- a/modules/authorize/lib/Auth/Process/Authorize.php
+++ b/modules/authorize/lib/Auth/Process/Authorize.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authorize\Auth\Process;
+
 /**
  * Filter to authorize only certain users.
  * See docs directory.
@@ -7,127 +9,134 @@
  * @author Ernesto Revilla, Yaco Sistemas SL., Ryan Panning
  * @package SimpleSAMLphp
  */
-class sspmod_authorize_Auth_Process_Authorize extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Flag to deny/unauthorize the user a attribute filter IS found
-	 *
-	 * @var bool
-	 */
-	protected $deny = FALSE;
-
-	/**
-	 * Flag to turn the REGEX pattern matching on or off
-	 *
-	 * @var bool
-	 */
-	protected $regex = TRUE;
-
-	/**
-	 * Array of valid users. Each element is a regular expression. You should
-	 * user \ to escape special chars, like '.' etc.
-	 *
-	 */
-	protected $valid_attribute_values = array();
-
-
-	/**
-	 * Initialize this filter.
-	 * Validate configuration parameters.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
-
-		// Check for the deny option, get it and remove it
-		// Must be bool specifically, if not, it might be for a attrib filter below
-		if (isset($config['deny']) && is_bool($config['deny'])) {
-			$this->deny = $config['deny'];
-			unset($config['deny']);
-		}
-
-		// Check for the regex option, get it and remove it
-		// Must be bool specifically, if not, it might be for a attrib filter below
-		if (isset($config['regex']) && is_bool($config['regex'])) {
-			$this->regex = $config['regex'];
-			unset($config['regex']);
-		}
-
-		foreach ($config as $attribute => $values) {
-			if (is_string($values))
-				$values = array($values);
-			if (!is_array($values))
-				throw new Exception('Filter Authorize: Attribute values is neither string nor array: ' . var_export($attribute, TRUE));
-			foreach ($values as $value){
-				if(!is_string($value)) {
-					throw new Exception('Filter Authorize: Each value should be a string for attribute: ' . var_export($attribute, TRUE) . ' value: ' . var_export($value, TRUE) . ' Config is: ' . var_export($config, TRUE));
-				}
-			}
-			$this->valid_attribute_values[$attribute] = $values;
-		}
-	}
-
-
-	/**
-	 * Apply filter to validate attributes.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		$authorize = $this->deny;
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		$attributes =& $request['Attributes'];
-
-		foreach ($this->valid_attribute_values as $name => $patterns) {
-			if(array_key_exists($name, $attributes)) {
-				foreach ($patterns as $pattern){
-					$values = $attributes[$name];
-					if (!is_array($values))
-						$values = array($values);
-					foreach ($values as $value){
-						if ($this->regex) {
-							$matched = preg_match($pattern, $value);
-						} else {
-							$matched = ($value == $pattern);
-						}
-						if ($matched) {
-							$authorize = ($this->deny ? FALSE : TRUE);
-							break 3;
-						}
-					}
-				}
-			}
-		}
-		if (!$authorize){
-			$this->unauthorized($request);
-		}
-	}
-
 
-	/**
-	 * When the process logic determines that the user is not
-	 * authorized for this service, then forward the user to
-	 * an 403 unauthorized page.
-	 *
-	 * Separated this code into its own method so that child
-	 * classes can override it and change the action. Forward
-	 * thinking in case a "chained" ACL is needed, more complex
-	 * permission logic.
-	 *
-	 * @param array $request
-	 */
-	protected function unauthorized(&$request) {
-		// Save state and redirect to 403 page
-		$id = SimpleSAML_Auth_State::saveState($request,
-			'authorize:Authorize');
-		$url = SimpleSAML\Module::getModuleURL(
-			'authorize/authorize_403.php');
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-	}
+class Authorize extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Flag to deny/unauthorize the user a attribute filter IS found
+     *
+     * @var bool
+     */
+    protected $deny = false;
+
+    /**
+     * Flag to turn the REGEX pattern matching on or off
+     *
+     * @var bool
+     */
+    protected $regex = true;
+
+    /**
+     * Array of valid users. Each element is a regular expression. You should
+     * user \ to escape special chars, like '.' etc.
+     *
+     */
+    protected $valid_attribute_values = [];
+
+    /**
+     * Initialize this filter.
+     * Validate configuration parameters.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        // Check for the deny option, get it and remove it
+        // Must be bool specifically, if not, it might be for a attrib filter below
+        if (isset($config['deny']) && is_bool($config['deny'])) {
+            $this->deny = $config['deny'];
+            unset($config['deny']);
+        }
+
+        // Check for the regex option, get it and remove it
+        // Must be bool specifically, if not, it might be for a attrib filter below
+        if (isset($config['regex']) && is_bool($config['regex'])) {
+            $this->regex = $config['regex'];
+            unset($config['regex']);
+        }
+
+        foreach ($config as $attribute => $values) {
+            if (is_string($values)) {
+                $values = [$values];
+            }
+            if (!is_array($values)) {
+                throw new \Exception(
+                    'Filter Authorize: Attribute values is neither string nor array: '.var_export($attribute, true)
+                );
+            }
+            foreach ($values as $value) {
+                if (!is_string($value)) {
+                    throw new \Exception(
+                        'Filter Authorize: Each value should be a string for attribute: '.var_export($attribute, true).
+                            ' value: '.var_export($value, true).' Config is: '.var_export($config, true)
+                    );
+                }
+            }
+            $this->valid_attribute_values[$attribute] = $values;
+        }
+    }
+
+    /**
+     * Apply filter to validate attributes.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        $authorize = $this->deny;
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        $attributes = &$request['Attributes'];
+
+        foreach ($this->valid_attribute_values as $name => $patterns) {
+            if (array_key_exists($name, $attributes)) {
+                foreach ($patterns as $pattern) {
+                    $values = $attributes[$name];
+                    if (!is_array($values)) {
+                        $values = [$values];
+                    }
+                    foreach ($values as $value) {
+                        if ($this->regex) {
+                            $matched = preg_match($pattern, $value);
+                        } else {
+                            $matched = ($value == $pattern);
+                        }
+                        if ($matched) {
+                            $authorize = ($this->deny ? false : true);
+                            break 3;
+                        }
+                    }
+                }
+            }
+        }
+        if (!$authorize) {
+            $this->unauthorized($request);
+        }
+    }
+
+    /**
+     * When the process logic determines that the user is not
+     * authorized for this service, then forward the user to
+     * an 403 unauthorized page.
+     *
+     * Separated this code into its own method so that child
+     * classes can override it and change the action. Forward
+     * thinking in case a "chained" ACL is needed, more complex
+     * permission logic.
+     *
+     * @param array $request
+     */
+    protected function unauthorized(&$request)
+    {
+        // Save state and redirect to 403 page
+        $id = \SimpleSAML\Auth\State::saveState($request, 'authorize:Authorize');
+        $url = \SimpleSAML\Module::getModuleURL('authorize/authorize_403.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+    }
 }
diff --git a/modules/authorize/templates/authorize_403.php b/modules/authorize/templates/authorize_403.php
index ee16d96a78b2bffb5ef237aa4e95ada165042659..43ab320336655dd097035b51c6e6c092ab40efb6 100644
--- a/modules/authorize/templates/authorize_403.php
+++ b/modules/authorize/templates/authorize_403.php
@@ -14,15 +14,11 @@ $this->data['403_header'] = $this->t('{authorize:Authorize:403_header}');
 $this->data['403_text'] = $this->t('{authorize:Authorize:403_text}');
 
 $this->includeAtTemplateBase('includes/header.php');
-?>
-<h1><?php echo $this->data['403_header']; ?></h1>
-<p><?php echo $this->data['403_text']; ?></p>
-<?php
-if (isset($this->data['LogoutURL'])) {
-?>
-<p><a href="<?php echo htmlspecialchars($this->data['LogoutURL']); ?>"><?php echo $this->t('{status:logout}'); ?></a></p>
-<?php
+
+echo '<h1>'.$this->data['403_header'].'</h1>';
+echo '<p>'.$this->data['403_text'].'</p>';
+if (isset($this->data['logoutURL'])) {
+    echo '<p><a href="'.htmlspecialchars($this->data['logoutURL']).'">'.$this->t('{status:logout}').'</a></p>';
 }
-?>
-<?php
+
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/authorize/templates/authorize_403.twig b/modules/authorize/templates/authorize_403.twig
new file mode 100644
index 0000000000000000000000000000000000000000..3f6402e923d727e04a639f9a7c92686979574677
--- /dev/null
+++ b/modules/authorize/templates/authorize_403.twig
@@ -0,0 +1,11 @@
+{% extends "base.twig" %}
+
+{% block content %}
+  <h1>{{ '{authorize:Authorize:403_header}'|trans }}</h1>
+  <p>{{ '{authorize:Authorize:403_text}'|trans }}</p>
+  {% if logoutURL is defined %}
+  <p>
+      <a href="{{ logoutURL|escape('html') }}">{{ '{status:logout}'|trans }}</a>
+  </p>
+  {% endif %}
+{% endblock%}
diff --git a/modules/authorize/www/authorize_403.php b/modules/authorize/www/authorize_403.php
index f3f99b25fae874138c89671695dd62cfb7011a38..4598a66c83673aaaa32f6a2d731d9ae468898a0f 100644
--- a/modules/authorize/www/authorize_403.php
+++ b/modules/authorize/www/authorize_403.php
@@ -6,14 +6,17 @@
  */
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['StateId'], 'authorize:Authorize');
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['StateId'], 'authorize:Authorize');
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'authorize:authorize_403.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'authorize:authorize_403.php');
 if (isset($state['Source']['auth'])) {
-    $t->data['LogoutURL'] = SimpleSAML\Module::getModuleURL('core/authenticate.php', array('as' => $state['Source']['auth']))."&logout";
+    $t->data['logoutURL'] = \SimpleSAML\Module::getModuleURL(
+        'core/authenticate.php',
+        ['as' => $state['Source']['auth']]
+    )."&logout";
 }
 header('HTTP/1.0 403 Forbidden');
 $t->show();
diff --git a/modules/authtwitter/lib/Auth/Source/Twitter.php b/modules/authtwitter/lib/Auth/Source/Twitter.php
index 2b5d68d9328aa4dacbe5ec64e0ee191b54539da9..19ff725800132cef6758cdaf9366a9b1a96f0f35 100644
--- a/modules/authtwitter/lib/Auth/Source/Twitter.php
+++ b/modules/authtwitter/lib/Auth/Source/Twitter.php
@@ -1,6 +1,8 @@
 <?php
 
-require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/libextinc/OAuth.php');
+namespace SimpleSAML\Module\authtwitter\Auth\Source;
+
+require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))).'/oauth/libextinc/OAuth.php');
 
 /**
  * Authenticate using Twitter.
@@ -8,22 +10,23 @@ require_once(dirname(dirname(dirname(dirname(dirname(__FILE__))))) . '/oauth/lib
  * @author Andreas Ă…kre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_authtwitter_Auth_Source_Twitter extends SimpleSAML_Auth_Source
+
+class Twitter extends \SimpleSAML\Auth\Source
 {
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGE_INIT = 'twitter:init';
+    /**
+     * The string used to identify our states.
+     */
+    const STAGE_INIT = 'twitter:init';
 
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'twitter:AuthId';
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = 'twitter:AuthId';
 
     /**
      * @var string
      */
-	private $key;
+    private $key;
 
     /**
      * @var string
@@ -33,117 +36,128 @@ class sspmod_authtwitter_Auth_Source_Twitter extends SimpleSAML_Auth_Source
     /**
      * @var bool
      */
-	private $force_login;
+    private $force_login;
 
     /**
      * @var bool
      */
     private $include_email;
 
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config)
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
     {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
+        assert(is_array($info));
+        assert(is_array($config));
 
-		$configObject = SimpleSAML_Configuration::loadFromArray($config, 'authsources[' . var_export($this->authId, true) . ']');
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
 
-		$this->key = $configObject->getString('key');
-		$this->secret = $configObject->getString('secret');
-		$this->force_login = $configObject->getBoolean('force_login', false);
-		$this->include_email = $configObject->getBoolean('include_email', false);
-	}
+        $configObject = \SimpleSAML\Configuration::loadFromArray(
+            $config,
+            'authsources['.var_export($this->authId, true).']'
+        );
 
+        $this->key = $configObject->getString('key');
+        $this->secret = $configObject->getString('secret');
+        $this->force_login = $configObject->getBoolean('force_login', false);
+        $this->include_email = $configObject->getBoolean('include_email', false);
+    }
 
-	/**
-	 * Log-in using Twitter platform
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state)
+    /**
+     * Log-in using Twitter platform
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
     {
-		assert(is_array($state));
-
-		// We are going to need the authId in order to retrieve this authentication source later
-		$state[self::AUTHID] = $this->authId;
-		
-		$stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-		
-		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
-		// Get the request token
-		$linkback = SimpleSAML\Module::getModuleURL('authtwitter/linkback.php', array('AuthState' => $stateID));
-		$requestToken = $consumer->getRequestToken('https://api.twitter.com/oauth/request_token', array('oauth_callback' => $linkback));
-		SimpleSAML\Logger::debug("Got a request token from the OAuth service provider [" .
-			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
-
-		$state['authtwitter:authdata:requestToken'] = $requestToken;
-		SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-
-		// Authorize the request token
-		$url = 'https://api.twitter.com/oauth/authenticate';
-		if ($this->force_login) {
-			$url = \SimpleSAML\Utils\HTTP::addURLParameters($url, array('force_login' => 'true'));
-		}
-		$consumer->getAuthorizeRequest($url, $requestToken);
-	}
-	
-	
-	public function finalStep(&$state)
+        assert(is_array($state));
+
+        // We are going to need the authId in order to retrieve this authentication source later
+        $state[self::AUTHID] = $this->authId;
+
+        $stateID = \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
+
+        $consumer = new \SimpleSAML\Module\oauth\Consumer($this->key, $this->secret);
+        // Get the request token
+        $linkback = \SimpleSAML\Module::getModuleURL('authtwitter/linkback.php', ['AuthState' => $stateID]);
+        $requestToken = $consumer->getRequestToken(
+            'https://api.twitter.com/oauth/request_token',
+            ['oauth_callback' => $linkback]
+        );
+        \SimpleSAML\Logger::debug("Got a request token from the OAuth service provider [".
+            $requestToken->key."] with the secret [".$requestToken->secret."]");
+
+        $state['authtwitter:authdata:requestToken'] = $requestToken;
+        \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
+
+        // Authorize the request token
+        $url = 'https://api.twitter.com/oauth/authenticate';
+        if ($this->force_login) {
+            $url = \SimpleSAML\Utils\HTTP::addURLParameters($url, ['force_login' => 'true']);
+        }
+        $consumer->getAuthorizeRequest($url, $requestToken);
+    }
+
+    public function finalStep(&$state)
     {
-		$requestToken = $state['authtwitter:authdata:requestToken'];
-		$parameters = array();
-
-		if (!isset($_REQUEST['oauth_token'])) {
-			throw new SimpleSAML_Error_BadRequest("Missing oauth_token parameter.");
-		}
-		if ($requestToken->key !== (string)$_REQUEST['oauth_token']) {
-			throw new SimpleSAML_Error_BadRequest("Invalid oauth_token parameter.");
-		}
-
-		if (!isset($_REQUEST['oauth_verifier'])) {
-			throw new SimpleSAML_Error_BadRequest("Missing oauth_verifier parameter.");
-		}
-		$parameters['oauth_verifier'] = (string)$_REQUEST['oauth_verifier'];
-		
-		$consumer = new sspmod_oauth_Consumer($this->key, $this->secret);
-		
-		SimpleSAML\Logger::debug("oauth: Using this request token [" .
-			$requestToken->key . "] with the secret [" . $requestToken->secret . "]");
-
-		// Replace the request token with an access token
-		$accessToken = $consumer->getAccessToken('https://api.twitter.com/oauth/access_token', $requestToken, $parameters);
-		SimpleSAML\Logger::debug("Got an access token from the OAuth service provider [" .
-			$accessToken->key . "] with the secret [" . $accessToken->secret . "]");
-
-		$verify_credentials_url = 'https://api.twitter.com/1.1/account/verify_credentials.json';
-		if ($this->include_email) {
-			$verify_credentials_url = $verify_credentials_url . '?include_email=true';
-		}
-		$userdata = $consumer->getUserInfo($verify_credentials_url, $accessToken);
-		
-		if (!isset($userdata['id_str']) || !isset($userdata['screen_name'])) {
-			throw new SimpleSAML_Error_AuthSource($this->authId, 'Authentication error: id_str and screen_name not set.');
-		}
-
-		$attributes = array();
-		foreach ($userdata as $key => $value) {
-			if (is_string($value)) {
-				$attributes['twitter.' . $key] = array((string)$value);
+        $requestToken = $state['authtwitter:authdata:requestToken'];
+        $parameters = [];
+
+        if (!isset($_REQUEST['oauth_token'])) {
+            throw new \SimpleSAML\Error\BadRequest("Missing oauth_token parameter.");
+        }
+        if ($requestToken->key !== (string) $_REQUEST['oauth_token']) {
+            throw new \SimpleSAML\Error\BadRequest("Invalid oauth_token parameter.");
+        }
+
+        if (!isset($_REQUEST['oauth_verifier'])) {
+            throw new \SimpleSAML\Error\BadRequest("Missing oauth_verifier parameter.");
+        }
+        $parameters['oauth_verifier'] = (string) $_REQUEST['oauth_verifier'];
+
+        $consumer = new \SimpleSAML\Module\oauth\Consumer($this->key, $this->secret);
+
+        \SimpleSAML\Logger::debug("oauth: Using this request token [".
+            $requestToken->key."] with the secret [".$requestToken->secret."]");
+
+        // Replace the request token with an access token
+        $accessToken = $consumer->getAccessToken(
+            'https://api.twitter.com/oauth/access_token',
+            $requestToken,
+            $parameters
+        );
+        \SimpleSAML\Logger::debug("Got an access token from the OAuth service provider [".
+            $accessToken->key."] with the secret [".$accessToken->secret."]");
+
+        $verify_credentials_url = 'https://api.twitter.com/1.1/account/verify_credentials.json';
+        if ($this->include_email) {
+            $verify_credentials_url = $verify_credentials_url.'?include_email=true';
+        }
+        $userdata = $consumer->getUserInfo($verify_credentials_url, $accessToken);
+
+        if (!isset($userdata['id_str']) || !isset($userdata['screen_name'])) {
+            throw new \SimpleSAML\Error\AuthSource(
+                $this->authId,
+                'Authentication error: id_str and screen_name not set.'
+            );
+        }
+
+        $attributes = [];
+        foreach ($userdata as $key => $value) {
+            if (is_string($value)) {
+                $attributes['twitter.'.$key] = [(string) $value];
             }
-		}
-		
-		$attributes['twitter_at_screen_name'] = array('@' . $userdata['screen_name']);
-		$attributes['twitter_screen_n_realm'] = array($userdata['screen_name'] . '@twitter.com');
-		$attributes['twitter_targetedID'] = array('http://twitter.com!' . $userdata['id_str']);
-			
-		$state['Attributes'] = $attributes;
-	}
+        }
+
+        $attributes['twitter_at_screen_name'] = ['@'.$userdata['screen_name']];
+        $attributes['twitter_screen_n_realm'] = [$userdata['screen_name'].'@twitter.com'];
+        $attributes['twitter_targetedID'] = ['http://twitter.com!'.$userdata['id_str']];
+
+        $state['Attributes'] = $attributes;
+    }
 }
diff --git a/modules/authtwitter/www/linkback.php b/modules/authtwitter/www/linkback.php
index 2886f8d9aea04f9565d6e1082a049c7db03bcc3c..cbeed68a7be8028ae0e217cadb15d199948b56af 100644
--- a/modules/authtwitter/www/linkback.php
+++ b/modules/authtwitter/www/linkback.php
@@ -5,31 +5,40 @@
  */
 
 if (!array_key_exists('AuthState', $_REQUEST) || empty($_REQUEST['AuthState'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing state parameter on twitter linkback endpoint.');
+    throw new \SimpleSAML\Error\BadRequest('Missing state parameter on twitter linkback endpoint.');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], sspmod_authtwitter_Auth_Source_Twitter::STAGE_INIT);
+$state = \SimpleSAML\Auth\State::loadState(
+    $_REQUEST['AuthState'],
+    \SimpleSAML\Module\authtwitter\Auth\Source\Twitter::STAGE_INIT
+);
 
 // Find authentication source
-if (!array_key_exists(sspmod_authtwitter_Auth_Source_Twitter::AUTHID, $state)) {
-	throw new SimpleSAML_Error_BadRequest('No data in state for ' . sspmod_authtwitter_Auth_Source_Twitter::AUTHID);
+if (!array_key_exists(\SimpleSAML\Module\authtwitter\Auth\Source\Twitter::AUTHID, $state)) {
+    throw new \SimpleSAML\Error\BadRequest(
+        'No data in state for '.\SimpleSAML\Module\authtwitter\Auth\Source\Twitter::AUTHID
+    );
 }
-$sourceId = $state[sspmod_authtwitter_Auth_Source_Twitter::AUTHID];
+$sourceId = $state[\SimpleSAML\Module\authtwitter\Auth\Source\Twitter::AUTHID];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new SimpleSAML_Error_BadRequest('Could not find authentication source with id ' . var_export($sourceId, TRUE));
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new \SimpleSAML\Error\BadRequest(
+        'Could not find authentication source with id '.var_export($sourceId, true)
+    );
 }
 
 try {
-	if (array_key_exists('denied', $_REQUEST)) {
-		throw new SimpleSAML_Error_UserAborted();
-	}
-
-	$source->finalStep($state);
-} catch (SimpleSAML_Error_Exception $e) {
-	SimpleSAML_Auth_State::throwException($state, $e);
-} catch (Exception $e) {
-	SimpleSAML_Auth_State::throwException($state, new SimpleSAML_Error_AuthSource($sourceId, 'Error on authtwitter linkback endpoint.', $e));
+    if (array_key_exists('denied', $_REQUEST)) {
+        throw new \SimpleSAML\Error\UserAborted();
+    }
+    $source->finalStep($state);
+} catch (\SimpleSAML\Error\Exception $e) {
+    \SimpleSAML\Auth\State::throwException($state, $e);
+} catch (\Exception $e) {
+    \SimpleSAML\Auth\State::throwException(
+        $state,
+        new \SimpleSAML\Error\AuthSource($sourceId, 'Error on authtwitter linkback endpoint.', $e)
+    );
 }
 
-SimpleSAML_Auth_Source::completeAuth($state);
+\SimpleSAML\Auth\Source::completeAuth($state);
diff --git a/modules/authwindowslive/docs/windowsliveid.md b/modules/authwindowslive/docs/windowsliveid.md
index 390edae2931bffadf1a955b68962817d1658a32d..b80116cf3a7ad20fc55ad1e0ceacb6999e438693 100644
--- a/modules/authwindowslive/docs/windowsliveid.md
+++ b/modules/authwindowslive/docs/windowsliveid.md
@@ -1,12 +1,14 @@
 Using the Windows Live ID authentication source with SimpleSAMLphp
 ==================================================================
+This module works around the limitation in Microsoft Online/Azure OIDC implementation of not supplying the OIDC userinfo endpoint.
+Microsoft explains the omission by suggesting that the Graph API can produce anything userinfo would have brought, in place.
 
 Remember to configure `authsources.php`, with both your Client ID and Secret key.
 
 To get an API key and a secret, register the application at:
 
- * <http://msdn.microsoft.com/en-us/library/ff751474.aspx>
- * <https://manage.dev.live.com>
+ * <https://msdn.microsoft.com/en-us/library/ff751474.aspx>
+ * <https://apps.dev.microsoft.com/>
 
 ## Testing authentication
 
diff --git a/modules/authwindowslive/lib/Auth/Source/LiveID.php b/modules/authwindowslive/lib/Auth/Source/LiveID.php
index 39fbfd1595f1762391885cd0b8adf0a80db6d4a4..3f4dc5446d3cd64b7020d66f2fd4e821736a2d58 100644
--- a/modules/authwindowslive/lib/Auth/Source/LiveID.php
+++ b/modules/authwindowslive/lib/Auth/Source/LiveID.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\authwindowslive\Auth\Source;
+
 /**
  * Authenticate using LiveID.
  *
@@ -7,9 +9,8 @@
  * @author Guy Halse, TENET.
  * @package SimpleSAMLphp
  */
-class sspmod_authwindowslive_Auth_Source_LiveID extends SimpleSAML_Auth_Source
+class LiveID extends \SimpleSAML\Auth\Source
 {
-
     /**
      * The string used to identify our states.
      */
@@ -23,14 +24,13 @@ class sspmod_authwindowslive_Auth_Source_LiveID extends SimpleSAML_Auth_Source
     private $key;
     private $secret;
 
-
     /**
      * Constructor for this authentication source.
      *
      * @param array $info  Information about this authentication source.
      * @param array $config  Configuration.
      *
-     * @throws Exception In case of misconfiguration.
+     * @throws \Exception In case of misconfiguration.
      */
     public function __construct($info, $config)
     {
@@ -41,19 +41,18 @@ class sspmod_authwindowslive_Auth_Source_LiveID extends SimpleSAML_Auth_Source
         parent::__construct($info, $config);
 
         if (!array_key_exists('key', $config)) {
-            throw new Exception('LiveID authentication source is not properly configured: missing [key]');
+            throw new \Exception('LiveID authentication source is not properly configured: missing [key]');
         }
 
         $this->key = $config['key'];
 
         if (!array_key_exists('secret', $config)) {
-            throw new Exception('LiveID authentication source is not properly configured: missing [secret]');
+            throw new \Exception('LiveID authentication source is not properly configured: missing [secret]');
         }
 
         $this->secret = $config['secret'];
     }
 
-
     /**
      * Log-in using LiveID platform
      *
@@ -66,54 +65,53 @@ class sspmod_authwindowslive_Auth_Source_LiveID extends SimpleSAML_Auth_Source
         // we are going to need the authId in order to retrieve this authentication source later
         $state[self::AUTHID] = $this->authId;
 
-        $stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
+        $stateID = \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
 
-        SimpleSAML\Logger::debug('authwindowslive auth state id = ' . $stateID);
+        \SimpleSAML\Logger::debug('authwindowslive auth state id = '.$stateID);
 
         // authenticate the user
         // documentation at:
         // https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-protocols-oauth-code/
-        $authorizeURL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'
-                . '?client_id=' . $this->key
-                . '&response_type=code'
-                . '&response_mode=query'
-                . '&redirect_uri=' . urlencode(SimpleSAML\Module::getModuleUrl('authwindowslive') . '/linkback.php')
-                . '&state=' . urlencode($stateID)
-                . '&scope=' . urlencode('openid https://graph.microsoft.com/user.read')
+        $authorizeURL = 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize'.
+            '?client_id='.$this->key.
+            '&response_type=code'.
+            '&response_mode=query'.
+            '&redirect_uri='.urlencode(\SimpleSAML\Module::getModuleURL('authwindowslive').'/linkback.php').
+            '&state='.urlencode($stateID).
+            '&scope='.urlencode('openid https://graph.microsoft.com/user.read')
         ;
 
         \SimpleSAML\Utils\HTTP::redirectTrustedURL($authorizeURL);
     }
 
-
     /**
      * @param $state
      *
-     * @throws Exception
+     * @throws \Exception
      */
     public function finalStep(&$state)
     {
-        SimpleSAML\Logger::debug(
+        \SimpleSAML\Logger::debug(
             "authwindowslive oauth: Using this verification code [".$state['authwindowslive:verification_code']."]"
         );
 
         // retrieve Access Token
         // documentation at:
         // https://azure.microsoft.com/en-us/documentation/articles/active-directory-v2-protocols-oauth-code/#request-an-access-token
-        $postData = 'client_id=' . urlencode($this->key)
-                . '&client_secret=' . urlencode($this->secret)
-                . '&scope=' . urlencode('https://graph.microsoft.com/user.read')
-                . '&grant_type=authorization_code'
-                . '&redirect_uri=' . urlencode(SimpleSAML\Module::getModuleUrl('authwindowslive') . '/linkback.php')
-                . '&code=' . urlencode($state['authwindowslive:verification_code']);
-
-        $context = array(
-            'http' => array(
-                'method'  => 'POST',
-                'header'  => 'Content-type: application/x-www-form-urlencoded',
+        $postData = 'client_id='.urlencode($this->key).
+            '&client_secret='.urlencode($this->secret).
+            '&scope='.urlencode('https://graph.microsoft.com/user.read').
+            '&grant_type=authorization_code'.
+            '&redirect_uri='.urlencode(\SimpleSAML\Module::getModuleURL('authwindowslive').'/linkback.php').
+            '&code='.urlencode($state['authwindowslive:verification_code']);
+
+        $context = [
+            'http' => [
+                'method' => 'POST',
+                'header' => 'Content-type: application/x-www-form-urlencoded',
                 'content' => $postData,
-            ),
-        );
+            ],
+        ];
 
         $result = \SimpleSAML\Utils\HTTP::fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', $context);
 
@@ -121,41 +119,43 @@ class sspmod_authwindowslive_Auth_Source_LiveID extends SimpleSAML_Auth_Source
 
         // error checking of $response to make sure we can proceed
         if (!array_key_exists('access_token', $response)) {
-            throw new Exception(
+            throw new \Exception(
                 '['.$response['error'].'] '.$response['error_description'].
-                "\r\nNo access_token returned - cannot proceed\r\n" . implode(', ', $response['error_codes'])
+                "\r\nNo access_token returned - cannot proceed\r\n".implode(', ', $response['error_codes'])
             );
         }
 
-        SimpleSAML\Logger::debug(
+        \SimpleSAML\Logger::debug(
             "authwindowslive: Got an access token from the OAuth service provider [".$response['access_token']."]"
         );
 
         // documentation at: http://graph.microsoft.io/en-us/docs/overview/call_api
-        $opts = array('http' => array('header' => "Accept: application/json\r\nAuthorization: Bearer ".
-                        $response['access_token']."\r\n"));
+        $opts = [
+            'http' => ['header' => "Accept: application/json\r\nAuthorization: Bearer ".
+                $response['access_token']."\r\n"]
+        ];
         $data = \SimpleSAML\Utils\HTTP::fetch('https://graph.microsoft.com/v1.0/me', $opts);
         $userdata = json_decode($data, true);
 
         // this is the simplest case
         if (!array_key_exists('@odata.context', $userdata) || array_key_exists('error', $userdata)) {
-            throw new Exception(
+            throw new \Exception(
                 'Unable to retrieve userdata from Microsoft Graph ['.$userdata['error']['code'].'] '.
                 $userdata['error']['message']
             );
         }
-        $attributes = array();
-        $attributes['windowslive_targetedID'] = array(
+        $attributes = [];
+        $attributes['windowslive_targetedID'] = [
             'https://graph.microsoft.com!'.(!empty($userdata['id']) ? $userdata['id'] : 'unknown')
-        );
+        ];
         foreach ($userdata as $key => $value) {
             if (is_string($value)) {
-                $attributes['windowslive.' . $key] = array((string)$value);
+                $attributes['windowslive.'.$key] = [(string) $value];
             }
         }
 
 
-        SimpleSAML\Logger::debug('LiveID Returned Attributes: '. implode(", ", array_keys($attributes)));
+        \SimpleSAML\Logger::debug('LiveID Returned Attributes: '.implode(", ", array_keys($attributes)));
 
         $state['Attributes'] = $attributes;
     }
diff --git a/modules/authwindowslive/www/linkback.php b/modules/authwindowslive/www/linkback.php
index e6b1ea2c3b50a8b06e60c6dc8875746dc2e94ed2..758bdd215f6b490ef11b8b554e1cf2914929595b 100644
--- a/modules/authwindowslive/www/linkback.php
+++ b/modules/authwindowslive/www/linkback.php
@@ -5,9 +5,12 @@
  */
 
 if (!array_key_exists('state', $_REQUEST)) {
-    throw new Exception('Lost OAuth Client State');
+    throw new \Exception('Lost OAuth Client State');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['state'], sspmod_authwindowslive_Auth_Source_LiveID::STAGE_INIT);
+$state = \SimpleSAML\Auth\State::loadState(
+    $_REQUEST['state'],
+    \SimpleSAML\Module\authwindowslive\Auth\Source\LiveID::STAGE_INIT
+);
 
 // http://msdn.microsoft.com/en-us/library/ff749771.aspx
 if (array_key_exists('code', $_REQUEST)) {
@@ -24,23 +27,23 @@ if (array_key_exists('code', $_REQUEST)) {
     // to preserve support for this, so this is left in as a placeholder.
     // redirect them to their original page so they can choose another auth mechanism
     if ($_REQUEST['error'] === 'user_denied') {
-        $e = new SimpleSAML_Error_UserAborted();
-        SimpleSAML_Auth_State::throwException($state, $e);
+        $e = new \SimpleSAML\Error\UserAborted();
+        \SimpleSAML\Auth\State::throwException($state, $e);
     }
 
     // error
-    throw new Exception('Authentication failed: ['.$_REQUEST['error'].'] '.$_REQUEST['error_description']);
+    throw new \Exception('Authentication failed: ['.$_REQUEST['error'].'] '.$_REQUEST['error_description']);
 }
 
 // find authentication source
-assert(array_key_exists(sspmod_authwindowslive_Auth_Source_LiveID::AUTHID, $state));
-$sourceId = $state[sspmod_authwindowslive_Auth_Source_LiveID::AUTHID];
+assert(array_key_exists(\SimpleSAML\Module\authwindowslive\Auth\Source\LiveID::AUTHID, $state));
+$sourceId = $state[\SimpleSAML\Module\authwindowslive\Auth\Source\LiveID::AUTHID];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
 if ($source === null) {
-    throw new Exception('Could not find authentication source with id '.$sourceId);
+    throw new \Exception('Could not find authentication source with id '.$sourceId);
 }
 
 $source->finalStep($state);
 
-SimpleSAML_Auth_Source::completeAuth($state);
+\SimpleSAML\Auth\Source::completeAuth($state);
diff --git a/modules/cas/lib/Auth/Source/CAS.php b/modules/cas/lib/Auth/Source/CAS.php
index 9d7a030aca5c00e9bd39ce320cc6b60e3f2ab71c..08f153c130f4a0ae2b545ba3e950f369f06f9d64 100644
--- a/modules/cas/lib/Auth/Source/CAS.php
+++ b/modules/cas/lib/Auth/Source/CAS.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\cas\Auth\Source;
+
 /**
  * Authenticate using CAS.
  *
@@ -9,37 +11,38 @@
  * @package SimpleSAMLphp
  */
 
-class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
+class CAS extends \SimpleSAML\Auth\Source
 {
     /**
      * The string used to identify our states.
      */
-    const STAGE_INIT = 'sspmod_cas_Auth_Source_CAS.state';
+    const STAGE_INIT = '\SimpleSAML\Module\cas\Auth\Source\CAS.state';
 
     /**
      * The key of the AuthId field in the state.
      */
-    const AUTHID = 'sspmod_cas_Auth_Source_CAS.AuthId';
+    const AUTHID = '\SimpleSAML\Module\cas\Auth\Source\CAS.AuthId';
 
     /**
      * @var array with ldap configuration
      */
-    private $_ldapConfig;
+    private $ldapConfig;
 
     /**
      * @var cas configuration
      */
-    private $_casConfig;
+    private $casConfig;
 
     /**
-     * @var cas chosen validation method
+     * @var string cas chosen validation method
      */
 
-    private $_validationMethod;
+    private $validationMethod;
+
     /**
-     * @var cas login method
+     * @var string cas login method
      */
-    private $_loginMethod;
+    private $loginMethod;
 
     /**
      * Constructor for this authentication source.
@@ -56,28 +59,28 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
         parent::__construct($info, $config);
 
         if (!array_key_exists('cas', $config)) {
-            throw new Exception('cas authentication source is not properly configured: missing [cas]');
+            throw new \Exception('cas authentication source is not properly configured: missing [cas]');
         }
 
         if (!array_key_exists('ldap', $config)) {
-            throw new Exception('ldap authentication source is not properly configured: missing [ldap]');
+            throw new \Exception('ldap authentication source is not properly configured: missing [ldap]');
         }
 
-        $this->_casConfig = $config['cas'];
-        $this->_ldapConfig = $config['ldap'];
+        $this->casConfig = $config['cas'];
+        $this->ldapConfig = $config['ldap'];
 
-        if (isset($this->_casConfig['serviceValidate'])) {
-            $this->_validationMethod = 'serviceValidate';
-        } elseif(isset($this->_casConfig['validate'])) {
-            $this->_validationMethod = 'validate';
+        if (isset($this->casConfig['serviceValidate'])) {
+            $this->validationMethod = 'serviceValidate';
+        } elseif (isset($this->casConfig['validate'])) {
+            $this->validationMethod = 'validate';
         } else {
-            throw new Exception("validate or serviceValidate not specified");
+            throw new \Exception("validate or serviceValidate not specified");
         }
 
-        if (isset($this->_casConfig['login'])) {
-            $this->_loginMethod =  $this->_casConfig['login'];
+        if (isset($this->casConfig['login'])) {
+            $this->loginMethod = $this->casConfig['login'];
         } else {
-            throw new Exception("cas login URL not specified");
+            throw new \Exception("cas login URL not specified");
         }
     }
 
@@ -88,21 +91,21 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
      * @param string $ticket
      * @param string $service
      *
-     * @return list username and attributes
+     * @return array username and attributes
      */
     private function casValidate($ticket, $service)
     {
-        $url = \SimpleSAML\Utils\HTTP::addURLParameters($this->_casConfig['validate'], array(
+        $url = \SimpleSAML\Utils\HTTP::addURLParameters($this->casConfig['validate'], [
             'ticket' => $ticket,
             'service' => $service,
-        ));
+        ]);
         $result = \SimpleSAML\Utils\HTTP::fetch($url);
-        $res = preg_split("/\r?\n/",$result);
+        $res = preg_split("/\r?\n/", $result);
 
         if (strcmp($res[0], "yes") == 0) {
-            return array($res[1], array());
+            return [$res[1], []];
         } else {
-            throw new Exception("Failed to validate CAS service ticket: $ticket");
+            throw new \Exception("Failed to validate CAS service ticket: $ticket");
         }
     }
 
@@ -113,29 +116,30 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
      * @param string $ticket
      * @param string $service
      *
-     * @return list username and attributes
+     * @return array username and attributes
      */
     private function casServiceValidate($ticket, $service)
     {
         $url = \SimpleSAML\Utils\HTTP::addURLParameters(
-            $this->_casConfig['serviceValidate'],
-            array(
+            $this->casConfig['serviceValidate'],
+            [
                 'ticket' => $ticket,
                 'service' => $service,
-            )
+            ]
         );
         $result = \SimpleSAML\Utils\HTTP::fetch($url);
 
         $dom = \SAML2\DOMDocumentFactory::fromString($result);
-        $xPath = new DOMXpath($dom);
+        $xPath = new \DOMXpath($dom);
         $xPath->registerNamespace("cas", 'http://www.yale.edu/tp/cas');
         $success = $xPath->query("/cas:serviceResponse/cas:authenticationSuccess/cas:user");
         if ($success->length == 0) {
             $failure = $xPath->evaluate("/cas:serviceResponse/cas:authenticationFailure");
-            throw new Exception("Error when validating CAS service ticket: " . $failure->item(0)->textContent);
+            throw new \Exception("Error when validating CAS service ticket: ".$failure->item(0)->textContent);
         } else {
-            $attributes = array();
-            if ($casattributes = $this->_casConfig['attributes']) { # some has attributes in the xml - attributes is a list of XPath expressions to get them
+            $attributes = [];
+            if ($casattributes = $this->casConfig['attributes']) {
+                // Some has attributes in the xml - attributes is a list of XPath expressions to get them
                 foreach ($casattributes as $name => $query) {
                     $attrs = $xPath->query($query);
                     foreach ($attrs as $attrvalue) {
@@ -145,7 +149,7 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
             }
             $casusername = $success->item(0)->textContent;
 
-            return array($casusername, $attributes);
+            return [$casusername, $attributes];
         }
     }
 
@@ -156,45 +160,52 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
      *
      * @param string $ticket
      * @param string $service
-     * @return list username and attributes
+     * @return array username and attributes
      */
     protected function casValidation($ticket, $service)
     {
-        switch ($this->_validationMethod)
-        {
+        switch ($this->validationMethod) {
             case 'validate':
                 return  $this->casValidate($ticket, $service);
-                break;
             case 'serviceValidate':
                 return $this->casServiceValidate($ticket, $service);
-                break;
             default:
-                throw new Exception("validate or serviceValidate not specified");
+                throw new \Exception("validate or serviceValidate not specified");
         }
     }
 
 
     /**
      * Called by linkback, to finish validate/ finish logging in.
-     * @param state $state
-     * @return list username, casattributes/ldap attributes
+     * @param array $state
      */
     public function finalStep(&$state)
     {
         $ticket = $state['cas:ticket'];
-        $stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
-        $service =  SimpleSAML\Module::getModuleURL('cas/linkback.php', array('stateID' => $stateID));
+        $stateID = \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
+        $service = \SimpleSAML\Module::getModuleURL('cas/linkback.php', ['stateID' => $stateID]);
         list($username, $casattributes) = $this->casValidation($ticket, $service);
-        $ldapattributes = array();
+        $ldapattributes = [];
 
-        if ($this->_ldapConfig['servers']) {
-            $ldap = new SimpleSAML_Auth_LDAP($this->_ldapConfig['servers'], $this->_ldapConfig['enable_tls']);
-            $ldapattributes = $ldap->validate($this->_ldapConfig, $username);
+        $config = \SimpleSAML\Configuration::loadFromArray(
+            $this->ldapConfig,
+            'Authentication source '.var_export($this->authId, true)
+        );
+        if ($this->ldapConfig['servers']) {
+            $ldap = new \SimpleSAML\Auth\LDAP(
+                $config->getString('servers'),
+                $config->getBoolean('enable_tls', false),
+                $config->getBoolean('debug', false),
+                $config->getInteger('timeout', 0),
+                $config->getInteger('port', 389),
+                $config->getBoolean('referrals', true)
+            );
+            $ldapattributes = $ldap->validate($this->ldapConfig, $username);
         }
         $attributes = array_merge_recursive($casattributes, $ldapattributes);
         $state['Attributes'] = $attributes;
 
-        SimpleSAML_Auth_Source::completeAuth($state);
+        \SimpleSAML\Auth\Source::completeAuth($state);
     }
 
 
@@ -210,11 +221,11 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
         // We are going to need the authId in order to retrieve this authentication source later
         $state[self::AUTHID] = $this->authId;
 
-        $stateID = SimpleSAML_Auth_State::saveState($state, self::STAGE_INIT);
+        $stateID = \SimpleSAML\Auth\State::saveState($state, self::STAGE_INIT);
 
-        $serviceUrl = SimpleSAML\Module::getModuleURL('cas/linkback.php', array('stateID' => $stateID));
+        $serviceUrl = \SimpleSAML\Module::getModuleURL('cas/linkback.php', ['stateID' => $stateID]);
 
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($this->_loginMethod, array('service' => $serviceUrl));
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($this->loginMethod, ['service' => $serviceUrl]);
     }
 
 
@@ -234,9 +245,9 @@ class sspmod_cas_Auth_Source_CAS extends SimpleSAML_Auth_Source
     public function logout(&$state)
     {
         assert(is_array($state));
-        $logoutUrl = $this->_casConfig['logout'];
+        $logoutUrl = $this->casConfig['logout'];
 
-        SimpleSAML_Auth_State::deleteState($state);
+        \SimpleSAML\Auth\State::deleteState($state);
         // we want cas to log us out
         \SimpleSAML\Utils\HTTP::redirectTrustedURL($logoutUrl);
     }
diff --git a/modules/cas/www/linkback.php b/modules/cas/www/linkback.php
index a6ffa4971e5c7f28685ccdf82e9825b622462b11..366583c8a7e572099e66cfaad716faaa084f3788 100644
--- a/modules/cas/www/linkback.php
+++ b/modules/cas/www/linkback.php
@@ -5,24 +5,22 @@
  */
 
 if (!isset($_GET['stateID'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing stateID parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing stateID parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_GET['stateID'], sspmod_cas_Auth_Source_CAS::STAGE_INIT);
+$state = \SimpleSAML\Auth\State::loadState($_GET['stateID'], \SimpleSAML\Module\cas\Auth\Source\CAS::STAGE_INIT);
 
 if (!isset($_GET['ticket'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing ticket parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing ticket parameter.');
 }
-$state['cas:ticket'] = (string)$_GET['ticket'];
+$state['cas:ticket'] = (string) $_GET['ticket'];
 
 // Find authentication source
-assert(array_key_exists(sspmod_cas_Auth_Source_CAS::AUTHID, $state));
-$sourceId = $state[sspmod_cas_Auth_Source_CAS::AUTHID];
+assert(array_key_exists(\SimpleSAML\Module\cas\Auth\Source\CAS::AUTHID, $state));
+$sourceId = $state[\SimpleSAML\Module\cas\Auth\Source\CAS::AUTHID];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new \Exception('Could not find authentication source with id '.$sourceId);
 }
 
 $source->finalStep($state);
-
-
diff --git a/modules/casserver/config-templates/module_casserver.php b/modules/casserver/config-templates/module_casserver.php
deleted file mode 100644
index fab96fbbf4d3a5f6e3f6a65edcbd2d686c56b354..0000000000000000000000000000000000000000
--- a/modules/casserver/config-templates/module_casserver.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-/* 
- * Configuration for the module casserver.
- */
-
-$config = array (
-
-	'legal_service_urls' => array(
-		'http://test.feide.no/casclient',
-		'http://test.feide.no/cas2',
-	),
-
-	// Legal values: saml2, shib13
-	'auth' => 'saml2',
-	
-	'ticketcache' => 'ticketcache',
-
-	'attrname' => 'mail', // 'eduPersonPrincipalName',
-	#'attributes' => TRUE, // enable transfer of attributes
-	
-);
diff --git a/modules/casserver/default-disable b/modules/casserver/default-disable
deleted file mode 100644
index fa0bd82e2df7bd79d57593d35bc53c1f9d3ef71f..0000000000000000000000000000000000000000
--- a/modules/casserver/default-disable
+++ /dev/null
@@ -1,3 +0,0 @@
-This file indicates that the default state of this module
-is disabled. To enable, create a file named enable in the
-same directory as this file.
diff --git a/modules/casserver/www/cas.php b/modules/casserver/www/cas.php
deleted file mode 100644
index 5b9d16baddc11f77522d13488225eba77a7fe574..0000000000000000000000000000000000000000
--- a/modules/casserver/www/cas.php
+++ /dev/null
@@ -1,34 +0,0 @@
-<?php
-
-/*
- * Frontend for login.php, proxy.php, validate.php and serviceValidate.php. It allows them to be called
- * as cas.php/login, cas.php/validate and cas.php/serviceValidate and is meant for clients
- * like phpCAS which expects one configured prefix which it appends login, validate and 
- * serviceValidate to.
- * 
- * This version supports CAS proxying. As SSP controls the user session (TGT in CAS parlance)
- * and the CASServer as a backend/proxy server is not aware of termination of the session the Proxy-
- * Granting-Tickets (PGT) issued have a very short ttl - pt. 60 secs.
- *
- * ServiceTickets (SP) and ProxyTickets (PT) now have a 5 secs ttl.
- *
- * Proxyed services (targetService) shall be present in the legal_service_urls config.
- * 
- */
- 
- 
-$validFunctions = array(
-	'login' => 'login',
-	'proxy' => 'proxy',
-	'validate' => 'serviceValidate',
-	'serviceValidate' => 'serviceValidate',
-	'proxyValidate' => 'serviceValidate'
-);
-
-$function = substr($_SERVER['PATH_INFO'], 1);
-
-if (!isset($validFunctions[$function])) {
-	throw new SimpleSAML_Error_NotFound('Not a valid function for cas.php.');
-}
-
-include($validFunctions[$function].".php");
diff --git a/modules/casserver/www/login.php b/modules/casserver/www/login.php
deleted file mode 100644
index fd55f05eb8a3b11dd845c8335ea2f3d11350d492..0000000000000000000000000000000000000000
--- a/modules/casserver/www/login.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-require 'tickets.php';
-
-/*
- * Incoming parameters:
- *  service
- *  renew
- *  gateway
- *  
- */
-
-if (!array_key_exists('service', $_GET))
-	throw new Exception('Required URL query parameter [service] not provided. (CAS Server)');
-
-$service = $_GET['service'];
-
-$forceAuthn =isset($_GET['renew']) && $_GET['renew'];
-$isPassive = isset($_GET['gateway']) && $_GET['gateway'];
-
-$config = SimpleSAML_Configuration::getInstance();
-$casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
-
-$legal_service_urls = $casconfig->getValue('legal_service_urls');
-if (!checkServiceURL($service, $legal_service_urls))
-	throw new Exception('Service parameter provided to CAS server is not listed as a legal service: [service] = ' . $service);
-
-$auth = $casconfig->getValue('auth', 'saml2');
-if (!in_array($auth, array('saml2', 'shib13'), true))
- 	throw new Exception('CAS Service configured to use [auth] = ' . $auth . ' only [saml2,shib13] is legal.');
- 
-$as = new \SimpleSAML\Auth\Simple($auth);
-if (!$as->isAuthenticated()) {
-	$params = array(
-		'ForceAuthn' => $forceAuthn,
-		'isPassive' => $isPassive,
-	);
-	$as->login($params);
-}
-
-$attributes = $as->getAttributes();
-
-$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', '/tmp'));
-
-$ticket = str_replace( '_', 'ST-', SimpleSAML\Utils\Random::generateID() );
-storeTicket($ticket, $path, array('service' => $service,
-	'forceAuthn' => $forceAuthn,
-	'attributes' => $attributes,
-	'proxies' => array(),
-	'validbefore' => time() + 5));
-
-\SimpleSAML\Utils\HTTP::redirectTrustedURL(
-	\SimpleSAML\Utils\HTTP::addURLParameters($service,
-		array('ticket' => $ticket)
-	)
-);
\ No newline at end of file
diff --git a/modules/casserver/www/proxy.php b/modules/casserver/www/proxy.php
deleted file mode 100644
index 6fc14e4a31407db3d1adf22f0ec23b6684212336..0000000000000000000000000000000000000000
--- a/modules/casserver/www/proxy.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-require 'tickets.php';
-
-/*
- * Incoming parameters:
- *  targetService
- *  ptg
- *  
- */
-
-if (array_key_exists('targetService', $_GET)) {
-	$targetService = $_GET['targetService'];
-	$pgt = $_GET['pgt'];
-} else {
-	throw new Exception('Required URL query parameter [targetService] not provided. (CAS Server)');
-}
-
-$casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
-
-$legal_service_urls = $casconfig->getValue('legal_service_urls');
-
-if (!checkServiceURL($targetService, $legal_service_urls))
-	throw new Exception('Service parameter provided to CAS server is not listed as a legal service: [service] = ' . $service);
-
-$path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
-
-$ticket = retrieveTicket($pgt, $path, false);
-if ($ticket['validbefore'] > time()) {
-	$pt = str_replace( '_', 'PT-', SimpleSAML\Utils\Random::generateID() );
-	storeTicket($pt, $path, array(
-		'service' => $targetService,
-		'forceAuthn' => false,
-		'attributes' => $ticket['attributes'],
-		'proxies' => $ticket['proxies'],
-		'validbefore' => time() + 5)
-	);
-		
-print <<<eox
-<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
-    <cas:proxySuccess>
-        <cas:proxyTicket>$pt</cas:proxyTicket>
-    </cas:proxySuccess>
-</cas:serviceResponse>
-eox;
-} else {
-print <<<eox
-<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
-    <cas:proxyFailure code="INVALID_REQUEST">
-        Proxygranting ticket to old - ssp casserver only supports shortlived (30 secs) pgts.
-    </cas:proxyFailure>
-</cas:serviceResponse>
-eox;
-}
\ No newline at end of file
diff --git a/modules/casserver/www/serviceValidate.php b/modules/casserver/www/serviceValidate.php
deleted file mode 100644
index fd9ebc65a974ffeb2dd2348e438494e954027583..0000000000000000000000000000000000000000
--- a/modules/casserver/www/serviceValidate.php
+++ /dev/null
@@ -1,107 +0,0 @@
-<?php
-require('tickets.php');
-
-// set manually if called directly - ie not included from validate.php or cas.php
-if (!$function) {
-    $function = 'serviceValidate';
-}
-
-/*
- * Incoming parameters:
- *  service
- *  renew
- *  ticket
- *
- */
-if (array_key_exists('service', $_GET)) {
-    $service = $_GET['service'];
-    $ticket = $_GET['ticket'];
-    $forceAuthn = isset($_GET['renew']) && $_GET['renew'];
-} else { 
-    throw new Exception('Required URL query parameter [service] not provided. (CAS Server)');
-}
-
-try {
-    // Load SimpleSAMLphp, configuration and metadata
-    $casconfig = SimpleSAML_Configuration::getConfig('module_casserver.php');
-
-    $path = $casconfig->resolvePath($casconfig->getValue('ticketcache', 'ticketcache'));
-    $ticketcontent = retrieveTicket($ticket, $path);
-
-    $usernamefield = $casconfig->getValue('attrname', 'eduPersonPrincipalName');
-    $dosendattributes = $casconfig->getValue('attributes', false);
-
-    $attributes = $ticketcontent['attributes'];
-
-    $pgtiouxml = "";
-
-    if ($ticketcontent['service'] == $service
-            && $ticketcontent['forceAuthn'] == $forceAuthn
-            && array_key_exists($usernamefield, $attributes)
-            && $ticketcontent['validbefore'] > time()) {
-
-        if (isset($_GET['pgtUrl'])) {
-            $pgtUrl = $_GET['pgtUrl'];
-            $pgtiou = str_replace( '_', 'PGTIOU-', SimpleSAML\Utils\Random::generateID());
-            $pgt = str_replace( '_', 'PGT-', SimpleSAML\Utils\Random::generateID());
-            $content = array(
-                'attributes' => $attributes,
-                'forceAuthn' => false,
-                'proxies' => array_merge(array($service), $ticketcontent['proxies']),
-                'validbefore' => time() + 60);
-            \SimpleSAML\Utils\HTTP::fetch($pgtUrl . '?pgtIou=' . $pgtiou . '&pgtId=' . $pgt);
-            storeTicket($pgt, $path, $content);
-            $pgtiouxml = "\n<cas:proxyGrantingTicket>$pgtiou</cas:proxyGrantingTicket>\n";
-        }
-
-	$proxiesxml = join("\n", array_map(
-	    function($a) { return "<cas:proxy>$a</cas:proxy>"; },
-	    $ticketcontent['proxies']));
-	if ($proxiesxml) {
-	    $proxiesxml = "<cas:proxies>\n$proxiesxml\n</cas:proxies>\n";
-	}
-
-	returnResponse('YES', $function, $attributes[$usernamefield][0],
-            $dosendattributes ? $attributes : array(),
-            $pgtiouxml.$proxiesxml);
-    } else {
-        returnResponse('NO', $function);
-    }
-
-} catch (Exception $e) {
-    returnResponse('NO', $function, $e->getMessage());
-}
-
-function returnResponse($value, $function, $usrname = '', $attributes = array(), $xtraxml = "")
-{
-    if ($value === 'YES') {
-        if ($function != 'validate') {
-            $attributesxml = "";
-            foreach ($attributes as $attributename => $attributelist) {
-                $attr = htmlspecialchars($attributename);
-                foreach ($attributelist as $attributevalue) {
-                    $attributesxml .= "<cas:$attr>" . htmlspecialchars($attributevalue) . "</cas:$attr>\n";
-                }
-            }
-            if (sizeof($attributes)) $attributesxml = "<cas:attributes>\n" . $attributesxml . "</cas:attributes>\n";
-            echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
-<cas:authenticationSuccess>
-<cas:user>' . htmlspecialchars($usrname) . '</cas:user>' .
-        $xtraxml .
-        $attributesxml .
-        '</cas:authenticationSuccess>
-</cas:serviceResponse>';
-        } else {
-            echo 'yes' . "\n" . $usrname;
-        }
-    } else {
-        if ($function != 'validate') {
-            echo '<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
-<cas:authenticationFailure code="">
-</cas:authenticationFailure>
-</cas:serviceResponse>';
-        } else {
-            echo 'no';
-        }
-    }
-}
diff --git a/modules/casserver/www/tickets.php b/modules/casserver/www/tickets.php
deleted file mode 100644
index 79498b1082d85769d1db6fe8cd945e7aa6190467..0000000000000000000000000000000000000000
--- a/modules/casserver/www/tickets.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-
-function storeTicket($ticket, $path, $value ) {
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-		
-	if (!is_writable($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] is not writable. ');
-
-	$filename = $path . '/' . $ticket;
-	file_put_contents($filename, serialize($value));
-}
-
-function retrieveTicket($ticket, $path, $unlink = true) {
-
-	if (!preg_match('/^(ST|PT|PGT)-?[a-zA-Z0-9]+$/D', $ticket)) throw new Exception('Invalid characters in ticket');
-
-	if (!is_dir($path)) 
-		throw new Exception('Directory for CAS Server ticket storage [' . $path . '] does not exists. ');
-
-	$filename = $path . '/' . $ticket;
-
-	if (!file_exists($filename))
-		throw new Exception('Could not find ticket');
-	
-	$content = file_get_contents($filename);
-	
-	if ($unlink) {
-		unlink($filename);
-	}
-	
-	return unserialize($content);
-}
-
-function checkServiceURL($service, array $legal_service_urls) {
-	foreach ($legal_service_urls AS $legalurl) {
-		if (strpos($service, $legalurl) === 0) return TRUE;
-	}
-	return FALSE;
-}
diff --git a/modules/casserver/www/validate.php b/modules/casserver/www/validate.php
deleted file mode 100644
index b57c744693a9c4f34abacc5f91ae87153296a480..0000000000000000000000000000000000000000
--- a/modules/casserver/www/validate.php
+++ /dev/null
@@ -1,3 +0,0 @@
-<?php
-$function = 'validate';
-include("serviceValidate.php");
diff --git a/modules/cdc/config-templates/module_cdc.php b/modules/cdc/config-templates/module_cdc.php
index 0e5013c87c5d5a489b1ebfec3e3264ac8baa5397..411bbc47110b4581eab72f0174f4edd66da9ff3e 100644
--- a/modules/cdc/config-templates/module_cdc.php
+++ b/modules/cdc/config-templates/module_cdc.php
@@ -1,7 +1,7 @@
 <?php
 
-$config = array(
-    'example.org' => array(
+$config = [
+    'example.org' => [
         /*
          * The shared key for this CDC server.
          */
@@ -18,5 +18,5 @@ $config = array(
          * If this is 0, the cookie will expire when the browser is closed.
          */
         'cookie.lifetime' => 0,
-    ),
-);
+    ],
+];
diff --git a/modules/cdc/lib/Auth/Process/CDC.php b/modules/cdc/lib/Auth/Process/CDC.php
index 9641da2ab90586b1d237ce7fb4aa0ab10d54d46f..bf2a669d67ca5b60275cb3c4f26ea71deab7fd29 100644
--- a/modules/cdc/lib/Auth/Process/CDC.php
+++ b/modules/cdc/lib/Auth/Process/CDC.php
@@ -1,11 +1,14 @@
 <?php
 
+namespace SimpleSAML\module\cdc\Auth\Process;
+
 /**
  * Filter for setting the SAML 2 common domain cookie.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_cdc_Auth_Process_CDC extends SimpleSAML_Auth_ProcessingFilter
+
+class CDC extends \SimpleSAML\Auth\ProcessingFilter
 {
     /**
      * Our CDC domain.
@@ -18,7 +21,7 @@ class sspmod_cdc_Auth_Process_CDC extends SimpleSAML_Auth_ProcessingFilter
     /**
      * Our CDC client.
      *
-     * @var sspmod_cdc_Client
+     * @var \SimpleSAML\Module\cdc\Client
      */
     private $client;
 
@@ -35,11 +38,11 @@ class sspmod_cdc_Auth_Process_CDC extends SimpleSAML_Auth_ProcessingFilter
         assert(is_array($config));
 
         if (!isset($config['domain'])) {
-            throw new SimpleSAML_Error_Exception('Missing domain option in cdc:CDC filter.');
+            throw new \SimpleSAML\Error\Exception('Missing domain option in cdc:CDC filter.');
         }
-        $this->domain = (string)$config['domain'];
+        $this->domain = (string) $config['domain'];
 
-        $this->client = new sspmod_cdc_Client($this->domain);
+        $this->client = new \SimpleSAML\Module\cdc\Client($this->domain);
     }
 
 
@@ -53,19 +56,19 @@ class sspmod_cdc_Auth_Process_CDC extends SimpleSAML_Auth_ProcessingFilter
         assert(is_array($state));
 
         if (!isset($state['Source']['entityid'])) {
-            SimpleSAML\Logger::warning('saml:CDC: Could not find IdP entityID.');
+            \SimpleSAML\Logger::warning('saml:CDC: Could not find IdP entityID.');
             return;
         }
 
         // Save state and build request
-        $id = SimpleSAML_Auth_State::saveState($state, 'cdc:resume');
+        $id = \SimpleSAML\Auth\State::saveState($state, 'cdc:resume');
 
-        $returnTo = SimpleSAML\Module::getModuleURL('cdc/resume.php', array('domain' => $this->domain));
+        $returnTo = \SimpleSAML\Module::getModuleURL('cdc/resume.php', ['domain' => $this->domain]);
 
-        $params = array(
+        $params = [
             'id' => $id,
             'entityID' => $state['Source']['entityid'],
-        );
+        ];
         $this->client->sendRequest($returnTo, 'append', $params);
     }
 }
diff --git a/modules/cdc/lib/Client.php b/modules/cdc/lib/Client.php
index ab59fa628276608546f5d569ef50bcf75eb83228..609aef63f403f78256597fc3a2e4f6a4d075cfe9 100644
--- a/modules/cdc/lib/Client.php
+++ b/modules/cdc/lib/Client.php
@@ -1,11 +1,14 @@
 <?php
 
+namespace SimpleSAML\Module\cdc;
+
 /**
  * CDC client class.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_cdc_Client
+
+class Client
 {
     /**
      * Our CDC domain.
@@ -18,7 +21,7 @@ class sspmod_cdc_Client
     /**
      * The CDC server we send requests to.
      *
-     * @var sspmod_cdc_Server|NULL
+     * @var Server|NULL
      */
     private $server;
 
@@ -33,7 +36,7 @@ class sspmod_cdc_Client
         assert(is_string($domain));
 
         $this->domain = $domain;
-        $this->server = new sspmod_cdc_Server($domain);
+        $this->server = new Server($domain);
     }
 
 
@@ -55,7 +58,7 @@ class sspmod_cdc_Client
      * @param string $op  The operation we are performing.
      * @param array $params  Additional parameters.
      */
-    public function sendRequest($returnTo, $op, array $params = array())
+    public function sendRequest($returnTo, $op, array $params = [])
     {
         assert(is_string($returnTo));
         assert(is_string($op));
diff --git a/modules/cdc/lib/Server.php b/modules/cdc/lib/Server.php
index 3727c347da1b070be747d3760379b7cb8107d730..affcf668ac241429c7eb933f87bfb48605dac0f1 100644
--- a/modules/cdc/lib/Server.php
+++ b/modules/cdc/lib/Server.php
@@ -1,11 +1,14 @@
 <?php
 
+namespace SimpleSAML\Module\cdc;
+
 /**
  * CDC server class.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_cdc_Server
+
+class Server
 {
     /**
      * The domain.
@@ -50,11 +53,11 @@ class sspmod_cdc_Server
     {
         assert(is_string($domain));
 
-        $cdcConfig = SimpleSAML_Configuration::getConfig('module_cdc.php');
+        $cdcConfig = \SimpleSAML\Configuration::getConfig('module_cdc.php');
         $config = $cdcConfig->getConfigItem($domain, null);
 
         if ($config === null) {
-            throw new SimpleSAML_Error_Exception('Unknown CDC domain: ' . var_export($domain, true));
+            throw new \SimpleSAML\Error\Exception('Unknown CDC domain: '.var_export($domain, true));
         }
 
         $this->domain = $domain;
@@ -63,7 +66,9 @@ class sspmod_cdc_Server
         $this->cookieLifetime = $config->getInteger('cookie.lifetime', 0);
 
         if ($this->key === 'ExampleSharedKey') {
-            throw new SimpleSAML_Error_Exception('Key for CDC domain ' . var_export($domain, true) . ' not changed from default.');
+            throw new \SimpleSAML\Error\Exception(
+                'Key for CDC domain '.var_export($domain, true).' not changed from default.'
+            );
         }
     }
 
@@ -96,7 +101,7 @@ class sspmod_cdc_Server
         }
 
         if ($response['domain'] !== $this->domain) {
-            throw new SimpleSAML_Error_Exception('Response received from wrong domain.');
+            throw new \SimpleSAML\Error\Exception('Response received from wrong domain.');
         }
 
         $this->validate('CDCResponse');
@@ -112,11 +117,11 @@ class sspmod_cdc_Server
     {
         $request = self::get('CDCRequest');
         if ($request === null) {
-            throw new SimpleSAML_Error_BadRequest('Missing "CDCRequest" parameter.');
+            throw new \SimpleSAML\Error\BadRequest('Missing "CDCRequest" parameter.');
         }
 
         $domain = $request['domain'];
-        $server = new sspmod_cdc_Server($domain);
+        $server = new Server($domain);
 
         $server->validate('CDCRequest');
         $server->handleRequest($request);
@@ -131,16 +136,16 @@ class sspmod_cdc_Server
     private function handleRequest(array $request)
     {
         if (!isset($request['op'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing "op" in CDC request.');
+            throw new \SimpleSAML\Error\BadRequest('Missing "op" in CDC request.');
         }
-        $op = (string)$request['op'];
+        $op = (string) $request['op'];
 
-        SimpleSAML\Logger::info('Received CDC request with "op": ' . var_export($op, true));
+        \SimpleSAML\Logger::info('Received CDC request with "op": '.var_export($op, true));
 
         if (!isset($request['return'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing "return" in CDC request.');
+            throw new \SimpleSAML\Error\BadRequest('Missing "return" in CDC request.');
         }
-        $return = (string)$request['return'];
+        $return = (string) $request['return'];
 
         switch ($op) {
             case 'append':
@@ -157,14 +162,14 @@ class sspmod_cdc_Server
         }
 
         if (is_string($response)) {
-            $response = array(
+            $response = [
                 'status' => $response,
-            );
+            ];
         }
 
         $response['op'] = $op;
         if (isset($request['id'])) {
-            $response['id'] = (string)$request['id'];
+            $response['id'] = (string) $request['id'];
         }
         $response['domain'] = $this->domain;
 
@@ -176,14 +181,14 @@ class sspmod_cdc_Server
      * Handle an append request.
      *
      * @param array $request  The request.
-     * @return array  The response.
+     * @return string The response.
      */
     private function handleAppend(array $request)
     {
         if (!isset($request['entityID'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing entityID in append request.');
+            throw new \SimpleSAML\Error\BadRequest('Missing entityID in append request.');
         }
-        $entityID = (string)$request['entityID'];
+        $entityID = (string) $request['entityID'];
 
         $list = $this->getCDC();
 
@@ -203,16 +208,16 @@ class sspmod_cdc_Server
      * Handle a delete request.
      *
      * @param array $request  The request.
-     * @return array  The response.
+     * @return string The response.
      */
     private function handleDelete(array $request)
     {
-        $params = array(
+        $params = [
             'path' => '/',
-            'domain' => '.' . $this->domain,
+            'domain' => '.'.$this->domain,
             'secure' => true,
             'httponly' => false,
-        );
+        ];
 
         \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', null, $params, false);
         return 'ok';
@@ -229,10 +234,10 @@ class sspmod_cdc_Server
     {
         $list = $this->getCDC();
 
-        return array(
+        return [
             'status' => 'ok',
             'cdc' => $list,
-        );
+        ];
     }
 
 
@@ -249,32 +254,32 @@ class sspmod_cdc_Server
         if (!isset($_REQUEST[$parameter])) {
             return null;
         }
-        $message = (string)$_REQUEST[$parameter];
+        $message = (string) $_REQUEST[$parameter];
 
         $message = @base64_decode($message);
         if ($message === false) {
-            throw new SimpleSAML_Error_BadRequest('Error base64-decoding CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Error base64-decoding CDC message.');
         }
 
         $message = @json_decode($message, true);
         if ($message === false) {
-            throw new SimpleSAML_Error_BadRequest('Error json-decoding CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Error json-decoding CDC message.');
         }
 
         if (!isset($message['timestamp'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing timestamp in CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Missing timestamp in CDC message.');
         }
-        $timestamp = (int)$message['timestamp'];
+        $timestamp = (int) $message['timestamp'];
 
         if ($timestamp + 60 < time()) {
-            throw new SimpleSAML_Error_BadRequest('CDC signature has expired.');
+            throw new \SimpleSAML\Error\BadRequest('CDC signature has expired.');
         }
         if ($timestamp - 60 > time()) {
-            throw new SimpleSAML_Error_BadRequest('CDC signature from the future.');
+            throw new \SimpleSAML\Error\BadRequest('CDC signature from the future.');
         }
 
         if (!isset($message['domain'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing domain in CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Missing domain in CDC message.');
         }
 
         return $message;
@@ -293,16 +298,16 @@ class sspmod_cdc_Server
         assert(is_string($parameter));
         assert(isset($_REQUEST[$parameter]));
 
-        $message = (string)$_REQUEST[$parameter];
+        $message = (string) $_REQUEST[$parameter];
 
         if (!isset($_REQUEST['Signature'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing Signature on CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Missing Signature on CDC message.');
         }
-        $signature = (string)$_REQUEST['Signature'];
+        $signature = (string) $_REQUEST['Signature'];
 
         $cSignature = $this->calcSignature($message);
         if ($signature !== $cSignature) {
-            throw new SimpleSAML_Error_BadRequest('Invalid signature on CDC message.');
+            throw new \SimpleSAML\Error\BadRequest('Invalid signature on CDC message.');
         }
     }
 
@@ -325,10 +330,10 @@ class sspmod_cdc_Server
 
         $signature = $this->calcSignature($message);
 
-        $params = array(
+        $params = [
             $parameter => $message,
             'Signature' => $signature,
-        );
+        ];
 
         $url = \SimpleSAML\Utils\HTTP::addURLParameters($to, $params);
         if (strlen($url) < 2048) {
@@ -349,7 +354,7 @@ class sspmod_cdc_Server
     {
         assert(is_string($rawMessage));
 
-        return sha1($this->key . $rawMessage . $this->key);
+        return sha1($this->key.$rawMessage.$this->key);
     }
 
 
@@ -361,17 +366,17 @@ class sspmod_cdc_Server
     private function getCDC()
     {
         if (!isset($_COOKIE['_saml_idp'])) {
-            return array();
+            return [];
         }
 
-        $ret = (string)$_COOKIE['_saml_idp'];
+        $ret = (string) $_COOKIE['_saml_idp'];
         $ret = explode(' ', $ret);
         foreach ($ret as &$idp) {
             $idp = base64_decode($idp);
             if ($idp === false) {
                 // Not properly base64 encoded
-                SimpleSAML\Logger::warning('CDC - Invalid base64-encoding of CDC entry.');
-                return array();
+                \SimpleSAML\Logger::warning('CDC - Invalid base64-encoding of CDC entry.');
+                return [];
             }
         }
 
@@ -406,14 +411,16 @@ class sspmod_cdc_Server
             $cookie = $tmp[1];
         }
 
-        $params = array(
+        $params = [
             'lifetime' => $this->cookieLifetime,
             'path' => '/',
-            'domain' => '.' . $this->domain,
+            'domain' => '.'.$this->domain,
             'secure' => true,
             'httponly' => false,
-        );
+        ];
 
         \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $cookie, $params, false);
+
+        return '_saml_idp';
     }
 }
diff --git a/modules/cdc/www/resume.php b/modules/cdc/www/resume.php
index a7f821998c953ff4a290315cf839a8d2a03dd815..ebe6b1cc9f246b94dca7ab01d3b208f8f15bd281 100644
--- a/modules/cdc/www/resume.php
+++ b/modules/cdc/www/resume.php
@@ -1,21 +1,20 @@
 <?php
 
-
 if (!array_key_exists('domain', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing domain to CDC resume handler.');
+    throw new \SimpleSAML\Error\BadRequest('Missing domain to CDC resume handler.');
 }
 
-$domain = (string)$_REQUEST['domain'];
-$client = new sspmod_cdc_Client($domain);
+$domain = (string) $_REQUEST['domain'];
+$client = new \SimpleSAML\Module\cdc\Client($domain);
 
 $response = $client->getResponse();
-if ($response === NULL) {
-	throw new SimpleSAML_Error_BadRequest('Missing CDC response to CDC resume handler.');
+if ($response === null) {
+    throw new \SimpleSAML\Error\BadRequest('Missing CDC response to CDC resume handler.');
 }
 
 if (!isset($response['id'])) {
-	throw new SimpleSAML_Error_BadRequest('CDCResponse without id.');
+    throw new \SimpleSAML\Error\BadRequest('CDCResponse without id.');
 }
-$state = SimpleSAML_Auth_State::loadState($response['id'], 'cdc:resume');
+$state = \SimpleSAML\Auth\State::loadState($response['id'], 'cdc:resume');
 
-SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+\SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
diff --git a/modules/cdc/www/server.php b/modules/cdc/www/server.php
index f84b7a90614528eecf3b4f97930d8ceadc8011a1..d5cfd16ece5aecda1184fdb626e824ca56e2d6a3 100644
--- a/modules/cdc/www/server.php
+++ b/modules/cdc/www/server.php
@@ -1,3 +1,3 @@
 <?php
 
-sspmod_cdc_Server::processRequest();
\ No newline at end of file
+\SimpleSAML\Module\cdc\Server::processRequest();
diff --git a/modules/authmyspace/default-disable b/modules/consent/default-disable
similarity index 100%
rename from modules/authmyspace/default-disable
rename to modules/consent/default-disable
diff --git a/modules/consent/default-enable b/modules/consent/default-enable
deleted file mode 100644
index 25615cb47c350d23033eb9801627ed8330bcc3e9..0000000000000000000000000000000000000000
--- a/modules/consent/default-enable
+++ /dev/null
@@ -1,3 +0,0 @@
-This file indicates that the default state of this module
-is enabled. To disable, create a file named disable in the
-same directory as this file.
diff --git a/modules/consent/dictionaries/consent.definition.json b/modules/consent/dictionaries/consent.definition.json
index d36f9e70f8d2396c191a6e12d236efe8d3a75aa9..6c445161046037f3264377dd668270ad384332b8 100644
--- a/modules/consent/dictionaries/consent.definition.json
+++ b/modules/consent/dictionaries/consent.definition.json
@@ -1,68 +1,68 @@
 {
-	"yes": {
-		"en": "Yes, continue"
-	},
-	"no": {
-		"en": "No, cancel"
-	},
-	"remember": {
-		"en": "Remember"
-	},
-	"consent_accept": {
-		"en": "SPNAME requires that the information below is transferred."
-	},
-	"login": {
-		"en": "login"
-	},
-	"service_providers_for": {
-		"en": "Service Providers for"
-	},
-	"service_provider_header": {
-		"en": "Service Provider"
-	},
-	"status_header": {
-		"en": "Consent status"
-	},
-	"show_hide_attributes": {
-		"en": "show\/hide attributes"
-	},
-	"consent_privacypolicy": {
-		"en": "Privacypolicy for the service"
-	},
-	"noconsent_title": {
-		"en": "No consent given"
-	},
-	"noconsent_text": {
-		"en": "You did not give consent for transfering your attributes to SPNAME."
-	},
-	"noconsent_return": {
-		"en": "Return to consent page"
-	},
-	"consent_header": {
-		"en": "Consent about releasing personal information"
-	},
-	"consent_attributes_header": {
-		"en": "Information that will be sent to SPNAME"
-	},
-	"show_attributes": {
-		"en": "Show attributes"
-	},
-	"noconsent_goto_about": {
-		"en": "Go to information page for the service"
-	},
-	"consent_purpose": {
-		"en": "The purpose of SPNAME is SPDESC"
-	},
-	"table_caption": {
-		"en": "User information"
-	},
-	"table_summary": {
-		"en": "List the information about you that is about to be transmitted to the service you are going to login to"
-	},
-	"show_attribute": {
-		"en": "Show content"
-	},
-	"abort": {
-		"en": "Abort login to SPNAME"
-	}
+    "yes": {
+        "en": "Yes, continue"
+    },
+    "no": {
+        "en": "No, cancel"
+    },
+    "remember": {
+        "en": "Remember"
+    },
+    "consent_accept": {
+        "en": "SPNAME requires that the information below is transferred."
+    },
+    "login": {
+        "en": "login"
+    },
+    "service_providers_for": {
+        "en": "Service Providers for"
+    },
+    "service_provider_header": {
+        "en": "Service Provider"
+    },
+    "status_header": {
+        "en": "Consent status"
+    },
+    "show_hide_attributes": {
+        "en": "show\/hide attributes"
+    },
+    "consent_privacypolicy": {
+        "en": "Privacy policy for the service"
+    },
+    "noconsent_title": {
+        "en": "No consent given"
+    },
+    "noconsent_text": {
+        "en": "You did not give consent for transfering your attributes to SPNAME."
+    },
+    "noconsent_return": {
+        "en": "Return to consent page"
+    },
+    "consent_header": {
+        "en": "Consent about releasing personal information"
+    },
+    "consent_attributes_header": {
+        "en": "Information that will be sent to SPNAME"
+    },
+    "show_attributes": {
+        "en": "Show attributes"
+    },
+    "noconsent_goto_about": {
+        "en": "Go to information page for the service"
+    },
+    "consent_purpose": {
+        "en": "The purpose of SPNAME is SPDESC"
+    },
+    "table_caption": {
+        "en": "User information"
+    },
+    "table_summary": {
+        "en": "List the information about you that is about to be transmitted to the service you are going to login to"
+    },
+    "show_attribute": {
+        "en": "Show content"
+    },
+    "abort": {
+        "en": "Abort login to SPNAME"
+    }
 }
diff --git a/modules/consent/dictionaries/consent.php b/modules/consent/dictionaries/consent.php
index cdf77fec0aa3ba12d75f9498822cb3ad504b62c4..90932786ab4f957ea168a9c613f742d863d07907 100644
--- a/modules/consent/dictionaries/consent.php
+++ b/modules/consent/dictionaries/consent.php
@@ -1,379 +1,378 @@
 <?php
 
-$lang = array(
-	'yes' => array (
-		'no' => 'Ja, fortsett',
-		'nn' => 'Ja, fortsett',
-		'da' => 'Ja, jeg accepterer',
-		'en' => 'Yes, continue',
-		'de' => 'Ja, ich stimmte zu',
-		'sv' => 'Ja',
-		'fi' => 'Kyllä',
-		'es' => 'SĂ­',
-		'fr' => 'Oui',
-		'nl' => 'Ja, ik ga akkoord',
-		'lb' => 'Jo',
-		'sl' => 'Da, nadaljuj',
-		'hr' => 'Da, prihvaćam',
-		'hu' => 'Igen, elfogadom',
-		'pl' => 'Tak, akceptujÄ™',
-		'pt' => 'Sim, Aceito',
-		'pt-br' => 'Sim, Aceito',
-		'tr' => 'Evet, devam et',
-	),
-	'no' => array (
-		'no' => 'Nei, avbryt',
-		'nn' => 'Nei, avbryt',
-		'da' => 'Nej, jeg accepterer ikke',
-		'en' => 'No, cancel',
-		'de' => 'Nein, ich stimmte nicht zu',
-		'sv' => 'Nej',
-		'fi' => 'ei',
-		'es' => 'No',
-		'fr' => 'Non',
-		'nl' => 'Nee, ik weiger',
-		'lb' => 'Nee',
-		'sl' => 'Ne, prekliÄŤi',
-		'hr' => 'Ne privaćam',
-		'hu' => 'Nem, nem fogadom el',
-		'pl' => 'Nie, nie akceptujÄ™',
-		'pt' => 'NĂŁo aceito',
-		'pt-br' => 'NĂŁo, nĂŁo aceito',
-		'tr' => 'Hayır, iptal et',
-	),
-	'remember' => array (
-		'no' => 'Godta ogsĂĄ for fremtiden',
-		'nn' => 'Godta ogsĂĄ for framtida',
-		'da' => 'Husk samtykke',
-		'en' => 'Remember',
-		'de' => 'Zustimmung merken',
-		'sv' => 'Spara samtycke',
-		'fi' => 'Muista',
-		'es' => 'Recordar el consentimiento',
-		'fr' => 'Se souvenir du consentement',
-		'nl' => 'Bewaar toestemming',
-		'lb' => 'Zoustëmmung verhalen',
-		'sl' => 'Zapomni si privolitev.',
-		'hr' => 'Zapamti dozvole',
-		'hu' => 'Emlékezzen a hozzájárulásra',
-		'pl' => 'Pamiętaj moją zgodę',
-		'pt' => 'Lembrar a minha escolha',
-		'pt-br' => 'Lembrar Consentimento',
-		'tr' => 'Hatırla',
-	),
-	'consent_header' => array (
-		'no' => 'Samtykke om overføring av personinformasjon',
-		'nn' => 'Samtykke til overføring av personinformasjon',
-		'da' => 'Samtykke til at frigive personlige oplysninger',
-		'en' => 'Consent about releasing personal information',
-		'de' => 'Zustimmung zur Weitergabe persönlicher Daten  ',
-		'sv' => 'Samtycke gällande överföring av personinformation',
-		'fi' => 'Henkilötietojen luovutuksen hyväksyntä',
-		'es' => 'Consentimiento para la liberaciĂłn de informaciĂłn personal',
-		'nl' => 'Toestemming voor het vrijgeven van persoonsgegevens',
-		'sl' => 'Odločitev o privolitvi posredovanja vaših osebnih podatkov',
-		'hr' => 'Dozvola za isporuku osobnih podataka',
-		'hu' => 'Hozzájárulás személyes adatok kiadásához',
-		'pl' => 'Zgoda na wysłanie danych osobistych',
-		'pt' => 'Consentimento do envio de informação pessoal',
-		'tr' => 'Kişisel bilgilerin verilmesi hakkında onay',
-	),
-	'consent_accept' => array (
-		'no' => 'For å fullføre innloggingen må du godta at opplysningene nedenfor sendes til SPNAME.',
-		'nn' => 'For å fullføra innlogginga må du godta at opplysningane under blir sende til SPNAME',
-		'da' => 'SPNAME kræver at nedenstående oplysninger overføres fra IDPNAME. Vil du acceptere dette?',
-		'en' => 'SPNAME requires that the information below is transferred.',
-		'de' => 'SPNAME erfordert die Ăśbertragung untenstehender Information von IDPNAME. Akzeptieren Sie das?',
-		'sv' => 'Du är på väg att logga in i tjänsten SPNAME. Tjänsten kräver att informationen nedan skickas från IDPNAME. Är detta okej?',
-		'fi' => 'Olet kirjautumassa palveluun SPNAME. Identiteetilähteesi henkilötietojasi palvelun tarjoajalle. Hyväksytkö tietojen siirron?',
-		'es' => 'Está a punto de acceder al servicio SPNAME. El servicio requiere que la información que se muestra a continuación sea transferida desde IDPNAME. ¿Acepta esto?  ',
-		'fr' => 'Vous êtes sur le point de vous connecter au service SPNAME. Lors de l\'ouverture de session, le fournisseur d\'identité enverra des informations sur votre identité à ce service. Acceptez-vous cela ?',
-		'nl' => 'U gaat inloggen bij een dienst SPNAME. Tijdens het loginproces stuurt de identity provider zgn. attributen met daarin informatie over uw identiteit voor deze dienst. Bent u het daarmee eens?',
-		'lb' => 'Daer sid dobai aerch um service unzemellen SPNAME. Waerend dem Login Prozess schéckt den Identity Provider Attributer, déi Informatiounen iwert aer Identitéit enthaalen. Akzeptéier daer daat?',
-		'sl' => 'Pravkar se nameravate prijaviti v storitev SPNAME. Med postopkom prijave bo IdP tej storitvi posredoval atribute, ki vsebujejo informacije o vaši identiteti. Ali se s tem strinjate? ',
-		'hr' => 'U tijeku je proces prijave za pristup servisu SPNAME. Servis zahtjeva da IDPNAME isporuÄŤi dolje navedene podatke. SlaĹľete li se s time?',
-		'hu' => 'Ön azonosítja magát ehhez a szolgáltatáshoz SPNAME. Az azonosítás során IDPNAME az alábbi adatokat fogja küldeni a szolgáltatásnak. Engedélyezi?',
-		'pl' => 'SPNAME wymaga aby poniższa informacja została przesłana.',
-		'pt' => 'O serviço SPNAME necessita que a informação apresentada em baixo seja transferida.',
-		'pt-br' => 'Você está prestes a acessar o serviço SPNAME. O serviço exige que as informações a seguir sejam transferidas do IDPNAME. Você aceita isso?',
-		'tr' => 'SPNAME aşağıdaki bilgilerin gönderilmesine ihtiyaç duyuyor.',
-	),
-	'consent_purpose' => array (
-		'no' => 'FormĂĄlet med SPNAME er SPDESC',
-		'nn' => 'Hensikta med SPNAME er SPDESC',
-		'da' => 'SPNAME har til formĂĄl at SPDESC',
-		'en' => 'The purpose of SPNAME is SPDESC',
-		'de' => 'Der Zweck von SPNAME ist SPDESC',
-		'sv' => 'Syftet med SPNAME är SPDESC',
-		'fi' => 'Palvelun SPNAME käyttötarkoitus on SPDESC',
-		'es' => 'El propĂłsito de SPNAME es SPDESC',
-		'nl' => 'Het doel van SPNAME is SPDESC',
-		'sl' => 'Namen %SPNAME%: %SPDESC%',
-		'hr' => 'Svrha SPNAME je SPDESC',
-		'hu' => 'A szolgáltatás (SPNAME) ezt a célt szolgálja: SPDESC',
-		'pl' => 'Celem SPNAME jest SPDESC',
-		'pt' => 'O propĂłsito de SPNAME Ă© SPDESC',
-		'tr' => 'SPNAME\'in amacı SPDESC\'tir',
-	),
-	'consent_privacypolicy' => array (
-		'no' => 'Personvern for tjenesten',
-		'nn' => 'Personvern for tenesta',
-		'da' => 'Tjenestens politik vedrørende personoplysninger',
-		'en' => 'Privacypolicy for the service',
-		'de' => 'Datenschutzrichtlinie des Dienstes',
-		'sv' => 'Tjänstens policy för personlig integritet',
-		'fi' => 'Tietosuojaseloste palvelulle',
-		'es' => 'PolĂ­tica de privacidad para el servicio',
-		'nl' => 'Privacybeleid voor de dienst',
-		'sl' => 'Politika zasebnosti za ta SP',
-		'hr' => 'Politika zaštite privatnosti',
-		'hu' => 'A szolgáltatás adatvádelmi nyilatkozata',
-		'pl' => 'Polityka prywatności dla serwisu',
-		'pt' => 'Política de privacidade do serviço',
-		'pt-br' => 'Política de Privacidade deste serviço',
-		'tr' => 'Servis için gizlilik politikası',
-	),
-	'consent_attributes_header' => array (
-		'no' => 'Opplysninger som vil bli sendt til SPNAME',
-		'nn' => 'Opplysningar som blir sende til SPNAME',
-		'da' => 'Attributter som bliver sendt til SPNAME',
-		'en' => 'Information that will be sent to SPNAME',
-		'de' => 'Informationen, die an SPNAME gesandt werden',
-		'sv' => 'Attribut som kommer att skickas till tjänsten',
-		'fi' => 'Tiedot lähetetään palvelulle SPNAME',
-		'es' => 'Atributos que serán enviados al servicio',
-		'nl' => 'Informatie die naar SPNAME zal worden gestuurd',
-		'sl' => 'Atributi, ki bodo poslani SPju',
-		'hr' => 'Atributi koji će biti poslani servisu',
-		'hu' => 'A(z) SPNAME szolgáltatónak küldött adatok',
-		'pl' => 'Atrybuty, które zostaną przesłane do serwisu',
-		'pt' => 'Informação que irá ser enviada para SPNAME',
-		'tr' => 'SPNAME\'e gönderilecek bilgiler',
-	),
-	'show_attributes' => array (
-		'no' => 'Vis opplysninger',
-		'nn' => 'Vis opplysingar',
-		'da' => 'Vis attributter',
-		'en' => 'Show attributes',
-		'de' => 'Attribute zeigen',
-		'sv' => 'Visa attribut',
-		'fi' => 'Näytä henkilötiedot',
-		'es' => 'Mostrar atributos',
-		'nl' => 'Toon attributen',
-		'sl' => 'PrikaĹľi atribute',
-		'hr' => 'PrikaĹľi atribute',
-		'hu' => 'Mutasd az attribĂştumokat',
-		'pl' => 'Wyświetl atrybuty',
-		'pt' => 'Mostrar atributos',
-		'tr' => 'Özellikleri göster',
-	),
-	'show_attribute' => array (
-		'no' => 'Vis innhold',
-		'nn' => 'Vis innhald',
-		'da' => 'Vis indhold',
-		'en' => 'Show content',
-		'sv' => 'Visa samtycke',
-		'es' => 'Mostrart consentimiento',
-		'nl' => 'Toon inhoud',
-		'sl' => 'PrikaĹľi vsebino',
-	),
-	'login' => array (
-		'no' => 'innlogging',
-		'nn' => 'Logg inn',
-		'da' => 'login',
-		'en' => 'login',
-		'de' => 'anmelden',
-		'sv' => 'Logga in',
-		'fi' => 'Tunnus',
-		'es' => 'login',
-		'fr' => 'ouvrir une session',
-		'nl' => 'Login',
-		'lb' => 'anloggen',
-		'sl' => 'Prijava',
-		'hr' => 'prijava',
-		'hu' => 'bejelentkezés',
-		'pl' => 'login',
-		'pt' => 'Entrar',
-		'pt-br' => 'login',
-		'tr' => 'GiriĹź',
-	),
-	'service_providers_for' => array (
-		'no' => 'Tjenesteleverandør for',
-		'nn' => 'Tenesteleverandørar for',
-		'da' => 'Tjenesteudbyder for',
-		'en' => 'Service Providers for',
-		'de' => 'Service-Provider fĂĽr',
-		'sv' => 'Tjänsteleverantörer för',
-		'fi' => 'Palveluntarjoaja',
-		'es' => 'Proveedores de servicio para',
-		'fr' => 'Fournisseurs de services pour',
-		'nl' => 'Service Providers voor',
-		'lb' => 'Service Provider fir',
-		'sl' => 'SP za',
-		'hr' => 'Davatelji usluge za',
-		'hu' => 'Alkalmazásszolgáltatók a következő számára',
-		'pl' => 'Dostawca Serwisu dla',
-		'pt' => 'Fornecedores de Serviço (SP) para',
-		'pt-br' => 'Provedor de serviços para',
-		'tr' => 'için Servis Sağlayıcılar',
-	),
-	'service_provider_header' => array (
-		'no' => 'Tjenesteleverandør',
-		'nn' => 'Tenesteleverandør',
-		'da' => 'Tjenesteudbyder',
-		'en' => 'Service Provider',
-		'de' => 'Service-Provider',
-		'sv' => 'Tjänsteleverantör',
-		'fi' => 'Palveluntarjoaja',
-		'es' => 'Proveedor de servicio',
-		'fr' => 'Fournisseur de service',
-		'nl' => 'Service Provider',
-		'lb' => 'Service Provider',
-		'sl' => 'SP',
-		'hr' => 'Davatelj usluge',
-		'hu' => 'Alkalmazásszolgáltató',
-		'pl' => 'Dostawca serwisu',
-		'pt' => 'Fornecedor de Serviço (SP)',
-		'pt-br' => 'Provedor de Serviços',
-		'tr' => 'Servis Sağlayıcı',
-	),
-	'status_header' => array (
-		'no' => 'Samtykke-status',
-		'nn' => 'Samtykkestatus',
-		'da' => 'Samtykke status',
-		'en' => 'Consent status',
-		'de' => 'Zustimmungsstatus',
-		'sv' => 'Status för samtycke',
-		'fi' => 'Hyväksynnään tila',
-		'es' => 'Estado del consentimiento',
-		'fr' => 'État des consentements',
-		'nl' => 'Toestemming status',
-		'lb' => 'Zoustëmmungsstatus',
-		'sl' => 'Stanje privolitve',
-		'hr' => 'Status dozvole',
-		'hu' => 'Hozzájárulás állapota',
-		'pl' => 'Status zgody',
-		'pt' => 'Consentimento',
-		'pt-br' => 'Status do Consentimento',
-		'tr' => 'Onay durumu',
-	),
-	'show_hide_attributes' => array (
-		'no' => 'Vis/skjul opplysninger',
-		'nn' => 'Vis/skjul opplysningar',
-		'da' => 'vis/skjul attributter',
-		'en' => 'show/hide attributes',
-		'de' => 'zeige/verstecke Eigenschaften',
-		'sv' => 'visa/göm attribut',
-		'fi' => 'Näytä/piilota attribuutteja',
-		'es' => 'Mostrar/ocultar atributos',
-		'fr' => 'montrer/cacher les attributs',
-		'nl' => 'toon/verberg attributen',
-		'lb' => 'Attributer weisen/verstoppen',
-		'sl' => 'prikaĹľi/skrij atribute',
-		'hr' => 'prikaĹľi/sakrij atribute',
-		'hu' => 'attribútumok mutatása/elrejtése',
-		'pl' => 'pokaĹĽ/ukryj atrybuty',
-		'pt' => 'Mostrar/Ocultar atributos',
-		'pt-br' => 'mostra/esconder Atributos',
-		'tr' => 'bilgileri göster/gizle ',
-	),
-	'noconsent_title' => array (
-		'no' => 'Ikke akseptert overføring av informasjon',
-		'nn' => 'Ikkje akseptert overføring av informasjon',
-		'da' => 'Manglende samtykke',
-		'en' => 'No consent given',
-		'de' => 'Zustimmung verweigert',
-		'sv' => 'Inget samtycket givet',
-		'fi' => 'Lupaa ei annettu',
-		'es' => 'No se diĂł el consentimiento',
-		'nl' => 'Geen toestemming gegeven',
-		'sl' => 'Privolitev ni bila dana.',
-		'hr' => 'Nema pristanka',
-		'hu' => 'Nincs hozzájárulás',
-		'pl' => 'Nie wyraĹĽono zgody',
-		'pt' => 'Consentimento negado',
-		'pt-br' => 'Nenhum consentimento dado',
-		'tr' => 'Onay verilmemiĹź',
-	),
-	'noconsent_text' => array (
-		'no' => 'Du har ikke akseptert å overlevere opplysninger til tjenesteleverandøren.',
-		'nn' => 'Du har ikkje akseptert til at dine opplysningar kan sendast til tenesteleverandøren',
-		'da' => 'Du har ikke givet samtykke til overleveringen af oplysninger til tjenesten',
-		'en' => 'You did not give consent for transfering your attributes to the service provider.',
-		'de' => 'Sie haben der Weitergabe ihrer Daten an den Service Provider nicht zugestimmt.',
-		'sv' => 'Du gav inte samtycke för att överföra dina attribut till tjänsteleverantören.',
-		'fi' => 'Et antanut lupaa siirtää henkilötietojasi palveluntarjoajalle',
-		'es' => 'No ha dado su consentimiento para tranferir sus atributos al proveedor de servicio.',
-		'nl' => 'U heeft geen toestemming gegeven om uw attributen naar de Service Provider te versturen',
-		'sl' => 'Niste podali privolitve za posredovanje atributov SP-ju.',
-		'hr' => 'Niste dali pristanak da se vaši podaci isporuče davatelju usluge.',
-		'hu' => 'Nem adta hozzájárulását, hogy adatait továbbadjuk a szolgáltatónak.',
-		'pl' => 'Nie wyraziłeś zgody na przesłanie Twoich atrybutów do Dostawcy Serwisu.',
-		'pt' => 'Negou o consentimento para a transferência dos seus atributos para o fornecedor de serviço.',
-		'pt-br' => 'Você não deu o consentimento para a transferência de seus atributos para o provedor de serviços.',
-		'tr' => 'Bilgilerinizin servis sağlayıcıya gönderilmesi için onay vermediniz.',
-	),
-	'noconsent_return' => array (
-		'no' => 'GĂĄ tilbake til aksept-siden med opplysninger',
-		'nn' => 'Gå tilbake til aksept-sida for overføring av opplysningar',
-		'da' => 'GĂĄ tilbage',
-		'en' => 'Return to consent page',
-		'de' => 'ZurĂĽck',
-		'sv' => 'Åter till sidan för samtycke',
-		'fi' => 'Palaa hyväksyntäsivulle',
-		'es' => 'Volver a la página de consentimiento',
-		'nl' => 'Keer terug naar de toestemmingspagina',
-		'sl' => 'Vrnitev na privolitveno stran',
-		'hr' => 'Povratak na stranicu s dozvolama',
-		'hu' => 'Vissza az hozzájárulás-kezelő oldalra',
-		'pl' => 'PowrĂłt do strony wydania zezwolenia.',
-		'pt' => 'Voltar à página de consentimento',
-		'pt-br' => 'Retornar a página de consentimento',
-		'tr' => 'Onay sayfasına geri dön',
-	),
-	'noconsent_goto_about' => array (
-		'no' => 'GĂĄ til informasjonsside om tjenesten',
-		'nn' => 'GĂĄ til informasjonssida for tenesta',
-		'da' => 'GĂĄ til side med information om tjenesten',
-		'en' => 'Go to information page for the service',
-		'de' => 'Gehe zur Informationsseite dieses Dienstes',
-		'sv' => 'Gå till tjänstens informationssida',
-		'fi' => 'Siirry palvelun tiedot -sivulle',
-		'es' => 'Ir a la página de información del servicio',
-		'nl' => 'Ga naar de informatiepagina voor de service',
-		'sl' => 'Pojdi na spletno stran z informacijami o storitvi',
-		'hr' => 'Idi na stranicu s informacijama o servisu',
-		'hu' => 'A szolgáltatás információs oldalára',
-		'pl' => 'PrzejdĹş do strony informacyjnej dla tego serwisu',
-		'pt' => 'Ir para página de informação do serviço',
-		'tr' => 'Servis için bilgi sayfasına git',
-	),
-	'table_caption' => array (
-		'no' => 'Bruker innformasjon',
-		'da' => 'Bruger information',
-		'en' => 'User information',
-		'de' => 'Benutzerdaten',
-		'sv' => 'Användarinformation',
-		'fi' => 'Käyttäjätiedot',
-		'es' => 'InformaciĂłn del usuario',
-		'nl' => 'Gerbuikersinformatie',
-		'sl' => 'Podatki o uporabniku',
-		'hu' => 'Felhasználói információk',
-		'pt' => 'Informação do utilizador',
-		'tr' => 'Kullanıcı bilgisi',
-	),
-	'table_summary' => array (
-		'no' => 'Her listes den innformasjonen om deg som blir send til den tjenesten du er i ferd med ĂĄ logge pĂĄ',
-		'da' => 'Informationer som vil blive sendt til den service du er ved at logge in pĂĄ',
-		'en' => 'List the information about you that is about to be transmitted to the service you are going to login to',
-		'sv' => 'Visa den nformation om din användare som kommer att skickas till tjänsten som du är på väg att logga in i',
-		'fi' => 'Näytä tietosi, joita ollaan siirtämässä palveluun',
-		'es' => 'Muestra que informaciĂłn relativa a usted va a ser transmitida al servicio en el que se va a identificar',
-		'nl' => 'De informatie die over jou bekend is en naar de service waarop je wilt inloggen verstuurd zal worden',
-		'sl' => 'Seznam podatkov o vas, ki bodo posredovani storitvi, v katero se nameravate prijaviti',
-		'hu' => 'Ezeket az adatokat fogjuk elküldeni Önről annak a szolgáltatásnak, ahová be kíván jelentkezni',
-		'pt' => 'Listar a informação acerca de si que será enviada para o serviço no qual se está autenticar',
-		'tr' => 'Girmek istediğiniz servise gönderilecek bilginizi listeleyin',
-	),
-
-);
+$lang = [
+    'yes' => [
+        'no' => 'Ja, fortsett',
+        'nn' => 'Ja, fortsett',
+        'da' => 'Ja, jeg accepterer',
+        'en' => 'Yes, continue',
+        'de' => 'Ja, ich stimmte zu',
+        'sv' => 'Ja',
+        'fi' => 'Kyllä',
+        'es' => 'SĂ­',
+        'fr' => 'Oui',
+        'nl' => 'Ja, ik ga akkoord',
+        'lb' => 'Jo',
+        'sl' => 'Da, nadaljuj',
+        'hr' => 'Da, prihvaćam',
+        'hu' => 'Igen, elfogadom',
+        'pl' => 'Tak, akceptujÄ™',
+        'pt' => 'Sim, Aceito',
+        'pt-br' => 'Sim, Aceito',
+        'tr' => 'Evet, devam et',
+    ],
+    'no' => [
+        'no' => 'Nei, avbryt',
+        'nn' => 'Nei, avbryt',
+        'da' => 'Nej, jeg accepterer ikke',
+        'en' => 'No, cancel',
+        'de' => 'Nein, ich stimmte nicht zu',
+        'sv' => 'Nej',
+        'fi' => 'ei',
+        'es' => 'No',
+        'fr' => 'Non',
+        'nl' => 'Nee, ik weiger',
+        'lb' => 'Nee',
+        'sl' => 'Ne, prekliÄŤi',
+        'hr' => 'Ne privaćam',
+        'hu' => 'Nem, nem fogadom el',
+        'pl' => 'Nie, nie akceptujÄ™',
+        'pt' => 'NĂŁo aceito',
+        'pt-br' => 'NĂŁo, nĂŁo aceito',
+        'tr' => 'Hayır, iptal et',
+    ],
+    'remember' => [
+        'no' => 'Godta ogsĂĄ for fremtiden',
+        'nn' => 'Godta ogsĂĄ for framtida',
+        'da' => 'Husk samtykke',
+        'en' => 'Remember',
+        'de' => 'Zustimmung merken',
+        'sv' => 'Spara samtycke',
+        'fi' => 'Muista',
+        'es' => 'Recordar el consentimiento',
+        'fr' => 'Se souvenir du consentement',
+        'nl' => 'Bewaar toestemming',
+        'lb' => 'Zoustëmmung verhalen',
+        'sl' => 'Zapomni si privolitev.',
+        'hr' => 'Zapamti dozvole',
+        'hu' => 'Emlékezzen a hozzájárulásra',
+        'pl' => 'Pamiętaj moją zgodę',
+        'pt' => 'Lembrar a minha escolha',
+        'pt-br' => 'Lembrar Consentimento',
+        'tr' => 'Hatırla',
+    ],
+    'consent_header' => [
+        'no' => 'Samtykke om overføring av personinformasjon',
+        'nn' => 'Samtykke til overføring av personinformasjon',
+        'da' => 'Samtykke til at frigive personlige oplysninger',
+        'en' => 'Consent about releasing personal information',
+        'de' => 'Zustimmung zur Weitergabe persönlicher Daten  ',
+        'sv' => 'Samtycke gällande överföring av personinformation',
+        'fi' => 'Henkilötietojen luovutuksen hyväksyntä',
+        'es' => 'Consentimiento para la liberaciĂłn de informaciĂłn personal',
+        'nl' => 'Toestemming voor het vrijgeven van persoonsgegevens',
+        'sl' => 'Odločitev o privolitvi posredovanja vaših osebnih podatkov',
+        'hr' => 'Dozvola za isporuku osobnih podataka',
+        'hu' => 'Hozzájárulás személyes adatok kiadásához',
+        'pl' => 'Zgoda na wysłanie danych osobistych',
+        'pt' => 'Consentimento do envio de informação pessoal',
+        'tr' => 'Kişisel bilgilerin verilmesi hakkında onay',
+    ],
+    'consent_accept' => [
+        'no' => 'For å fullføre innloggingen må du godta at opplysningene nedenfor sendes til SPNAME.',
+        'nn' => 'For å fullføra innlogginga må du godta at opplysningane under blir sende til SPNAME',
+        'da' => 'SPNAME kræver at nedenstående oplysninger overføres fra IDPNAME. Vil du acceptere dette?',
+        'en' => 'SPNAME requires that the information below is transferred.',
+        'de' => 'SPNAME erfordert die Ăśbertragung untenstehender Information von IDPNAME. Akzeptieren Sie das?',
+        'sv' => 'Du är på väg att logga in i tjänsten SPNAME. Tjänsten kräver att informationen nedan skickas från IDPNAME. Är detta okej?',
+        'fi' => 'Olet kirjautumassa palveluun SPNAME. Identiteetilähteesi henkilötietojasi palvelun tarjoajalle. Hyväksytkö tietojen siirron?',
+        'es' => 'Está a punto de acceder al servicio SPNAME. El servicio requiere que la información que se muestra a continuación sea transferida desde IDPNAME. ¿Acepta esto?  ',
+        'fr' => 'Vous êtes sur le point de vous connecter au service SPNAME. Lors de l\'ouverture de session, le fournisseur d\'identité enverra des informations sur votre identité à ce service. Acceptez-vous cela ?',
+        'nl' => 'U gaat inloggen bij een dienst SPNAME. Tijdens het loginproces stuurt de identity provider zgn. attributen met daarin informatie over uw identiteit voor deze dienst. Bent u het daarmee eens?',
+        'lb' => 'Daer sid dobai aerch um service unzemellen SPNAME. Waerend dem Login Prozess schéckt den Identity Provider Attributer, déi Informatiounen iwert aer Identitéit enthaalen. Akzeptéier daer daat?',
+        'sl' => 'Pravkar se nameravate prijaviti v storitev SPNAME. Med postopkom prijave bo IdP tej storitvi posredoval atribute, ki vsebujejo informacije o vaši identiteti. Ali se s tem strinjate? ',
+        'hr' => 'U tijeku je proces prijave za pristup servisu SPNAME. Servis zahtjeva da IDPNAME isporuÄŤi dolje navedene podatke. SlaĹľete li se s time?',
+        'hu' => 'Ön azonosítja magát ehhez a szolgáltatáshoz SPNAME. Az azonosítás során IDPNAME az alábbi adatokat fogja küldeni a szolgáltatásnak. Engedélyezi?',
+        'pl' => 'SPNAME wymaga aby poniższa informacja została przesłana.',
+        'pt' => 'O serviço SPNAME necessita que a informação apresentada em baixo seja transferida.',
+        'pt-br' => 'Você está prestes a acessar o serviço SPNAME. O serviço exige que as informações a seguir sejam transferidas do IDPNAME. Você aceita isso?',
+        'tr' => 'SPNAME aşağıdaki bilgilerin gönderilmesine ihtiyaç duyuyor.',
+    ],
+    'consent_purpose' => [
+        'no' => 'FormĂĄlet med SPNAME er SPDESC',
+        'nn' => 'Hensikta med SPNAME er SPDESC',
+        'da' => 'SPNAME har til formĂĄl at SPDESC',
+        'en' => 'The purpose of SPNAME is SPDESC',
+        'de' => 'Der Zweck von SPNAME ist SPDESC',
+        'sv' => 'Syftet med SPNAME är SPDESC',
+        'fi' => 'Palvelun SPNAME käyttötarkoitus on SPDESC',
+        'es' => 'El propĂłsito de SPNAME es SPDESC',
+        'nl' => 'Het doel van SPNAME is SPDESC',
+        'sl' => 'Namen %SPNAME%: %SPDESC%',
+        'hr' => 'Svrha SPNAME je SPDESC',
+        'hu' => 'A szolgáltatás (SPNAME) ezt a célt szolgálja: SPDESC',
+        'pl' => 'Celem SPNAME jest SPDESC',
+        'pt' => 'O propĂłsito de SPNAME Ă© SPDESC',
+        'tr' => 'SPNAME\'in amacı SPDESC\'tir',
+    ],
+    'consent_privacypolicy' => [
+        'no' => 'Personvern for tjenesten',
+        'nn' => 'Personvern for tenesta',
+        'da' => 'Tjenestens politik vedrørende personoplysninger',
+        'en' => 'Privacy policy for the service',
+        'de' => 'Datenschutzrichtlinie des Dienstes',
+        'sv' => 'Tjänstens policy för personlig integritet',
+        'fi' => 'Tietosuojaseloste palvelulle',
+        'es' => 'PolĂ­tica de privacidad para el servicio',
+        'nl' => 'Privacybeleid voor de dienst',
+        'sl' => 'Politika zasebnosti za ta SP',
+        'hr' => 'Politika zaštite privatnosti',
+        'hu' => 'A szolgáltatás adatvádelmi nyilatkozata',
+        'pl' => 'Polityka prywatności dla serwisu',
+        'pt' => 'Política de privacidade do serviço',
+        'pt-br' => 'Política de Privacidade deste serviço',
+        'tr' => 'Servis için gizlilik politikası',
+    ],
+    'consent_attributes_header' => [
+        'no' => 'Opplysninger som vil bli sendt til SPNAME',
+        'nn' => 'Opplysningar som blir sende til SPNAME',
+        'da' => 'Attributter som bliver sendt til SPNAME',
+        'en' => 'Information that will be sent to SPNAME',
+        'de' => 'Informationen, die an SPNAME gesandt werden',
+        'sv' => 'Attribut som kommer att skickas till tjänsten',
+        'fi' => 'Tiedot lähetetään palvelulle SPNAME',
+        'es' => 'Atributos que serán enviados al servicio',
+        'nl' => 'Informatie die naar SPNAME zal worden gestuurd',
+        'sl' => 'Atributi, ki bodo poslani SPju',
+        'hr' => 'Atributi koji će biti poslani servisu',
+        'hu' => 'A(z) SPNAME szolgáltatónak küldött adatok',
+        'pl' => 'Atrybuty, które zostaną przesłane do serwisu',
+        'pt' => 'Informação que irá ser enviada para SPNAME',
+        'tr' => 'SPNAME\'e gönderilecek bilgiler',
+    ],
+    'show_attributes' => [
+        'no' => 'Vis opplysninger',
+        'nn' => 'Vis opplysingar',
+        'da' => 'Vis attributter',
+        'en' => 'Show attributes',
+        'de' => 'Attribute zeigen',
+        'sv' => 'Visa attribut',
+        'fi' => 'Näytä henkilötiedot',
+        'es' => 'Mostrar atributos',
+        'nl' => 'Toon attributen',
+        'sl' => 'PrikaĹľi atribute',
+        'hr' => 'PrikaĹľi atribute',
+        'hu' => 'Mutasd az attribĂştumokat',
+        'pl' => 'Wyświetl atrybuty',
+        'pt' => 'Mostrar atributos',
+        'tr' => 'Özellikleri göster',
+    ],
+    'show_attribute' => [
+        'no' => 'Vis innhold',
+        'nn' => 'Vis innhald',
+        'da' => 'Vis indhold',
+        'en' => 'Show content',
+        'sv' => 'Visa samtycke',
+        'es' => 'Mostrart consentimiento',
+        'nl' => 'Toon inhoud',
+        'sl' => 'PrikaĹľi vsebino',
+    ],
+    'login' => [
+        'no' => 'innlogging',
+        'nn' => 'Logg inn',
+        'da' => 'login',
+        'en' => 'login',
+        'de' => 'anmelden',
+        'sv' => 'Logga in',
+        'fi' => 'Tunnus',
+        'es' => 'login',
+        'fr' => 'ouvrir une session',
+        'nl' => 'Login',
+        'lb' => 'anloggen',
+        'sl' => 'Prijava',
+        'hr' => 'prijava',
+        'hu' => 'bejelentkezés',
+        'pl' => 'login',
+        'pt' => 'Entrar',
+        'pt-br' => 'login',
+        'tr' => 'GiriĹź',
+    ],
+    'service_providers_for' => [
+        'no' => 'Tjenesteleverandør for',
+        'nn' => 'Tenesteleverandørar for',
+        'da' => 'Tjenesteudbyder for',
+        'en' => 'Service Providers for',
+        'de' => 'Service-Provider fĂĽr',
+        'sv' => 'Tjänsteleverantörer för',
+        'fi' => 'Palveluntarjoaja',
+        'es' => 'Proveedores de servicio para',
+        'fr' => 'Fournisseurs de services pour',
+        'nl' => 'Service Providers voor',
+        'lb' => 'Service Provider fir',
+        'sl' => 'SP za',
+        'hr' => 'Davatelji usluge za',
+        'hu' => 'Alkalmazásszolgáltatók a következő számára',
+        'pl' => 'Dostawca Serwisu dla',
+        'pt' => 'Fornecedores de Serviço (SP) para',
+        'pt-br' => 'Provedor de serviços para',
+        'tr' => 'için Servis Sağlayıcılar',
+    ],
+    'service_provider_header' => [
+        'no' => 'Tjenesteleverandør',
+        'nn' => 'Tenesteleverandør',
+        'da' => 'Tjenesteudbyder',
+        'en' => 'Service Provider',
+        'de' => 'Service-Provider',
+        'sv' => 'Tjänsteleverantör',
+        'fi' => 'Palveluntarjoaja',
+        'es' => 'Proveedor de servicio',
+        'fr' => 'Fournisseur de service',
+        'nl' => 'Service Provider',
+        'lb' => 'Service Provider',
+        'sl' => 'SP',
+        'hr' => 'Davatelj usluge',
+        'hu' => 'Alkalmazásszolgáltató',
+        'pl' => 'Dostawca serwisu',
+        'pt' => 'Fornecedor de Serviço (SP)',
+        'pt-br' => 'Provedor de Serviços',
+        'tr' => 'Servis Sağlayıcı',
+    ],
+    'status_header' => [
+        'no' => 'Samtykke-status',
+        'nn' => 'Samtykkestatus',
+        'da' => 'Samtykke status',
+        'en' => 'Consent status',
+        'de' => 'Zustimmungsstatus',
+        'sv' => 'Status för samtycke',
+        'fi' => 'Hyväksynnään tila',
+        'es' => 'Estado del consentimiento',
+        'fr' => 'État des consentements',
+        'nl' => 'Toestemming status',
+        'lb' => 'Zoustëmmungsstatus',
+        'sl' => 'Stanje privolitve',
+        'hr' => 'Status dozvole',
+        'hu' => 'Hozzájárulás állapota',
+        'pl' => 'Status zgody',
+        'pt' => 'Consentimento',
+        'pt-br' => 'Status do Consentimento',
+        'tr' => 'Onay durumu',
+    ],
+    'show_hide_attributes' => [
+        'no' => 'Vis/skjul opplysninger',
+        'nn' => 'Vis/skjul opplysningar',
+        'da' => 'vis/skjul attributter',
+        'en' => 'show/hide attributes',
+        'de' => 'zeige/verstecke Eigenschaften',
+        'sv' => 'visa/göm attribut',
+        'fi' => 'Näytä/piilota attribuutteja',
+        'es' => 'Mostrar/ocultar atributos',
+        'fr' => 'montrer/cacher les attributs',
+        'nl' => 'toon/verberg attributen',
+        'lb' => 'Attributer weisen/verstoppen',
+        'sl' => 'prikaĹľi/skrij atribute',
+        'hr' => 'prikaĹľi/sakrij atribute',
+        'hu' => 'attribútumok mutatása/elrejtése',
+        'pl' => 'pokaĹĽ/ukryj atrybuty',
+        'pt' => 'Mostrar/Ocultar atributos',
+        'pt-br' => 'mostra/esconder Atributos',
+        'tr' => 'bilgileri göster/gizle ',
+    ],
+    'noconsent_title' => [
+        'no' => 'Ikke akseptert overføring av informasjon',
+        'nn' => 'Ikkje akseptert overføring av informasjon',
+        'da' => 'Manglende samtykke',
+        'en' => 'No consent given',
+        'de' => 'Zustimmung verweigert',
+        'sv' => 'Inget samtycket givet',
+        'fi' => 'Lupaa ei annettu',
+        'es' => 'No se diĂł el consentimiento',
+        'nl' => 'Geen toestemming gegeven',
+        'sl' => 'Privolitev ni bila dana.',
+        'hr' => 'Nema pristanka',
+        'hu' => 'Nincs hozzájárulás',
+        'pl' => 'Nie wyraĹĽono zgody',
+        'pt' => 'Consentimento negado',
+        'pt-br' => 'Nenhum consentimento dado',
+        'tr' => 'Onay verilmemiĹź',
+    ],
+    'noconsent_text' => [
+        'no' => 'Du har ikke akseptert å overlevere opplysninger til tjenesteleverandøren.',
+        'nn' => 'Du har ikkje akseptert til at dine opplysningar kan sendast til tenesteleverandøren',
+        'da' => 'Du har ikke givet samtykke til overleveringen af oplysninger til tjenesten',
+        'en' => 'You did not give consent for transfering your attributes to the service provider.',
+        'de' => 'Sie haben der Weitergabe ihrer Daten an den Service Provider nicht zugestimmt.',
+        'sv' => 'Du gav inte samtycke för att överföra dina attribut till tjänsteleverantören.',
+        'fi' => 'Et antanut lupaa siirtää henkilötietojasi palveluntarjoajalle',
+        'es' => 'No ha dado su consentimiento para tranferir sus atributos al proveedor de servicio.',
+        'nl' => 'U heeft geen toestemming gegeven om uw attributen naar de Service Provider te versturen',
+        'sl' => 'Niste podali privolitve za posredovanje atributov SP-ju.',
+        'hr' => 'Niste dali pristanak da se vaši podaci isporuče davatelju usluge.',
+        'hu' => 'Nem adta hozzájárulását, hogy adatait továbbadjuk a szolgáltatónak.',
+        'pl' => 'Nie wyraziłeś zgody na przesłanie Twoich atrybutów do Dostawcy Serwisu.',
+        'pt' => 'Negou o consentimento para a transferência dos seus atributos para o fornecedor de serviço.',
+        'pt-br' => 'Você não deu o consentimento para a transferência de seus atributos para o provedor de serviços.',
+        'tr' => 'Bilgilerinizin servis sağlayıcıya gönderilmesi için onay vermediniz.',
+    ],
+    'noconsent_return' => [
+        'no' => 'GĂĄ tilbake til aksept-siden med opplysninger',
+        'nn' => 'Gå tilbake til aksept-sida for overføring av opplysningar',
+        'da' => 'GĂĄ tilbage',
+        'en' => 'Return to consent page',
+        'de' => 'ZurĂĽck',
+        'sv' => 'Åter till sidan för samtycke',
+        'fi' => 'Palaa hyväksyntäsivulle',
+        'es' => 'Volver a la página de consentimiento',
+        'nl' => 'Keer terug naar de toestemmingspagina',
+        'sl' => 'Vrnitev na privolitveno stran',
+        'hr' => 'Povratak na stranicu s dozvolama',
+        'hu' => 'Vissza az hozzájárulás-kezelő oldalra',
+        'pl' => 'PowrĂłt do strony wydania zezwolenia.',
+        'pt' => 'Voltar à página de consentimento',
+        'pt-br' => 'Retornar a página de consentimento',
+        'tr' => 'Onay sayfasına geri dön',
+    ],
+    'noconsent_goto_about' => [
+        'no' => 'GĂĄ til informasjonsside om tjenesten',
+        'nn' => 'GĂĄ til informasjonssida for tenesta',
+        'da' => 'GĂĄ til side med information om tjenesten',
+        'en' => 'Go to information page for the service',
+        'de' => 'Gehe zur Informationsseite dieses Dienstes',
+        'sv' => 'Gå till tjänstens informationssida',
+        'fi' => 'Siirry palvelun tiedot -sivulle',
+        'es' => 'Ir a la página de información del servicio',
+        'nl' => 'Ga naar de informatiepagina voor de service',
+        'sl' => 'Pojdi na spletno stran z informacijami o storitvi',
+        'hr' => 'Idi na stranicu s informacijama o servisu',
+        'hu' => 'A szolgáltatás információs oldalára',
+        'pl' => 'PrzejdĹş do strony informacyjnej dla tego serwisu',
+        'pt' => 'Ir para página de informação do serviço',
+        'tr' => 'Servis için bilgi sayfasına git',
+    ],
+    'table_caption' => [
+        'no' => 'Bruker innformasjon',
+        'da' => 'Bruger information',
+        'en' => 'User information',
+        'de' => 'Benutzerdaten',
+        'sv' => 'Användarinformation',
+        'fi' => 'Käyttäjätiedot',
+        'es' => 'InformaciĂłn del usuario',
+        'nl' => 'Gerbuikersinformatie',
+        'sl' => 'Podatki o uporabniku',
+        'hu' => 'Felhasználói információk',
+        'pt' => 'Informação do utilizador',
+        'tr' => 'Kullanıcı bilgisi',
+    ],
+    'table_summary' => [
+        'no' => 'Her listes den innformasjonen om deg som blir send til den tjenesten du er i ferd med ĂĄ logge pĂĄ',
+        'da' => 'Informationer som vil blive sendt til den service du er ved at logge in pĂĄ',
+        'en' => 'List the information about you that is about to be transmitted to the service you are going to login to',
+        'sv' => 'Visa den nformation om din användare som kommer att skickas till tjänsten som du är på väg att logga in i',
+        'fi' => 'Näytä tietosi, joita ollaan siirtämässä palveluun',
+        'es' => 'Muestra que informaciĂłn relativa a usted va a ser transmitida al servicio en el que se va a identificar',
+        'nl' => 'De informatie die over jou bekend is en naar de service waarop je wilt inloggen verstuurd zal worden',
+        'sl' => 'Seznam podatkov o vas, ki bodo posredovani storitvi, v katero se nameravate prijaviti',
+        'hu' => 'Ezeket az adatokat fogjuk elküldeni Önről annak a szolgáltatásnak, ahová be kíván jelentkezni',
+        'pt' => 'Listar a informação acerca de si que será enviada para o serviço no qual se está autenticar',
+        'tr' => 'Girmek istediğiniz servise gönderilecek bilginizi listeleyin',
+    ],
+];
diff --git a/modules/consent/dictionaries/consent.translation.json b/modules/consent/dictionaries/consent.translation.json
index 12ddfefed1040516adfc128ed30398bb6b32d71e..e454122655aaada5c7a6e6f8d3120adb31ac6b48 100644
--- a/modules/consent/dictionaries/consent.translation.json
+++ b/modules/consent/dictionaries/consent.translation.json
@@ -1,762 +1,762 @@
 {
-	"yes": {
-		"no": "Ja, fortsett",
-		"nn": "Ja, fortsett",
-		"sv": "Ja",
-		"es": "S\u00ed",
-		"fr": "Oui",
-		"de": "Ja, ich stimme zu",
-		"nl": "Ja, ik ga akkoord",
-		"lb": "Jo",
-		"sl": "Da, nadaljuj",
-		"da": "Ja, jeg accepterer",
-		"hr": "Da, nastavi",
-		"hu": "Igen, elfogadom",
-		"fi": "Kyll\u00e4",
-		"pt-br": "Sim, Aceito",
-		"pt": "Sim, Aceito",
-		"pl": "Tak, akceptuj\u0119",
-		"cs": "Ano, akceptuji",
-		"tr": "Evet, devam et",
-		"it": "S\u00ec, continuare",
-		"lt": "Taip, t\u0119sti",
-		"ja": "\u306f\u3044\u3001\u7d9a\u3051\u307e\u3059",
-		"zh-tw": "\u662f\uff0c\u7e7c\u7e8c",
-		"et": "Jah, j\u00e4tka",
-		"he": "\u05db\u05df, \u05d4\u05de\u05e9\u05da",
-		"ru": "\u0414\u0430, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c",
-		"zh": "\u662f\u7684\uff0c\u7ee7\u7eed",
-		"ar": "\u0646\u0639\u0645\u060c \u0648\u0627\u0635\u0644",
-		"lv": "J\u0101, turpin\u0101t",
-		"id": "Yam lanjutkan",
-		"sr": "Da, nastavi",
-		"ro": "Da, continu\u0103",
-		"eu": "Bai, jarraitu",
-		"af": "Ja, voortgaan",
-		"el": "\u0391\u03c0\u03bf\u03b4\u03bf\u03c7\u03ae"
-	},
-	"no": {
-		"no": "Nei, avbryt",
-		"nn": "Nei, avbryt",
-		"sv": "Nej",
-		"es": "No",
-		"fr": "Non",
-		"de": "Nein, ich stimme nicht zu",
-		"nl": "Nee, ik weiger",
-		"lb": "Nee",
-		"sl": "Ne, prekli\u010di",
-		"da": "Nej, jeg accepterer ikke",
-		"hr": "Ne, odustani",
-		"hu": "Nem, nem fogadom el",
-		"fi": "ei",
-		"pt-br": "N\u00e3o, n\u00e3o aceito",
-		"pt": "N\u00e3o aceito",
-		"pl": "Nie, nie akceptuj\u0119",
-		"cs": "Ne, neakceptuji",
-		"tr": "Hay\u0131r, iptal et",
-		"it": "No, cancellare",
-		"lt": "Ne, nutraukti",
-		"ja": "\u3044\u3044\u3048\u3001\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059",
-		"zh-tw": "\u4e0d\uff0c\u53d6\u6d88",
-		"et": "Ei, loobu",
-		"he": "\u05dc\u05d0, \u05d1\u05d8\u05dc",
-		"ru": "\u041d\u0435\u0442, \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
-		"zh": "\u4e0d\uff0c\u53d6\u6d88",
-		"ar": "\u0644\u0627\u060c \u0627\u0644\u063a",
-		"lv": "N\u0113, atcelt",
-		"id": "Tidak, batalkan",
-		"sr": "Ne, odustani",
-		"ro": "Nu, renun\u021b",
-		"eu": "Ez, utzi",
-		"af": "Nee, kanselleer",
-		"el": "\u0391\u03c0\u03cc\u03c1\u03c1\u03b9\u03c8\u03b7"
-	},
-	"remember": {
-		"no": "Godta ogs\u00e5 for fremtiden",
-		"nn": "Godta ogs\u00e5 for framtida",
-		"sv": "Spara samtycke",
-		"es": "Recordar el consentimiento",
-		"fr": "Se souvenir du consentement",
-		"de": "Zustimmung merken",
-		"nl": "Bewaar toestemming",
-		"lb": "Zoust\u00ebmmung verhalen",
-		"sl": "Zapomni si privolitev.",
-		"da": "Husk samtykke",
-		"hr": "Zapamti moj odabir",
-		"hu": "Eml\u00e9kezzen a hozz\u00e1j\u00e1rul\u00e1sra",
-		"fi": "Muista",
-		"pt-br": "Lembrar Consentimento",
-		"pt": "Lembrar a minha escolha",
-		"pl": "Pami\u0119taj moj\u0105 zgod\u0119",
-		"cs": "Zapamatuj",
-		"tr": "Hat\u0131rla",
-		"it": "Ricordare",
-		"lt": "\u012esiminti",
-		"ja": "\u8a18\u61b6\u3059\u308b",
-		"zh-tw": "\u8a18\u4f4f",
-		"et": "J\u00e4ta meelde",
-		"he": "\u05d6\u05db\u05d5\u05e8",
-		"ru": "\u0417\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c",
-		"zh": "\u8bb0\u4f4f",
-		"ar": "\u062a\u0630\u0643\u0631\u0623\u0644\u063a\u062a \u0630\u0643\u0631",
-		"lv": "Atcer\u0113ties",
-		"id": "Ingat",
-		"sr": "Zapamti moj izbor",
-		"ro": "\u021aine minte",
-		"eu": "Onespena gogoratu",
-		"af": "Onthou",
-		"el": "\u039d\u03b1 \u03b8\u03c5\u03bc\u03ac\u03c3\u03b1\u03b9 \u03c4\u03b7\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03bc\u03bf\u03c5"
-	},
-	"consent_accept": {
-		"no": "For \u00e5 fullf\u00f8re innloggingen m\u00e5 du godta at opplysningene nedenfor sendes til SPNAME.",
-		"nn": "For \u00e5 fullf\u00f8ra innlogginga m\u00e5 du godta at opplysningane under blir sende til SPNAME",
-		"sv": "Du \u00e4r p\u00e5 v\u00e4g att logga in i tj\u00e4nsten SPNAME. Tj\u00e4nsten kr\u00e4ver att informationen nedan skickas fr\u00e5n IDPNAME. \u00c4r detta okej?",
-		"es": "Est\u00e1 a punto de acceder al servicio SPNAME. El servicio requiere que la informaci\u00f3n que se muestra a continuaci\u00f3n sea transferida desde IDPNAME. \u00bfAcepta esto?",
-		"fr": "Vous \u00eates sur le point de vous connecter au service SPNAME. Lors de l'ouverture de session, le fournisseur d'identit\u00e9 enverra des informations sur votre identit\u00e9 \u00e0 ce service. Acceptez-vous cela ?",
-		"de": "SPNAME erfordert die \u00dcbertragung untenstehender Information von IDPNAME. Akzeptieren Sie das?",
-		"nl": "U gaat inloggen bij een dienst SPNAME. Tijdens het loginproces stuurt de identity provider zgn. attributen met daarin informatie over uw identiteit voor deze dienst. Bent u het daarmee eens?",
-		"lb": "Daer sid dobai aerch um service unzemellen SPNAME. Waerend dem Login Prozess sch\u00e9ckt den Identity Provider Attributer, d\u00e9i Informatiounen iwert aer Identit\u00e9it enthaalen. Akzept\u00e9ier daer daat?",
-		"sl": "Pravkar se nameravate prijaviti v storitev SPNAME. Med postopkom prijave bo IdP tej storitvi posredoval atribute, ki vsebujejo informacije o va\u0161i identiteti. Ali se s tem strinjate? ",
-		"da": "SPNAME kr\u00e6ver at nedenst\u00e5ende oplysninger overf\u00f8res fra IDPNAME. Vil du acceptere dette?",
-		"hr": "Servis SPNAME zahtjeva isporuku dolje navedenih podataka.",
-		"hu": "\u00d6n azonos\u00edtja mag\u00e1t ehhez a szolg\u00e1ltat\u00e1shoz SPNAME. Az azonos\u00edt\u00e1s sor\u00e1n IDPNAME az al\u00e1bbi adatokat fogja k\u00fcldeni a szolg\u00e1ltat\u00e1snak. Enged\u00e9lyezi?",
-		"fi": "Olet kirjautumassa palveluun SPNAME. Identiteetil\u00e4hteesi henkil\u00f6tietojasi palvelun tarjoajalle. Hyv\u00e4ksytk\u00f6 tietojen siirron?",
-		"pt-br": "Voc\u00ea est\u00e1 prestes a acessar o servi\u00e7o SPNAME. O servi\u00e7o exige que as informa\u00e7\u00f5es a seguir sejam transferidas do IDPNAME. Voc\u00ea aceita isso?",
-		"pt": "O servi\u00e7o SPNAME necessita que a informa\u00e7\u00e3o apresentada em baixo seja transferida.",
-		"pl": "SPNAME wymaga aby poni\u017csza informacja zosta\u0142a przes\u0142ana.",
-		"cs": "M\u016f\u017eete se p\u0159ihl\u00e1sit do slu\u017eby SPNAME",
-		"tr": "SPNAME a\u015fa\u011f\u0131daki bilgilerin g\u00f6nderilmesine ihtiya\u00e7 duyuyor.",
-		"it": "SPNAME richiede che l'informazione sotto riportata sia trasferita.",
-		"lt": "SPNAME reikalauja persi\u0173sti \u017eemiau pateikt\u0105 informacij\u0105",
-		"ja": "SPNAME\u306f\u4ee5\u4e0b\u306e\u5909\u63db\u3055\u308c\u305f\u60c5\u5831\u3092\u8981\u6c42\u3057\u307e\u3059\u3002",
-		"zh-tw": "SPNAME \u8981\u6c42\u8a72\u8cc7\u8a0a\u65bc\u9019\u500b\u50b3\u9001\u3002",
-		"et": "SPNAME n\u00f5uab allpool oleva info edastamist.",
-		"he": "SPNAME \u05d3\u05d5\u05e8\u05e9 \u05e9\u05de\u05d9\u05d3\u05e2 \u05d4\u05e0\"\u05dc \u05d9\u05d5\u05e2\u05d1\u05e8",
-		"ru": "SPNAME \u0442\u0440\u0435\u0431\u0443\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u043d\u0438\u0436\u0435, \u0431\u044b\u043b\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430.",
-		"zh": "SPNAME\u8bf7\u6c42\u7684\u4fe1\u606f\u5df2\u7ecf\u88ab\u4f20\u8f93\u51fa\u53bb",
-		"ar": "\u064a\u062d\u062a\u0627\u062c SPNAME \u062a\u062d\u0648\u064a\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0623\u062f\u0646\u0627\u0647 ",
-		"lv": "SPNAME prasa p\u0101rraid\u012bt pa t\u012bklu zem\u0101k eso\u0161o inform\u0101ciju.",
-		"id": "SPNAME mensyaratkan informasi dibawah ini harus ditransder.",
-		"sr": "Servis SPNAME zahteva slanje dole navedenih podataka.",
-		"ro": "SPNAME solicit\u0103 trimiterea informa\u021biilor de mai jos.",
-		"eu": "Zerbitzuak, hemen agertzen den informazioa lekualdatzea eskatzen du.",
-		"af": "SPNAME vereis dat die inligting hieronder oorgedra word.",
-		"el": "\u0395\u03ac\u03bd \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03ae\u03c3\u03b5\u03c4\u03b5\u002c \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03c5 \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03bf\u03cd\u03bd \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 <b>SPNAME<\/b>. \u03a3\u03c5\u03bc\u03c6\u03c9\u03bd\u03b5\u03af\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03b7\u03bd \u03b1\u03c0\u03b5\u03bb\u03b5\u03c5\u03b8\u03ad\u03c1\u03c9\u03c3\u03b7 \u03c4\u03c9\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd \u03b1\u03c5\u03c4\u03ce\u03bd \u03c3\u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03ba\u03ac\u03b8\u03b5 \u03c6\u03bf\u03c1\u03ac \u03c0\u03bf\u03c5 \u03b5\u03c0\u03b9\u03b8\u03c5\u03bc\u03b5\u03af\u03c4\u03b5 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae\u003b"
-	},
-	"login": {
-		"no": "innlogging",
-		"nn": "Logg inn",
-		"sv": "Logga in",
-		"es": "login",
-		"fr": "ouvrir une session",
-		"de": "anmelden",
-		"nl": "Login",
-		"lb": "anloggen",
-		"sl": "Prijava",
-		"da": "login",
-		"hr": "prijavi se",
-		"hu": "bejelentkez\u00e9s",
-		"fi": "Tunnus",
-		"pt-br": "login",
-		"pt": "Entrar",
-		"pl": "login",
-		"cs": "Login",
-		"tr": "Giri\u015f",
-		"it": "connessione",
-		"lt": "Prisijungti",
-		"ja": "\u30ed\u30b0\u30a4\u30f3",
-		"zh-tw": "\u767b\u5165",
-		"et": "logi sisse",
-		"he": "\u05db\u05e0\u05d9\u05e1\u05d4",
-		"ru": "\u041b\u043e\u0433\u0438\u043d",
-		"zh": "\u767b\u5f55",
-		"ar": "\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644",
-		"lv": "piesl\u0113gties",
-		"id": "login",
-		"sr": "prijavi se",
-		"ro": "autentificare",
-		"eu": "hasi saioa",
-		"af": "meld aan",
-		"el": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2"
-	},
-	"service_providers_for": {
-		"no": "Tjenesteleverand\u00f8r for",
-		"nn": "Tenesteleverand\u00f8rar for",
-		"sv": "Tj\u00e4nsteleverant\u00f6rer f\u00f6r",
-		"es": "Proveedores de servicio para",
-		"fr": "Fournisseurs de services pour",
-		"de": "Service-Provider f\u00fcr",
-		"nl": "Service Providers voor",
-		"lb": "Service Provider fir",
-		"sl": "SP za",
-		"da": "Tjenesteudbyder for",
-		"hr": "Davatelji usluge za",
-		"hu": "Alkalmaz\u00e1sszolg\u00e1ltat\u00f3k a k\u00f6vetkez\u0151 sz\u00e1m\u00e1ra",
-		"fi": "Palveluntarjoaja",
-		"pt-br": "Provedor de servi\u00e7os para",
-		"pt": "Fornecedores de Servi\u00e7o (SP) para",
-		"pl": "Dostawca Serwisu dla",
-		"cs": "Poskytovatel slu\u017eby pro",
-		"tr": "i\u00e7in Servis Sa\u011flay\u0131c\u0131lar",
-		"it": "Service Provider per",
-		"lt": "Paslaug\u0173 teik\u0117jai",
-		"ja": "\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0: ",
-		"zh-tw": "\u7d66\u670d\u52d9\u63d0\u4f9b\u8005",
-		"et": "Teenusepakkujad",
-		"he": "\u05e1\u05e4\u05e7\u05d9 \u05e9\u05d9\u05e8\u05d5\u05ea \u05e2\u05d1\u05d5\u05e8",
-		"ru": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0438 \u0443\u0441\u043b\u0443\u0433 \u0434\u043b\u044f",
-		"zh": "\u670d\u52a1\u63d0\u4f9b\u8005\u7ed9",
-		"ar": "\u0645\u0642\u062f\u0645\u064a \u062e\u062f\u0645\u0627\u062a \u0644",
-		"lv": "Servisa pieg\u0101d\u0101t\u0101ji priek\u0161",
-		"id": "Service Provider untuk",
-		"sr": "Davaoci Servisa za",
-		"ro": "Furnizor de servicii pentru",
-		"eu": "Zerbitzu hornitzaileak hontarako: ",
-		"af": "Diens Verskaffers vir",
-		"el": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03b9 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03b9\u03ce\u03bd \u03b3\u03b9\u03b1"
-	},
-	"service_provider_header": {
-		"no": "Tjenesteleverand\u00f8r",
-		"nn": "Tenesteleverand\u00f8r",
-		"sv": "Tj\u00e4nsteleverant\u00f6r",
-		"es": "Proveedor de servicio",
-		"fr": "Fournisseur de service",
-		"de": "Service-Provider",
-		"nl": "Service Provider",
-		"lb": "Service Provider",
-		"sl": "SP",
-		"da": "Tjenesteudbyder",
-		"hr": "Davatelj usluge",
-		"hu": "Alkalmaz\u00e1sszolg\u00e1ltat\u00f3",
-		"fi": "Palveluntarjoaja",
-		"pt-br": "Provedor de Servi\u00e7os",
-		"pt": "Fornecedor de Servi\u00e7o (SP)",
-		"pl": "Dostawca serwisu",
-		"cs": "Poskytovatel slu\u017eby",
-		"tr": "Servis Sa\u011flay\u0131c\u0131",
-		"it": "Service Provider",
-		"lt": "Paslaugos teik\u0117jas",
-		"ja": "\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0",
-		"zh-tw": "\u670d\u52d9\u63d0\u4f9b\u8005",
-		"et": "Teenusepakkuja",
-		"he": "\u05e1\u05e4\u05e7 \u05e9\u05d9\u05e8\u05d5\u05ea",
-		"ru": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0443\u0441\u043b\u0443\u0433",
-		"zh": "\u670d\u52a1\u63d0\u4f9b\u8005",
-		"ar": "\u0645\u0642\u062f\u0645 \u062e\u062f\u0645\u0627\u062a",
-		"lv": "Servisa pieg\u0101d\u0101t\u0101js",
-		"id": "Service Provider",
-		"sr": "Davalac Servisa",
-		"ro": "Furnizor de servicii",
-		"eu": "Zerbitzu hornitzailea",
-		"af": "Diens Verskaffer",
-		"el": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03c2 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u03c2"
-	},
-	"status_header": {
-		"no": "Samtykke-status",
-		"nn": "Samtykkestatus",
-		"sv": "Status f\u00f6r samtycke",
-		"es": "Estado del consentimiento",
-		"fr": "\u00c9tat des consentements",
-		"de": "Zustimmungsstatus",
-		"nl": "Toestemming status",
-		"lb": "Zoust\u00ebmmungsstatus",
-		"sl": "Stanje privolitve",
-		"da": "Samtykke status",
-		"hr": "Status odobrenja",
-		"hu": "Hozz\u00e1j\u00e1rul\u00e1s \u00e1llapota",
-		"fi": "Hyv\u00e4ksynn\u00e4\u00e4n tila",
-		"pt-br": "Status do Consentimento",
-		"pt": "Consentimento",
-		"pl": "Status zgody",
-		"cs": "Status souhlasu",
-		"tr": "Onay durumu",
-		"it": "Stato del consenso",
-		"lt": "Leidimo b\u016bsena",
-		"ja": "\u627f\u8a8d\u30b9\u30c6\u30fc\u30bf\u30b9",
-		"zh-tw": "\u540c\u610f\u72c0\u614b",
-		"et": "N\u00f5usoleku olek",
-		"he": "\u05de\u05e6\u05d1 \u05d4\u05e1\u05db\u05de\u05d4",
-		"ru": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441",
-		"zh": "\u540c\u610f\u72b6\u6001",
-		"ar": "\u062d\u0627\u0644\u0629 \u0645\u0648\u0627\u0641\u0642\u0629",
-		"lv": "Noteikumu statuss",
-		"id": "Status persetujuan",
-		"sr": "Status odobrenja",
-		"ro": "Stare acord",
-		"eu": "Onespen egoera",
-		"af": "Toestemming status",
-		"el": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
-	},
-	"show_hide_attributes": {
-		"no": "Vis\/skjul opplysninger",
-		"nn": "Vis\/skjul opplysningar",
-		"sv": "visa\/g\u00f6m attribut",
-		"es": "Mostrar\/ocultar atributos",
-		"fr": "montrer\/cacher les attributs",
-		"de": "zeige\/verstecke Eigenschaften",
-		"nl": "toon\/verberg attributen",
-		"lb": "Attributer weisen\/verstoppen",
-		"sl": "prika\u017ei\/skrij atribute",
-		"da": "vis\/skjul attributter",
-		"hr": "prika\u017ei\/sakrij atribute",
-		"hu": "attrib\u00fatumok mutat\u00e1sa\/elrejt\u00e9se",
-		"fi": "N\u00e4yt\u00e4\/piilota attribuutteja",
-		"pt-br": "mostra\/esconder Atributos",
-		"pt": "Mostrar\/Ocultar atributos",
-		"pl": "poka\u017c\/ukryj atrybuty",
-		"cs": "zobraz\/skryj atributy",
-		"tr": "bilgileri g\u00f6ster\/gizle ",
-		"it": "Mostra\/nascondi attributi",
-		"lt": "rodyti\/sl\u0117pti atributus",
-		"ja": "\u8868\u793a\/\u975e\u8868\u793a\u5c5e\u6027",
-		"zh-tw": "\u986f\u793a\/\u96b1\u85cf\u5c6c\u6027",
-		"et": "n\u00e4ita\/peida atribuudid",
-		"he": "\u05d4\u05e8\u05d0\u05d4\\\u05d4\u05e1\u05ea\u05e8 \u05ea\u05db\u05d5\u05e0\u05d5\u05ea ",
-		"ru": "\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\/\u0441\u043a\u0440\u044b\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
-		"zh": "\u663e\u793a\/\u9690\u85cf\u5c5e\u6027",
-		"ar": "\u0627\u0638\u0647\u0631\/\u0627\u0644\u063a\u064a \u0627\u0644\u0633\u0645\u0627\u062a",
-		"lv": "r\u0101d\u012bt\/sl\u0113pt atrib\u016btus",
-		"id": "perlihatkan\/sembunyikan attribut",
-		"sr": "prika\u017ei\/sakrij atribute",
-		"ro": "arat\u0103\/ascunde atributele",
-		"eu": "erakutsi\/gorde atributuak",
-		"af": "vertoon\/verberg eienskappe",
-		"el": "\u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\/\u03b1\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd"
-	},
-	"consent_privacypolicy": {
-		"no": "Personvern for tjenesten",
-		"nn": "Personvern for tenesta",
-		"sv": "Tj\u00e4nstens policy f\u00f6r personlig integritet",
-		"es": "Pol\u00edtica de privacidad para el servicio",
-		"de": "Datenschutzrichtlinie des Dienstes",
-		"nl": "Privacybeleid voor de dienst",
-		"sl": "Politika zasebnosti za ta SP",
-		"da": "Tjenestens politik vedr\u00f8rende personoplysninger",
-		"hr": "Politika za\u0161tite privatnosti kod servisa",
-		"hu": "A szolg\u00e1ltat\u00e1s adatv\u00e1delmi nyilatkozata",
-		"fi": "Tietosuojaseloste palvelulle",
-		"pt-br": "Pol\u00edtica de Privacidade deste servi\u00e7o",
-		"pt": "Pol\u00edtica de privacidade do servi\u00e7o",
-		"pl": "Polityka prywatno\u015bci dla serwisu",
-		"cs": "Bezpe\u010dnostn\u00ed politika slu\u017eby",
-		"tr": "Servis i\u00e7in gizlilik politikas\u0131",
-		"fr": "Politique de confidentialit\u00e9 pour ce service",
-		"it": "Politica della privacy per il servizio",
-		"lt": "\u0160ios paslaugos privatumo politika",
-		"ja": "\u30b5\u30fc\u30d3\u30b9\u306e\u30d7\u30e9\u30a4\u30d0\u30b7\u30dd\u30ea\u30b7\u30fc",
-		"zh-tw": "\u670d\u52d9\u96b1\u79c1\u6b0a\u653f\u7b56",
-		"et": "Teenuse privaatsuspoliitika",
-		"he": "\u05de\u05d3\u05d9\u05e0\u05d9\u05d5\u05ea \u05d4\u05e4\u05e8\u05d8\u05d9\u05d5\u05ea \u05e9\u05dc \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea",
-		"ru": "\u041f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043b\u0443\u0436\u0431\u044b",
-		"zh": "\u8be5\u670d\u52a1\u7684\u9690\u79c1\u7b56\u7565",
-		"ar": "\u0633\u064a\u0627\u0633\u0629 \u0627\u0644\u062e\u0635\u0648\u0635\u064a\u0629 \u0644\u0644\u062e\u062f\u0645\u0629",
-		"lv": "Servisa dro\u0161\u012bbas noteikumi",
-		"id": "Kebijakan privasi untuk layanan",
-		"sr": "Politika za\u0161tite privatnosti kod servisa",
-		"ro": "Politica de confiden\u021bialitate pentru serviciu",
-		"eu": "Zerbitzuarentzako pribatutasun-politika",
-		"af": "Privaatheidsbeleid vir die diens",
-		"el": "\u03a0\u03bf\u03bb\u03b9\u03c4\u03b9\u03ba\u03ae \u03c0\u03c1\u03bf\u03c3\u03c4\u03b1\u03c3\u03af\u03b1\u03c2 \u03b1\u03c0\u03bf\u03c1\u03c1\u03ae\u03c4\u03bf\u03c5 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u03c2"
-	},
-	"noconsent_title": {
-		"no": "Ikke akseptert overf\u00f8ring av informasjon",
-		"nn": "Ikkje akseptert overf\u00f8ring av informasjon",
-		"sv": "Inget samtycket givet",
-		"es": "No se di\u00f3 el consentimiento",
-		"de": "Zustimmung verweigert",
-		"nl": "Geen toestemming gegeven",
-		"sl": "Privolitev ni bila dana.",
-		"da": "Manglende samtykke",
-		"hr": "Isporuka podataka nije odobrena",
-		"hu": "Nincs hozz\u00e1j\u00e1rul\u00e1s",
-		"fi": "Lupaa ei annettu",
-		"pt-br": "Nenhum consentimento dado",
-		"pt": "Consentimento negado",
-		"pl": "Nie wyra\u017cono zgody",
-		"cs": "Souhlas nebyl vyd\u00e1n",
-		"tr": "Onay verilmemi\u015f",
-		"fr": "Aucun consentement n'a \u00e9t\u00e9 donn\u00e9",
-		"it": "Nessun consenso dato",
-		"lt": "Leidimas neduotas",
-		"ja": "\u627f\u8a8d\u306f\u3042\u308a\u307e\u305b\u3093",
-		"zh-tw": "\u5c1a\u672a\u540c\u610f",
-		"et": "N\u00f5usolekut pole antud",
-		"he": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05e0\u05d4 \u05d4\u05e1\u05db\u05de\u05d4",
-		"ru": "\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f",
-		"zh": "\u672a\u540c\u610f",
-		"ar": "\u0644\u0645 \u062a\u0639\u0637\u064a \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
-		"lv": "Nav noteikumu",
-		"id": "Tidan ada persetujuan yang diberikan",
-		"sr": "Slanje podataka nije odobreno",
-		"ro": "Nu a fost dat acordul (consim\u021b\u0103m\u00e2ntul)",
-		"eu": "Ez da onespena eman",
-		"af": "Geen toestemming is gegee nie",
-		"el": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03bf\u03c7\u03ae \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
-	},
-	"noconsent_text": {
-		"no": "Du har ikke akseptert \u00e5 overlevere opplysninger til SPNAME.",
-		"nn": "Du har ikkje akseptert til at dine opplysningar kan sendast til SPNAME.",
-		"sv": "Du gav inte samtycke f\u00f6r att \u00f6verf\u00f6ra dina attribut till tj\u00e4nsteleverant\u00f6ren.",
-		"es": "No ha dado su consentimiento para tranferir sus atributos al proveedor de servicio.",
-		"de": "Sie haben der Weitergabe ihrer Daten an den Service Provider nicht zugestimmt.",
-		"nl": "U heeft geen toestemming gegeven om uw attributen naar de Service Provider te versturen",
-		"sl": "Niste podali privolitve za posredovanje atributov SP-ju.",
-		"da": "Du har ikke givet samtykke til overleveringen af oplysninger til tjenesten",
-		"hr": "Niste dali pristanak da se va\u0161i podaci isporu\u010de davatelju usluge.",
-		"hu": "Nem adta hozz\u00e1j\u00e1rul\u00e1s\u00e1t, hogy adatait tov\u00e1bbadjuk a szolg\u00e1ltat\u00f3nak.",
-		"fi": "Et antanut lupaa siirt\u00e4\u00e4 henkil\u00f6tietojasi palveluntarjoajalle",
-		"pt-br": "Voc\u00ea n\u00e3o deu o consentimento para a transfer\u00eancia de seus atributos para o provedor de servi\u00e7os.",
-		"pt": "Negou o consentimento para a transfer\u00eancia dos seus atributos para o fornecedor de servi\u00e7o.",
-		"pl": "Nie wyrazi\u0142e\u015b zgody na przes\u0142anie Twoich atrybut\u00f3w do Dostawcy Serwisu.",
-		"cs": "Nedal jste souhlas pro zasl\u00e1n\u00ed sv\u00fdch atribut\u016f poskytovateli slu\u017eeb.",
-		"tr": "Bilgilerinizin servis sa\u011flay\u0131c\u0131ya g\u00f6nderilmesi i\u00e7in onay vermediniz.",
-		"fr": "Vous n'avez pas donn\u00e9 votre consentement \u00e0 la divulgation de vos attributs pour ce fournisseur de service.",
-		"it": "Non hai dato il consenso per trasferire i tuoi attributi al service provider.",
-		"lt": "J\u016bs nedav\u0117te sutikimo persi\u0173sti J\u016bs\u0173 atributus SPNAME paslaugos teik\u0117jui.",
-		"ja": "\u3042\u306a\u305f\u306f\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0\u306b\u5c5e\u6027\u3092\u8ee2\u9001\u3059\u308b\u4e8b\u3092\u627f\u8a8d\u3057\u3066\u3044\u307e\u305b\u3093\u3002",
-		"zh-tw": "\u60a8\u4e0d\u540c\u610f\u50b3\u8f38\u60a8\u7684\u5c6c\u6027\u81f3\u670d\u52d9\u63d0\u4f9b\u8005\u3002",
-		"et": "Sa ei andnud n\u00f5usolekut sinu atribuutide teenusepakkujale edastamiseks.",
-		"he": "\u05dc\u05d0 \u05e0\u05ea\u05e0\u05ea \u05d4\u05e1\u05db\u05de\u05d4 \u05dc\u05d4\u05e2\u05d1\u05e8\u05ea \u05d4\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9\u05dd \u05dc\u05e1\u05e4\u05e7 \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea.",
-		"ru": "\u0412\u044b \u043d\u0435 \u0434\u0430\u043b\u0438 \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0432\u0430\u0448\u0438\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u043a \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0443 \u0443\u0441\u043b\u0443\u0433.",
-		"zh": "\u4f60\u6ca1\u6709\u540c\u610f\u4f20\u8f93\u4f60\u7684\u76f8\u5173\u5c5e\u6027\u7ed9\u670d\u52a1\u63d0\u4f9b\u8005",
-		"ar": "\u0644\u0645 \u062a\u0648\u0627\u0641\u0642 \u0639\u0644\u064a \u062a\u062d\u0648\u064a\u0644 \u0633\u0645\u0627\u062a\u0643 \u0644\u0645\u0642\u062f\u0645 \u0627\u0644\u062e\u062f\u0645\u0629",
-		"lv": "J\u016bs neesat devis at\u013cauju p\u0101rraid\u012bt inform\u0101ciju servisa pieg\u0101d\u0101t\u0101jam.",
-		"id": "Anda tidak memberikan persetujuan untuk mentransfer atribut-atribute Anda ke service provider.",
-		"sr": "Niste odobrili da se va\u0161i podaci po\u0161alju davaocu servisa.",
-		"ro": "Nu a\u021bi fost de acord s\u0103 trimite\u021bi atributele c\u0103tre SPNAME.",
-		"eu": "Ez duzu onespena eman zure atributuak zerbitzuari transferitzeko.",
-		"af": "Jy het nie toestemming gegee vir die oordrag van jou eienskappe na SPNAME nie.",
-		"el": "\u0394\u03b5\u03bd \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b4\u03ce\u03c3\u03b5\u03b9 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7 \u03b3\u03b9\u03b1 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03bc\u03cc \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ce\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
-	},
-	"noconsent_return": {
-		"no": "G\u00e5 tilbake til samtykkesiden",
-		"nn": "G\u00e5 tilbake til samtykkesida",
-		"sv": "\u00c5ter till sidan f\u00f6r samtycke",
-		"es": "Volver a la p\u00e1gina de consentimiento",
-		"de": "Zur\u00fcck",
-		"nl": "Keer terug naar de toestemmingspagina",
-		"sl": "Vrnitev na privolitveno stran",
-		"da": "G\u00e5 tilbage",
-		"hr": "Povratak na stranicu za kreiranje dozvola",
-		"hu": "Vissza az hozz\u00e1j\u00e1rul\u00e1s-kezel\u0151 oldalra",
-		"fi": "Palaa hyv\u00e4ksynt\u00e4sivulle",
-		"pt-br": "Retornar a p\u00e1gina de consentimento",
-		"pt": "Voltar \u00e0 p\u00e1gina de consentimento",
-		"pl": "Powr\u00f3t do strony wydania zezwolenia.",
-		"cs": "Zp\u00e1tky na str\u00e1nku pro souhlas",
-		"tr": "Onay sayfas\u0131na geri d\u00f6n",
-		"fr": "Retour \u00e0 la page de consentement",
-		"it": "Torna alla pagina del consenso",
-		"lt": "Gr\u012f\u017eti \u012f leidim\u0173 puslap\u012f",
-		"ja": "\u627f\u8a8d\u30da\u30fc\u30b8\u306b\u623b\u308b",
-		"zh-tw": "\u56de\u5230\u540c\u610f\u9801\u9762",
-		"et": "Tagasi n\u00f5usoleku lehele",
-		"he": "\u05d7\u05d6\u05d5\u05e8 \u05dc\u05d3\u05e3 \u05d4\u05e1\u05db\u05de\u05d4",
-		"zh": "\u8fd4\u56de\u540c\u610f\u754c\u9762",
-		"ar": "\u0639\u062f \u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
-		"lv": "Atgriezties uz noteikumu lapu",
-		"id": "Kembali ke halaman persetujuan",
-		"sr": "Povratak na stranicu za kreiranje pristanka",
-		"ro": "\u00centoarcere la pagina de consim\u021b\u0103m\u00e2nt",
-		"ru": "\u0412\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u043b\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f",
-		"eu": "Itzuli onespen orrira",
-		"af": "Keer terug na die toestemmingsbladsy",
-		"el": "\u0395\u03c0\u03b9\u03c3\u03c4\u03c1\u03bf\u03c6\u03ae \u03c3\u03c4\u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1 \u03b4\u03ae\u03bb\u03c9\u03c3\u03b7\u03c2 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
-	},
-	"consent_header": {
-		"no": "Samtykke om overf\u00f8ring av personinformasjon",
-		"nn": "Samtykke til overf\u00f8ring av personinformasjon",
-		"sv": "Samtycke g\u00e4llande \u00f6verf\u00f6ring av personinformation",
-		"es": "Consentimiento para la liberaci\u00f3n de informaci\u00f3n personal",
-		"de": "Zustimmung zur Weitergabe pers\u00f6nlicher Daten",
-		"nl": "Toestemming voor het vrijgeven van persoonsgegevens",
-		"sl": "Odlo\u010ditev o privolitvi posredovanja va\u0161ih osebnih podatkov",
-		"da": "Samtykke til at frigive personlige oplysninger",
-		"hr": "Dozvola za isporuku osobnih podataka",
-		"hu": "Hozz\u00e1j\u00e1rul\u00e1s szem\u00e9lyes adatok kiad\u00e1s\u00e1hoz",
-		"fi": "Henkil\u00f6tietojen luovutuksen hyv\u00e4ksynt\u00e4",
-		"pt": "Consentimento do envio de informa\u00e7\u00e3o pessoal",
-		"pl": "Zgoda na wys\u0142anie danych osobistych",
-		"cs": "Obsah odes\u00edlan\u00fdch osobn\u00edch informac\u00ed",
-		"tr": "Ki\u015fisel bilgilerin verilmesi hakk\u0131nda onay",
-		"fr": "Consentement pour la divulgation d'informations personnelles",
-		"it": "Consenso al rilascio delle informazioni personali",
-		"lt": "Leidimas perduoti asmenin\u0119 informacij\u0105",
-		"ja": "\u500b\u4eba\u60c5\u5831\u306e\u627f\u8a8d\u3092\u89e3\u9664",
-		"zh-tw": "\u540c\u610f\u6709\u95dc\u65bc\u500b\u4eba\u95dc\u4fc2\u8cc7\u8a0a",
-		"et": "N\u00f5usolek isikuandmete edastamiseks",
-		"he": "\u05d4\u05e1\u05db\u05de\u05d4 \u05dc\u05d4\u05e2\u05d1\u05e8\u05ea \u05de\u05d9\u05d3\u05e2 \u05d0\u05d9\u05e9\u05d9",
-		"pt-br": "Consentimento sobre a libera\u00e7\u00e3o de informa\u00e7\u00f5es pessoais",
-		"zh": "\u540c\u610f\u5f00\u653e\u4e2a\u4eba\u4fe1\u606f",
-		"ar": "\u0627\u0648\u0627\u0641\u0642 \u0639\u0644\u064a \u0646\u0634\u0631 \u0633\u0645\u0627\u062a\u064a \u0627\u0644\u0634\u062e\u0635\u064a\u0629",
-		"lv": "Noteikumi par person\u012bg\u0101s inform\u0101cijas nodo\u0161anu",
-		"id": "Persetujuan tentang melepas informasi personal",
-		"sr": "Pristanak za slanje li\u010dnih podataka",
-		"ro": "Acordul pentru a furniza informa\u021bii personale",
-		"ru": "\u0421\u043e\u0433\u043b\u0430\u0441\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445",
-		"eu": "Informazio pertsonala askatzeko onespena ",
-		"af": "Toestemming mbt. die vrystelling van persoonlike informasie",
-		"el": "\u0394\u03ae\u03bb\u03c9\u03c3\u03b7 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03bc\u03cc \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ce\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd"
-	},
-	"consent_attributes_header": {
-		"no": "Opplysninger som vil bli sendt til SPNAME",
-		"nn": "Opplysningar som blir sende til SPNAME",
-		"sv": "Attribut som kommer att skickas till tj\u00e4nsten",
-		"es": "Atributos que ser\u00e1n enviados al servicio",
-		"de": "Informationen, die an SPNAME gesandt werden",
-		"nl": "Informatie die naar SPNAME zal worden gestuurd",
-		"sl": "Atributi, ki bodo poslani SPju",
-		"da": "Attributter som bliver sendt til SPNAME",
-		"hr": "Informacije koje \u0107e biti poslane servisu SPNAME",
-		"hu": "A(z) SPNAME szolg\u00e1ltat\u00f3nak k\u00fcld\u00f6tt adatok",
-		"fi": "Tiedot l\u00e4hetet\u00e4\u00e4n palvelulle SPNAME",
-		"pt": "Informa\u00e7\u00e3o que ir\u00e1 ser enviada para SPNAME",
-		"pl": "Atrybuty, kt\u00f3re zostan\u0105 przes\u0142ane do serwisu",
-		"cs": "Atributy, kter\u00e9 mohou b\u00fdt zasl\u00e1ny slu\u017eb\u011b",
-		"tr": "SPNAME'e g\u00f6nderilecek bilgiler",
-		"fr": "Informations qui seront envoy\u00e9es \u00e0 SPNAME",
-		"it": "Informazioni che saranno inviate a SPNAME",
-		"lt": "Informacija, kuri bus persi\u0173sta \u012f SPNAME",
-		"ja": "SPNAME\u3068\u3057\u3066\u9001\u4fe1\u3055\u308c\u308b\u60c5\u5831",
-		"zh-tw": "\u8cc7\u8a0a\u5c07\u88ab\u50b3\u9001\u81f3 SPNAME",
-		"et": "Andmed saadetakse SPNAME-le",
-		"he": "\u05d4\u05de\u05d9\u05d3\u05e2 \u05d9\u05e9\u05dc\u05d7 \u05dc SPNAME",
-		"zh": "\u4fe1\u606f\u5c06\u4f1a\u53d1\u9001\u7ed9SPNAME",
-		"ar": "\u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u062a\u064a \u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644\u0647\u0627 \u0644 SPNAME",
-		"lv": "Inform\u0101cija, kas tiks s\u016bt\u012bta SPNAME",
-		"id": "Informasi yang akan dikirim ke SPNAME",
-		"sr": "Informacije koje \u0107e biti poslate servisu SPNAME",
-		"ro": "Informa\u021bii care vor fi trimise la SPNAME",
-		"ru": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430 \u0432 SPNAME ",
-		"eu": "Zerbitzura bidaliko diren atributuak",
-		"af": "Informasie wat gestuur sal word na SPNAME",
-		"el": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
-	},
-	"show_attributes": {
-		"no": "Vis opplysninger",
-		"nn": "Vis opplysingar",
-		"sv": "Visa attribut",
-		"es": "Mostrar atributos",
-		"de": "Attribute zeigen",
-		"nl": "Toon attributen",
-		"sl": "Prika\u017ei atribute",
-		"da": "Vis attributter",
-		"hr": "Prika\u017ei atribute",
-		"hu": "Mutasd az attrib\u00fatumokat",
-		"fi": "N\u00e4yt\u00e4 henkil\u00f6tiedot",
-		"pt": "Mostrar atributos",
-		"pl": "Wy\u015bwietl atrybuty",
-		"cs": "Zobraz atributy",
-		"tr": "\u00d6zellikleri g\u00f6ster",
-		"fr": "Montrer les attributs",
-		"it": "Mostra attributi",
-		"lt": "Parodyti atributus",
-		"ja": "\u5c5e\u6027\u3092\u8868\u793a\u3059\u308b",
-		"zh-tw": "\u986f\u793a\u5c6c\u6027",
-		"et": "N\u00e4ita andmeid",
-		"he": "\u05d4\u05e6\u05d2 \u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9\u05dd",
-		"pt-br": "Mostrar atributos",
-		"zh": "\u663e\u793a\u5c5e\u6027",
-		"ar": "\u0627\u0638\u0647\u0631 \u0627\u0644\u0633\u0645\u0627\u062a",
-		"lv": "R\u0101d\u012bt atrib\u016btus",
-		"id": "Perlihatkan atribut-atribut",
-		"sr": "Prika\u017ei atribute",
-		"ro": "Arat\u0103 atributele",
-		"ru": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
-		"eu": "Erakutsi atributuak",
-		"af": "Vertoon eienskappe"
-	},
-	"noconsent_goto_about": {
-		"no": "G\u00e5 til informasjonsside om tjenesten",
-		"nn": "G\u00e5 til informasjonssida for tenesta",
-		"sv": "G\u00e5 till tj\u00e4nstens informationssida",
-		"es": "Ir a la p\u00e1gina de informaci\u00f3n del servicio",
-		"de": "Gehe zur Informationsseite dieses Dienstes",
-		"nl": "Ga naar de informatiepagina voor de service",
-		"sl": "Pojdi na spletno stran z informacijami o storitvi",
-		"da": "G\u00e5 til side med information om tjenesten",
-		"hr": "Idi na stranicu s informacijama o servisu",
-		"hu": "A szolg\u00e1ltat\u00e1s inform\u00e1ci\u00f3s oldal\u00e1ra",
-		"fi": "Siirry palvelun tiedot -sivulle",
-		"pt": "Ir para p\u00e1gina de informa\u00e7\u00e3o do servi\u00e7o",
-		"pl": "Przejd\u017a do strony informacyjnej dla tego serwisu",
-		"cs": "Jdi na str\u00e1nku s informacemi o slu\u017eb\u011b",
-		"tr": "Servis i\u00e7in bilgi sayfas\u0131na git",
-		"fr": "Aller \u00e0 la page d'information sur ce service",
-		"it": "Vai alla pagina di informazioni per il servizio",
-		"lt": "Pereiti \u012f \u0161ios paslaugos informacin\u012f puslap\u012f",
-		"ja": "\u30b5\u30fc\u30d3\u30b9\u306e\u70ba\u306e\u60c5\u5831\u30da\u30fc\u30b8\u3092\u53c2\u7167",
-		"zh-tw": "\u81f3\u670d\u52d9\u8cc7\u8a0a\u9801\u9762",
-		"et": "Mine teenuse infolehele",
-		"he": "\u05dc\u05da \u05d0\u05dc \u05d3\u05e3 \u05d4\u05de\u05d9\u05d3\u05e2 \u05e9\u05dc \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea",
-		"pt-br": "Ir para a P\u00e1gina de Informa\u00e7\u00e3o do servi\u00e7o",
-		"zh": "\u83b7\u53d6\u8be5\u670d\u52a1\u7684\u4fe1\u606f",
-		"ar": "\u0627\u0630\u0647\u0628 \u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0639\u0646 \u0627\u0644\u062e\u062f\u0645\u0629",
-		"lv": "Iet uz servisa inform\u0101cijas lapu",
-		"id": "Pergi ke halaman informasi untul layanan",
-		"sr": "Idi na stranicu sa informacijama o servisu",
-		"ro": "Link la pagina serviciului",
-		"ru": "\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u043b\u0443\u0436\u0431\u0435",
-		"eu": "Joan zerbitzuaren informazio orrira",
-		"af": "Gaan na die informasie bladsy vir die diens",
-		"el": "\u0395\u03c0\u03b9\u03c0\u03bb\u03ad\u03bf\u03bd \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1"
-	},
-	"consent_purpose": {
-		"no": "Form\u00e5let med SPNAME er SPDESC",
-		"nn": "Hensikta med SPNAME er SPDESC",
-		"sv": "Syftet med SPNAME \u00e4r SPDESC",
-		"es": "El prop\u00f3sito de SPNAME es SPDESC",
-		"de": "Der Zweck von SPNAME ist SPDESC",
-		"nl": "Het doel van SPNAME is SPDESC",
-		"sl": "Namen %SPNAME%: %SPDESC%",
-		"da": "SPNAME har til form\u00e5l at SPDESC",
-		"hr": "Namjena servisa SPNAME je SPDESC",
-		"hu": "A szolg\u00e1ltat\u00e1s (SPNAME) ezt a c\u00e9lt szolg\u00e1lja: SPDESC",
-		"fi": "Palvelun SPNAME k\u00e4ytt\u00f6tarkoitus on SPDESC",
-		"pt": "O prop\u00f3sito de SPNAME \u00e9 SPDESC",
-		"pl": "Celem SPNAME jest SPDESC",
-		"cs": "C\u00edl SPNAME v SPDESC",
-		"tr": "SPNAME'in amac\u0131 SPDESC'tir",
-		"fr": "L'objet de SPNAME est SPDESC",
-		"it": "Lo scopo di SPNAME \u00e8 SPDESC",
-		"lt": "SPNAME paskirtis yra SPDESC",
-		"ja": "SPNAME\u306e\u76ee\u7684\u306fSPDESC\u3067\u3059",
-		"zh-tw": "SPNAME \u7684\u76ee\u7684\u5730\u70ba SPDESC",
-		"et": "Teenuse SPNAME eesm\u00e4rk on SPDESC",
-		"he": "\u05d4\u05de\u05d8\u05e8\u05d4 \u05e9\u05dc SPNAME \u05d4\u05d9\u05d0 SPDESC",
-		"zh": "SPNAME\u7684\u76ee\u7684\u662fSPDESC",
-		"ar": "\u0627\u0644\u063a\u0631\u0636 \u0645\u0646 SPNAME \u0647\u0648 SPDESC",
-		"lv": "SPNAME nol\u016bks ir SPDESC",
-		"id": "Tujuan dari SPNAME adalah SPDESC",
-		"sr": "Namena servisa SPNAME je SPDESC",
-		"ro": "Scopul SPNAME este SPDESC",
-		"ru": "\u0426\u0435\u043b\u044c SPNAME - SPDESC",
-		"eu": "Zerbtizuaren xedea SPDESC da",
-		"af": "Die doel van SPNAME is SPDESC",
-		"el": "\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03cc\u03c0\u03c9\u03c2 \u03c0\u03b1\u03c1\u03ad\u03c7\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u003a SPDESC"
-	},
-	"table_caption": {
-		"no": "Bruker innformasjon",
-		"sv": "Anv\u00e4ndarinformation",
-		"es": "Informaci\u00f3n del usuario",
-		"de": "Benutzerdaten",
-		"nl": "Gerbuikersinformatie",
-		"sl": "Podatki o uporabniku",
-		"da": "Bruger information",
-		"hu": "Felhaszn\u00e1l\u00f3i inform\u00e1ci\u00f3k",
-		"fi": "K\u00e4ytt\u00e4j\u00e4tiedot",
-		"pt": "Informa\u00e7\u00e3o do utilizador",
-		"tr": "Kullan\u0131c\u0131 bilgisi",
-		"fr": "Information sur l'usager",
-		"hr": "Informacije o korisniku",
-		"nn": "Brukarinformasjon",
-		"it": "Informazioni utente",
-		"lt": "Vartotojo informacija",
-		"ja": "\u30e6\u30fc\u30b6\u30fc\u60c5\u5831",
-		"zh-tw": "\u4f7f\u7528\u8005\u8cc7\u8a0a",
-		"et": "Kasutajainfo",
-		"he": "\u05de\u05d9\u05d3\u05e2 \u05e2\u05dc \u05d4\u05de\u05e9\u05ea\u05de\u05e9",
-		"pt-br": "Informa\u00e7\u00f5es do Usu\u00e1rio",
-		"zh": "\u7528\u6237\u4fe1\u606f",
-		"ar": "\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645",
-		"lv": "Lietot\u0101ja inform\u0101cija",
-		"id": "Informasi User",
-		"sr": "Informacije o korisniku",
-		"ro": "Informa\u021bii despre utilizator",
-		"ru": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435",
-		"cs": "U\u017eivatelsk\u00e9 informace",
-		"eu": "Erabiltzailearen informazioa",
-		"af": "Gebruiker informasie",
-		"el": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7"
-	},
-	"table_summary": {
-		"no": "Her listes den innformasjonen om deg som blir send til den tjenesten du er i ferd med \u00e5 logge p\u00e5",
-		"sv": "Visa den nformation om din anv\u00e4ndare som kommer att skickas till tj\u00e4nsten som du \u00e4r p\u00e5 v\u00e4g att logga in i",
-		"es": "Muestra que informaci\u00f3n relativa a usted va a ser transmitida al servicio en el que se va a identificar",
-		"nl": "De informatie die over jou bekend is en naar de service waarop je wilt inloggen verstuurd zal worden",
-		"sl": "Seznam podatkov o vas, ki bodo posredovani storitvi, v katero se nameravate prijaviti",
-		"da": "Informationer som vil blive sendt til den service du er ved at logge in p\u00e5",
-		"hu": "Ezeket az adatokat fogjuk elk\u00fcldeni \u00d6nr\u0151l annak a szolg\u00e1ltat\u00e1snak, ahov\u00e1 be k\u00edv\u00e1n jelentkezni",
-		"fi": "N\u00e4yt\u00e4 tietosi, joita ollaan siirt\u00e4m\u00e4ss\u00e4 palveluun",
-		"pt": "Listar a informa\u00e7\u00e3o acerca de si que ser\u00e1 enviada para o servi\u00e7o no qual se est\u00e1 autenticar",
-		"tr": "Girmek istedi\u011finiz servise g\u00f6nderilecek bilginizi listeleyin",
-		"de": "Zeige die Information \u00fcber Sie, die an den Service, auf dem Sie sich einloggen werden, \u00fcbermittelt werden",
-		"fr": "Liste des informations vous concernant qui seront envoy\u00e9es au service auquel vous allez vous connecter",
-		"hr": "Prika\u017ei popis va\u0161ih podataka koji \u0107e biti proslje\u0111eni servisu kojem \u017eelite pristupiti",
-		"nn": "List informasjon om deg som blir overf\u00f8rt til tenesta du skal logga inn p\u00e5",
-		"it": "Mostra le informazioni su di te che stanno per essere trasferire al servizio a cui ti vuoi collegare",
-		"lt": "Per\u017ei\u016br\u0117ti informacij\u0105 apie jus, kuri bus persi\u0173sta paslaugai, \u012f kuri\u0105 jungiat\u0117s",
-		"ja": "\u4e00\u89a7\u306e\u60c5\u5831\u306f\u3042\u306a\u305f\u304c\u30ed\u30b0\u30a4\u30f3\u3059\u308b\u969b\u306b\u30b5\u30fc\u30d3\u30b9\u306b\u8ee2\u9001\u3055\u308c\u307e\u3059\u3002",
-		"zh-tw": "\u5c07\u95dc\u65bc\u6211\u50b3\u9001\u81f3\u60a8\u9810\u8a08\u8981\u767b\u5165\u7684\u670d\u52d9",
-		"et": "Teave sinu kohta, mis edastatakse teenusele, millesse asud sisse logima",
-		"he": "\u05d4\u05e6\u05d2 \u05d0\u05ea \u05d4\u05de\u05d9\u05d3\u05e2 \u05e2\u05dc\u05d9\u05da \u05d0\u05e9\u05e8 \u05d9\u05d5\u05e2\u05d1\u05e8 \u05dc\u05e9\u05d9\u05e8\u05d5\u05ea \u05e9\u05d0\u05ea\u05d4 \u05e2\u05d5\u05de\u05d3 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05d0\u05dc\u05d9\u05d5",
-		"pt-br": "Liste as informa\u00e7\u00f5es sobre voc\u00ea que est\u00e1 prestes a ser transmitida para o servi\u00e7o que voc\u00ea est\u00e1 acessando",
-		"zh": "\u5f53\u4f60\u767b\u5f55\u65f6\u5c06\u8981\u4f20\u8f93\u7ed9\u670d\u52a1\u7684\u4fe1\u606f\u5217\u8868",
-		"ar": "\u0642\u0627\u0626\u0645\u0629 \u0645\u0639\u0644\u0648\u0645\u0627\u062a\u0643 \u0627\u0644\u062a\u064a \u0633\u062a\u062d\u0648\u0644 \u0644\u0645\u0642\u062f\u0645 \u0627\u0644\u062e\u062f\u0645\u0629 \u0627\u0644\u0630\u064a \u062a\u0631\u063a\u0628 \u0628\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0627\u0644\u064a\u0647",
-		"lv": "Inform\u0101cija par Jums, kas tiks s\u016bt\u012bta servisam, kuram J\u016bs piesl\u0113dzaties",
-		"id": "Daftar informasi tentang Anda yang akan dikirimkan ke service tujuan login Anda.",
-		"sr": "Prika\u017ei spisak podataka o vama koji \u0107e biti prosle\u0111eni servisu kome \u017eelite pristupiti",
-		"ro": "Afi\u0219eaz\u0103 informa\u021biile care vor fi trimise la serviciul unde dori\u021bi s\u0103 v\u0103 autentifica\u021bi",
-		"ru": "\u0412\u044b\u0434\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430 \u0441\u043b\u0443\u0436\u0431\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0432\u043e\u0439\u0442\u0438",
-		"cs": "Seznam informac\u00ed o v\u00e1s, kter\u00e9 budou p\u0159ed\u00e1ny slu\u017eb\u011b, ke kter\u00e9 se p\u0159ihla\u0161ujete",
-		"eu": "Zu identifikatuko zaren zerbitzura zure ze informazio bidaliko den erakusten du ",
-		"af": "Lys die informasie mbt. jou wat op die punt is om gestuur te word vir die diens waarby jy wil aanmeld.",
-		"el": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae"
-	},
-	"show_attribute": {
-		"no": "Vis innhold",
-		"nn": "Vis innhald",
-		"sv": "Visa samtycke",
-		"es": "Mostrart consentimiento",
-		"nl": "Toon inhoud",
-		"sl": "Prika\u017ei vsebino",
-		"da": "Vis indhold",
-		"de": "Zeige Inhalt",
-		"pt": "Mostrar conte\u00fado",
-		"fr": "Montrer le contenu",
-		"hr": "Prika\u017ei sadr\u017eaj",
-		"it": "Mostra contenuto",
-		"hu": "R\u00e9szletek",
-		"lt": "Parodyti leidim\u0105",
-		"ja": "\u5185\u5bb9\u3092\u8868\u793a\u3059\u308b",
-		"zh-tw": "\u986f\u793a\u5167\u5bb9",
-		"pl": "Wy\u015bwietl zawarto\u015b\u0107",
-		"et": "N\u00e4ita sisu",
-		"he": "\u05d4\u05e6\u05d2 \u05ea\u05d5\u05db\u05df",
-		"pt-br": "Mostrar Conte\u00fado",
-		"zh": "\u663e\u793a\u5185\u5bb9",
-		"ar": "\u0627\u0638\u0647\u0631\u0627\u0644\u064a\u0647\u0627 \u0638\u0647\u0631 \u0627\u0644\u0645\u062d\u062a\u0648\u064a",
-		"lv": "R\u0101d\u012bt saturu",
-		"id": "Perlihatkan konten",
-		"sr": "Prika\u017ei sadr\u017eaj",
-		"ro": "Arat\u0103 con\u021binutul",
-		"ru": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435",
-		"cs": "Zobrazit obsah",
-		"eu": "Erakutsi onespena",
-		"af": "Vertoon inhoud",
-		"el": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03b5\u03c1\u03b5\u03b9\u03ce\u03bd"
-	},
-	"abort": {
-		"no": "Avbryt innlogging til SPNAME",
-		"nn": "Avbryt innlogging til SPNAME",
-		"lt": "At\u0161aukti prisijungim\u0105 prie SPNAME",
-		"sr": "Prekini prijavu na SPNAME",
-		"it": "Login interrotto a SPNAME",
-		"fr": "Annuler la connexion au fournisseur de service SPNAME",
-		"de": "Anmeldung am Service Provider SPNAME abbrechen",
-		"et": "Katkesta sisselogimine: SPNAME",
-		"nl": "Inloggen op SPNAME afbreken",
-		"es": "Cancelar la identificaci\u00f3n en SPNAME",
-		"ro": "Anuleaz\u0103 cererea de autentificare la SPNAME",
-		"ar": "\u0625\u0644\u063a\u0627\u0621 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062f\u062e\u0648\u0644 \u0644SPNAME",
-		"ru": "\u041f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043d \u0432 SPNAME",
-		"cs": "Zru\u0161it p\u0159ihl\u00e1\u0161en\u00ed k SPNAME",
-		"hr": "Odustani od prijave u SPNAME",
-		"zh": "\u4e2d\u6b62\u767b\u5f55\u5230SPNAME",
-		"eu": "Bertan behera utzi zerbitzuan identifikazioa",
-		"zh-tw": "\u95dc\u65bc\u767b\u5165\u81f3 SPNAME",
-		"da": "Afbryd login til SPNAME",
-		"af": "Kanseleer aanmelding na SPNAME",
-		"el": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03b5\u03b9\u03c3\u03cc\u03b4\u03bf\u03c5 \u03c3\u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
-	}
+    "yes": {
+        "no": "Ja, fortsett",
+        "nn": "Ja, fortsett",
+        "sv": "Ja",
+        "es": "S\u00ed",
+        "fr": "Oui",
+        "de": "Ja, ich stimme zu",
+        "nl": "Ja, ik ga akkoord",
+        "lb": "Jo",
+        "sl": "Da, nadaljuj",
+        "da": "Ja, jeg accepterer",
+        "hr": "Da, nastavi",
+        "hu": "Igen, elfogadom",
+        "fi": "Kyll\u00e4",
+        "pt-br": "Sim, Aceito",
+        "pt": "Sim, Aceito",
+        "pl": "Tak, akceptuj\u0119",
+        "cs": "Ano, akceptuji",
+        "tr": "Evet, devam et",
+        "it": "S\u00ec, continuare",
+        "lt": "Taip, t\u0119sti",
+        "ja": "\u306f\u3044\u3001\u7d9a\u3051\u307e\u3059",
+        "zh-tw": "\u662f\uff0c\u7e7c\u7e8c",
+        "et": "Jah, j\u00e4tka",
+        "he": "\u05db\u05df, \u05d4\u05de\u05e9\u05da",
+        "ru": "\u0414\u0430, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c",
+        "zh": "\u662f\u7684\uff0c\u7ee7\u7eed",
+        "ar": "\u0646\u0639\u0645\u060c \u0648\u0627\u0635\u0644",
+        "lv": "J\u0101, turpin\u0101t",
+        "id": "Yam lanjutkan",
+        "sr": "Da, nastavi",
+        "ro": "Da, continu\u0103",
+        "eu": "Bai, jarraitu",
+        "af": "Ja, voortgaan",
+        "el": "\u0391\u03c0\u03bf\u03b4\u03bf\u03c7\u03ae"
+    },
+    "no": {
+        "no": "Nei, avbryt",
+        "nn": "Nei, avbryt",
+        "sv": "Nej",
+        "es": "No",
+        "fr": "Non",
+        "de": "Nein, ich stimme nicht zu",
+        "nl": "Nee, ik weiger",
+        "lb": "Nee",
+        "sl": "Ne, prekli\u010di",
+        "da": "Nej, jeg accepterer ikke",
+        "hr": "Ne, odustani",
+        "hu": "Nem, nem fogadom el",
+        "fi": "ei",
+        "pt-br": "N\u00e3o, n\u00e3o aceito",
+        "pt": "N\u00e3o aceito",
+        "pl": "Nie, nie akceptuj\u0119",
+        "cs": "Ne, neakceptuji",
+        "tr": "Hay\u0131r, iptal et",
+        "it": "No, cancellare",
+        "lt": "Ne, nutraukti",
+        "ja": "\u3044\u3044\u3048\u3001\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059",
+        "zh-tw": "\u4e0d\uff0c\u53d6\u6d88",
+        "et": "Ei, loobu",
+        "he": "\u05dc\u05d0, \u05d1\u05d8\u05dc",
+        "ru": "\u041d\u0435\u0442, \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c",
+        "zh": "\u4e0d\uff0c\u53d6\u6d88",
+        "ar": "\u0644\u0627\u060c \u0627\u0644\u063a",
+        "lv": "N\u0113, atcelt",
+        "id": "Tidak, batalkan",
+        "sr": "Ne, odustani",
+        "ro": "Nu, renun\u021b",
+        "eu": "Ez, utzi",
+        "af": "Nee, kanselleer",
+        "el": "\u0391\u03c0\u03cc\u03c1\u03c1\u03b9\u03c8\u03b7"
+    },
+    "remember": {
+        "no": "Godta ogs\u00e5 for fremtiden",
+        "nn": "Godta ogs\u00e5 for framtida",
+        "sv": "Spara samtycke",
+        "es": "Recordar el consentimiento",
+        "fr": "Se souvenir du consentement",
+        "de": "Zustimmung merken",
+        "nl": "Bewaar toestemming",
+        "lb": "Zoust\u00ebmmung verhalen",
+        "sl": "Zapomni si privolitev.",
+        "da": "Husk samtykke",
+        "hr": "Zapamti moj odabir",
+        "hu": "Eml\u00e9kezzen a hozz\u00e1j\u00e1rul\u00e1sra",
+        "fi": "Muista",
+        "pt-br": "Lembrar Consentimento",
+        "pt": "Lembrar a minha escolha",
+        "pl": "Pami\u0119taj moj\u0105 zgod\u0119",
+        "cs": "Zapamatuj",
+        "tr": "Hat\u0131rla",
+        "it": "Ricordare",
+        "lt": "\u012esiminti",
+        "ja": "\u8a18\u61b6\u3059\u308b",
+        "zh-tw": "\u8a18\u4f4f",
+        "et": "J\u00e4ta meelde",
+        "he": "\u05d6\u05db\u05d5\u05e8",
+        "ru": "\u0417\u0430\u043f\u043e\u043c\u043d\u0438\u0442\u044c",
+        "zh": "\u8bb0\u4f4f",
+        "ar": "\u062a\u0630\u0643\u0631\u0623\u0644\u063a\u062a \u0630\u0643\u0631",
+        "lv": "Atcer\u0113ties",
+        "id": "Ingat",
+        "sr": "Zapamti moj izbor",
+        "ro": "\u021aine minte",
+        "eu": "Onespena gogoratu",
+        "af": "Onthou",
+        "el": "\u039d\u03b1 \u03b8\u03c5\u03bc\u03ac\u03c3\u03b1\u03b9 \u03c4\u03b7\u03bd \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \u03bc\u03bf\u03c5"
+    },
+    "consent_accept": {
+        "no": "For \u00e5 fullf\u00f8re innloggingen m\u00e5 du godta at opplysningene nedenfor sendes til SPNAME.",
+        "nn": "For \u00e5 fullf\u00f8ra innlogginga m\u00e5 du godta at opplysningane under blir sende til SPNAME",
+        "sv": "Du \u00e4r p\u00e5 v\u00e4g att logga in i tj\u00e4nsten SPNAME. Tj\u00e4nsten kr\u00e4ver att informationen nedan skickas fr\u00e5n IDPNAME. \u00c4r detta okej?",
+        "es": "Est\u00e1 a punto de acceder al servicio SPNAME. El servicio requiere que la informaci\u00f3n que se muestra a continuaci\u00f3n sea transferida desde IDPNAME. \u00bfAcepta esto?",
+        "fr": "Vous \u00eates sur le point de vous connecter au service SPNAME. Lors de l'ouverture de session, le fournisseur d'identit\u00e9 enverra des informations sur votre identit\u00e9 \u00e0 ce service. Acceptez-vous cela ?",
+        "de": "SPNAME erfordert die \u00dcbertragung untenstehender Information von IDPNAME. Akzeptieren Sie das?",
+        "nl": "U gaat inloggen bij een dienst SPNAME. Tijdens het loginproces stuurt de identity provider zgn. attributen met daarin informatie over uw identiteit voor deze dienst. Bent u het daarmee eens?",
+        "lb": "Daer sid dobai aerch um service unzemellen SPNAME. Waerend dem Login Prozess sch\u00e9ckt den Identity Provider Attributer, d\u00e9i Informatiounen iwert aer Identit\u00e9it enthaalen. Akzept\u00e9ier daer daat?",
+        "sl": "Pravkar se nameravate prijaviti v storitev SPNAME. Med postopkom prijave bo IdP tej storitvi posredoval atribute, ki vsebujejo informacije o va\u0161i identiteti. Ali se s tem strinjate? ",
+        "da": "SPNAME kr\u00e6ver at nedenst\u00e5ende oplysninger overf\u00f8res fra IDPNAME. Vil du acceptere dette?",
+        "hr": "Servis SPNAME zahtjeva isporuku dolje navedenih podataka.",
+        "hu": "\u00d6n azonos\u00edtja mag\u00e1t ehhez a szolg\u00e1ltat\u00e1shoz SPNAME. Az azonos\u00edt\u00e1s sor\u00e1n IDPNAME az al\u00e1bbi adatokat fogja k\u00fcldeni a szolg\u00e1ltat\u00e1snak. Enged\u00e9lyezi?",
+        "fi": "Olet kirjautumassa palveluun SPNAME. Identiteetil\u00e4hteesi henkil\u00f6tietojasi palvelun tarjoajalle. Hyv\u00e4ksytk\u00f6 tietojen siirron?",
+        "pt-br": "Voc\u00ea est\u00e1 prestes a acessar o servi\u00e7o SPNAME. O servi\u00e7o exige que as informa\u00e7\u00f5es a seguir sejam transferidas do IDPNAME. Voc\u00ea aceita isso?",
+        "pt": "O servi\u00e7o SPNAME necessita que a informa\u00e7\u00e3o apresentada em baixo seja transferida.",
+        "pl": "SPNAME wymaga aby poni\u017csza informacja zosta\u0142a przes\u0142ana.",
+        "cs": "M\u016f\u017eete se p\u0159ihl\u00e1sit do slu\u017eby SPNAME",
+        "tr": "SPNAME a\u015fa\u011f\u0131daki bilgilerin g\u00f6nderilmesine ihtiya\u00e7 duyuyor.",
+        "it": "SPNAME richiede che l'informazione sotto riportata sia trasferita.",
+        "lt": "SPNAME reikalauja persi\u0173sti \u017eemiau pateikt\u0105 informacij\u0105",
+        "ja": "SPNAME\u306f\u4ee5\u4e0b\u306e\u5909\u63db\u3055\u308c\u305f\u60c5\u5831\u3092\u8981\u6c42\u3057\u307e\u3059\u3002",
+        "zh-tw": "SPNAME \u8981\u6c42\u8a72\u8cc7\u8a0a\u65bc\u9019\u500b\u50b3\u9001\u3002",
+        "et": "SPNAME n\u00f5uab allpool oleva info edastamist.",
+        "he": "SPNAME \u05d3\u05d5\u05e8\u05e9 \u05e9\u05de\u05d9\u05d3\u05e2 \u05d4\u05e0\"\u05dc \u05d9\u05d5\u05e2\u05d1\u05e8",
+        "ru": "SPNAME \u0442\u0440\u0435\u0431\u0443\u0435\u0442, \u0447\u0442\u043e\u0431\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u043d\u0438\u0436\u0435, \u0431\u044b\u043b\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430.",
+        "zh": "SPNAME\u8bf7\u6c42\u7684\u4fe1\u606f\u5df2\u7ecf\u88ab\u4f20\u8f93\u51fa\u53bb",
+        "ar": "\u064a\u062d\u062a\u0627\u062c SPNAME \u062a\u062d\u0648\u064a\u0644 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a \u0623\u062f\u0646\u0627\u0647 ",
+        "lv": "SPNAME prasa p\u0101rraid\u012bt pa t\u012bklu zem\u0101k eso\u0161o inform\u0101ciju.",
+        "id": "SPNAME mensyaratkan informasi dibawah ini harus ditransder.",
+        "sr": "Servis SPNAME zahteva slanje dole navedenih podataka.",
+        "ro": "SPNAME solicit\u0103 trimiterea informa\u021biilor de mai jos.",
+        "eu": "Zerbitzuak, hemen agertzen den informazioa lekualdatzea eskatzen du.",
+        "af": "SPNAME vereis dat die inligting hieronder oorgedra word.",
+        "el": "\u0395\u03ac\u03bd \u03c0\u03c1\u03bf\u03c7\u03c9\u03c1\u03ae\u03c3\u03b5\u03c4\u03b5\u002c \u03c4\u03b1 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03b1 \u03c0\u03bf\u03c5 \u03b1\u03ba\u03bf\u03bb\u03bf\u03c5\u03b8\u03bf\u03cd\u03bd \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 <b>SPNAME<\/b>. \u03a3\u03c5\u03bc\u03c6\u03c9\u03bd\u03b5\u03af\u03c4\u03b5 \u03bc\u03b5 \u03c4\u03b7\u03bd \u03b1\u03c0\u03b5\u03bb\u03b5\u03c5\u03b8\u03ad\u03c1\u03c9\u03c3\u03b7 \u03c4\u03c9\u03bd \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd \u03b1\u03c5\u03c4\u03ce\u03bd \u03c3\u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03ba\u03ac\u03b8\u03b5 \u03c6\u03bf\u03c1\u03ac \u03c0\u03bf\u03c5 \u03b5\u03c0\u03b9\u03b8\u03c5\u03bc\u03b5\u03af\u03c4\u03b5 \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae\u003b"
+    },
+    "login": {
+        "no": "innlogging",
+        "nn": "Logg inn",
+        "sv": "Logga in",
+        "es": "login",
+        "fr": "ouvrir une session",
+        "de": "anmelden",
+        "nl": "Login",
+        "lb": "anloggen",
+        "sl": "Prijava",
+        "da": "login",
+        "hr": "prijavi se",
+        "hu": "bejelentkez\u00e9s",
+        "fi": "Tunnus",
+        "pt-br": "login",
+        "pt": "Entrar",
+        "pl": "login",
+        "cs": "Login",
+        "tr": "Giri\u015f",
+        "it": "connessione",
+        "lt": "Prisijungti",
+        "ja": "\u30ed\u30b0\u30a4\u30f3",
+        "zh-tw": "\u767b\u5165",
+        "et": "logi sisse",
+        "he": "\u05db\u05e0\u05d9\u05e1\u05d4",
+        "ru": "\u041b\u043e\u0433\u0438\u043d",
+        "zh": "\u767b\u5f55",
+        "ar": "\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644",
+        "lv": "piesl\u0113gties",
+        "id": "login",
+        "sr": "prijavi se",
+        "ro": "autentificare",
+        "eu": "hasi saioa",
+        "af": "meld aan",
+        "el": "\u0395\u03af\u03c3\u03bf\u03b4\u03bf\u03c2"
+    },
+    "service_providers_for": {
+        "no": "Tjenesteleverand\u00f8r for",
+        "nn": "Tenesteleverand\u00f8rar for",
+        "sv": "Tj\u00e4nsteleverant\u00f6rer f\u00f6r",
+        "es": "Proveedores de servicio para",
+        "fr": "Fournisseurs de services pour",
+        "de": "Service-Provider f\u00fcr",
+        "nl": "Service Providers voor",
+        "lb": "Service Provider fir",
+        "sl": "SP za",
+        "da": "Tjenesteudbyder for",
+        "hr": "Davatelji usluge za",
+        "hu": "Alkalmaz\u00e1sszolg\u00e1ltat\u00f3k a k\u00f6vetkez\u0151 sz\u00e1m\u00e1ra",
+        "fi": "Palveluntarjoaja",
+        "pt-br": "Provedor de servi\u00e7os para",
+        "pt": "Fornecedores de Servi\u00e7o (SP) para",
+        "pl": "Dostawca Serwisu dla",
+        "cs": "Poskytovatel slu\u017eby pro",
+        "tr": "i\u00e7in Servis Sa\u011flay\u0131c\u0131lar",
+        "it": "Service Provider per",
+        "lt": "Paslaug\u0173 teik\u0117jai",
+        "ja": "\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0: ",
+        "zh-tw": "\u7d66\u670d\u52d9\u63d0\u4f9b\u8005",
+        "et": "Teenusepakkujad",
+        "he": "\u05e1\u05e4\u05e7\u05d9 \u05e9\u05d9\u05e8\u05d5\u05ea \u05e2\u05d1\u05d5\u05e8",
+        "ru": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0438 \u0443\u0441\u043b\u0443\u0433 \u0434\u043b\u044f",
+        "zh": "\u670d\u52a1\u63d0\u4f9b\u8005\u7ed9",
+        "ar": "\u0645\u0642\u062f\u0645\u064a \u062e\u062f\u0645\u0627\u062a \u0644",
+        "lv": "Servisa pieg\u0101d\u0101t\u0101ji priek\u0161",
+        "id": "Service Provider untuk",
+        "sr": "Davaoci Servisa za",
+        "ro": "Furnizor de servicii pentru",
+        "eu": "Zerbitzu hornitzaileak hontarako: ",
+        "af": "Diens Verskaffers vir",
+        "el": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03b9 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03b9\u03ce\u03bd \u03b3\u03b9\u03b1"
+    },
+    "service_provider_header": {
+        "no": "Tjenesteleverand\u00f8r",
+        "nn": "Tenesteleverand\u00f8r",
+        "sv": "Tj\u00e4nsteleverant\u00f6r",
+        "es": "Proveedor de servicio",
+        "fr": "Fournisseur de service",
+        "de": "Service-Provider",
+        "nl": "Service Provider",
+        "lb": "Service Provider",
+        "sl": "SP",
+        "da": "Tjenesteudbyder",
+        "hr": "Davatelj usluge",
+        "hu": "Alkalmaz\u00e1sszolg\u00e1ltat\u00f3",
+        "fi": "Palveluntarjoaja",
+        "pt-br": "Provedor de Servi\u00e7os",
+        "pt": "Fornecedor de Servi\u00e7o (SP)",
+        "pl": "Dostawca serwisu",
+        "cs": "Poskytovatel slu\u017eby",
+        "tr": "Servis Sa\u011flay\u0131c\u0131",
+        "it": "Service Provider",
+        "lt": "Paslaugos teik\u0117jas",
+        "ja": "\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0",
+        "zh-tw": "\u670d\u52d9\u63d0\u4f9b\u8005",
+        "et": "Teenusepakkuja",
+        "he": "\u05e1\u05e4\u05e7 \u05e9\u05d9\u05e8\u05d5\u05ea",
+        "ru": "\u041f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a \u0443\u0441\u043b\u0443\u0433",
+        "zh": "\u670d\u52a1\u63d0\u4f9b\u8005",
+        "ar": "\u0645\u0642\u062f\u0645 \u062e\u062f\u0645\u0627\u062a",
+        "lv": "Servisa pieg\u0101d\u0101t\u0101js",
+        "id": "Service Provider",
+        "sr": "Davalac Servisa",
+        "ro": "Furnizor de servicii",
+        "eu": "Zerbitzu hornitzailea",
+        "af": "Diens Verskaffer",
+        "el": "\u03a0\u03ac\u03c1\u03bf\u03c7\u03bf\u03c2 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u03c2"
+    },
+    "status_header": {
+        "no": "Samtykke-status",
+        "nn": "Samtykkestatus",
+        "sv": "Status f\u00f6r samtycke",
+        "es": "Estado del consentimiento",
+        "fr": "\u00c9tat des consentements",
+        "de": "Zustimmungsstatus",
+        "nl": "Toestemming status",
+        "lb": "Zoust\u00ebmmungsstatus",
+        "sl": "Stanje privolitve",
+        "da": "Samtykke status",
+        "hr": "Status odobrenja",
+        "hu": "Hozz\u00e1j\u00e1rul\u00e1s \u00e1llapota",
+        "fi": "Hyv\u00e4ksynn\u00e4\u00e4n tila",
+        "pt-br": "Status do Consentimento",
+        "pt": "Consentimento",
+        "pl": "Status zgody",
+        "cs": "Status souhlasu",
+        "tr": "Onay durumu",
+        "it": "Stato del consenso",
+        "lt": "Leidimo b\u016bsena",
+        "ja": "\u627f\u8a8d\u30b9\u30c6\u30fc\u30bf\u30b9",
+        "zh-tw": "\u540c\u610f\u72c0\u614b",
+        "et": "N\u00f5usoleku olek",
+        "he": "\u05de\u05e6\u05d1 \u05d4\u05e1\u05db\u05de\u05d4",
+        "ru": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0442\u0430\u0442\u0443\u0441",
+        "zh": "\u540c\u610f\u72b6\u6001",
+        "ar": "\u062d\u0627\u0644\u0629 \u0645\u0648\u0627\u0641\u0642\u0629",
+        "lv": "Noteikumu statuss",
+        "id": "Status persetujuan",
+        "sr": "Status odobrenja",
+        "ro": "Stare acord",
+        "eu": "Onespen egoera",
+        "af": "Toestemming status",
+        "el": "\u039a\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
+    },
+    "show_hide_attributes": {
+        "no": "Vis\/skjul opplysninger",
+        "nn": "Vis\/skjul opplysningar",
+        "sv": "visa\/g\u00f6m attribut",
+        "es": "Mostrar\/ocultar atributos",
+        "fr": "montrer\/cacher les attributs",
+        "de": "zeige\/verstecke Eigenschaften",
+        "nl": "toon\/verberg attributen",
+        "lb": "Attributer weisen\/verstoppen",
+        "sl": "prika\u017ei\/skrij atribute",
+        "da": "vis\/skjul attributter",
+        "hr": "prika\u017ei\/sakrij atribute",
+        "hu": "attrib\u00fatumok mutat\u00e1sa\/elrejt\u00e9se",
+        "fi": "N\u00e4yt\u00e4\/piilota attribuutteja",
+        "pt-br": "mostra\/esconder Atributos",
+        "pt": "Mostrar\/Ocultar atributos",
+        "pl": "poka\u017c\/ukryj atrybuty",
+        "cs": "zobraz\/skryj atributy",
+        "tr": "bilgileri g\u00f6ster\/gizle ",
+        "it": "Mostra\/nascondi attributi",
+        "lt": "rodyti\/sl\u0117pti atributus",
+        "ja": "\u8868\u793a\/\u975e\u8868\u793a\u5c5e\u6027",
+        "zh-tw": "\u986f\u793a\/\u96b1\u85cf\u5c6c\u6027",
+        "et": "n\u00e4ita\/peida atribuudid",
+        "he": "\u05d4\u05e8\u05d0\u05d4\\\u05d4\u05e1\u05ea\u05e8 \u05ea\u05db\u05d5\u05e0\u05d5\u05ea ",
+        "ru": "\u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c\/\u0441\u043a\u0440\u044b\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
+        "zh": "\u663e\u793a\/\u9690\u85cf\u5c5e\u6027",
+        "ar": "\u0627\u0638\u0647\u0631\/\u0627\u0644\u063a\u064a \u0627\u0644\u0633\u0645\u0627\u062a",
+        "lv": "r\u0101d\u012bt\/sl\u0113pt atrib\u016btus",
+        "id": "perlihatkan\/sembunyikan attribut",
+        "sr": "prika\u017ei\/sakrij atribute",
+        "ro": "arat\u0103\/ascunde atributele",
+        "eu": "erakutsi\/gorde atributuak",
+        "af": "vertoon\/verberg eienskappe",
+        "el": "\u03b5\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7\/\u03b1\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03c3\u03c4\u03bf\u03b9\u03c7\u03b5\u03af\u03c9\u03bd"
+    },
+    "consent_privacypolicy": {
+        "no": "Personvern for tjenesten",
+        "nn": "Personvern for tenesta",
+        "sv": "Tj\u00e4nstens policy f\u00f6r personlig integritet",
+        "es": "Pol\u00edtica de privacidad para el servicio",
+        "de": "Datenschutzrichtlinie des Dienstes",
+        "nl": "Privacybeleid voor de dienst",
+        "sl": "Politika zasebnosti za ta SP",
+        "da": "Tjenestens politik vedr\u00f8rende personoplysninger",
+        "hr": "Politika za\u0161tite privatnosti kod servisa",
+        "hu": "A szolg\u00e1ltat\u00e1s adatv\u00e1delmi nyilatkozata",
+        "fi": "Tietosuojaseloste palvelulle",
+        "pt-br": "Pol\u00edtica de Privacidade deste servi\u00e7o",
+        "pt": "Pol\u00edtica de privacidade do servi\u00e7o",
+        "pl": "Polityka prywatno\u015bci dla serwisu",
+        "cs": "Bezpe\u010dnostn\u00ed politika slu\u017eby",
+        "tr": "Servis i\u00e7in gizlilik politikas\u0131",
+        "fr": "Politique de confidentialit\u00e9 pour ce service",
+        "it": "Politica della privacy per il servizio",
+        "lt": "\u0160ios paslaugos privatumo politika",
+        "ja": "\u30b5\u30fc\u30d3\u30b9\u306e\u30d7\u30e9\u30a4\u30d0\u30b7\u30dd\u30ea\u30b7\u30fc",
+        "zh-tw": "\u670d\u52d9\u96b1\u79c1\u6b0a\u653f\u7b56",
+        "et": "Teenuse privaatsuspoliitika",
+        "he": "\u05de\u05d3\u05d9\u05e0\u05d9\u05d5\u05ea \u05d4\u05e4\u05e8\u05d8\u05d9\u05d5\u05ea \u05e9\u05dc \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea",
+        "ru": "\u041f\u043e\u043b\u0438\u0442\u0438\u043a\u0430 \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043b\u0443\u0436\u0431\u044b",
+        "zh": "\u8be5\u670d\u52a1\u7684\u9690\u79c1\u7b56\u7565",
+        "ar": "\u0633\u064a\u0627\u0633\u0629 \u0627\u0644\u062e\u0635\u0648\u0635\u064a\u0629 \u0644\u0644\u062e\u062f\u0645\u0629",
+        "lv": "Servisa dro\u0161\u012bbas noteikumi",
+        "id": "Kebijakan privasi untuk layanan",
+        "sr": "Politika za\u0161tite privatnosti kod servisa",
+        "ro": "Politica de confiden\u021bialitate pentru serviciu",
+        "eu": "Zerbitzuarentzako pribatutasun-politika",
+        "af": "Privaatheidsbeleid vir die diens",
+        "el": "\u03a0\u03bf\u03bb\u03b9\u03c4\u03b9\u03ba\u03ae \u03c0\u03c1\u03bf\u03c3\u03c4\u03b1\u03c3\u03af\u03b1\u03c2 \u03b1\u03c0\u03bf\u03c1\u03c1\u03ae\u03c4\u03bf\u03c5 \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u03c2"
+    },
+    "noconsent_title": {
+        "no": "Ikke akseptert overf\u00f8ring av informasjon",
+        "nn": "Ikkje akseptert overf\u00f8ring av informasjon",
+        "sv": "Inget samtycket givet",
+        "es": "No se di\u00f3 el consentimiento",
+        "de": "Zustimmung verweigert",
+        "nl": "Geen toestemming gegeven",
+        "sl": "Privolitev ni bila dana.",
+        "da": "Manglende samtykke",
+        "hr": "Isporuka podataka nije odobrena",
+        "hu": "Nincs hozz\u00e1j\u00e1rul\u00e1s",
+        "fi": "Lupaa ei annettu",
+        "pt-br": "Nenhum consentimento dado",
+        "pt": "Consentimento negado",
+        "pl": "Nie wyra\u017cono zgody",
+        "cs": "Souhlas nebyl vyd\u00e1n",
+        "tr": "Onay verilmemi\u015f",
+        "fr": "Aucun consentement n'a \u00e9t\u00e9 donn\u00e9",
+        "it": "Nessun consenso dato",
+        "lt": "Leidimas neduotas",
+        "ja": "\u627f\u8a8d\u306f\u3042\u308a\u307e\u305b\u3093",
+        "zh-tw": "\u5c1a\u672a\u540c\u610f",
+        "et": "N\u00f5usolekut pole antud",
+        "he": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05e0\u05d4 \u05d4\u05e1\u05db\u05de\u05d4",
+        "ru": "\u041d\u0435\u0442 \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f",
+        "zh": "\u672a\u540c\u610f",
+        "ar": "\u0644\u0645 \u062a\u0639\u0637\u064a \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
+        "lv": "Nav noteikumu",
+        "id": "Tidan ada persetujuan yang diberikan",
+        "sr": "Slanje podataka nije odobreno",
+        "ro": "Nu a fost dat acordul (consim\u021b\u0103m\u00e2ntul)",
+        "eu": "Ez da onespena eman",
+        "af": "Geen toestemming is gegee nie",
+        "el": "\u039c\u03b7 \u03b1\u03c0\u03bf\u03b4\u03bf\u03c7\u03ae \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
+    },
+    "noconsent_text": {
+        "no": "Du har ikke akseptert \u00e5 overlevere opplysninger til SPNAME.",
+        "nn": "Du har ikkje akseptert til at dine opplysningar kan sendast til SPNAME.",
+        "sv": "Du gav inte samtycke f\u00f6r att \u00f6verf\u00f6ra dina attribut till tj\u00e4nsteleverant\u00f6ren.",
+        "es": "No ha dado su consentimiento para tranferir sus atributos al proveedor de servicio.",
+        "de": "Sie haben der Weitergabe ihrer Daten an den Service Provider nicht zugestimmt.",
+        "nl": "U heeft geen toestemming gegeven om uw attributen naar de Service Provider te versturen",
+        "sl": "Niste podali privolitve za posredovanje atributov SP-ju.",
+        "da": "Du har ikke givet samtykke til overleveringen af oplysninger til tjenesten",
+        "hr": "Niste dali pristanak da se va\u0161i podaci isporu\u010de davatelju usluge.",
+        "hu": "Nem adta hozz\u00e1j\u00e1rul\u00e1s\u00e1t, hogy adatait tov\u00e1bbadjuk a szolg\u00e1ltat\u00f3nak.",
+        "fi": "Et antanut lupaa siirt\u00e4\u00e4 henkil\u00f6tietojasi palveluntarjoajalle",
+        "pt-br": "Voc\u00ea n\u00e3o deu o consentimento para a transfer\u00eancia de seus atributos para o provedor de servi\u00e7os.",
+        "pt": "Negou o consentimento para a transfer\u00eancia dos seus atributos para o fornecedor de servi\u00e7o.",
+        "pl": "Nie wyrazi\u0142e\u015b zgody na przes\u0142anie Twoich atrybut\u00f3w do Dostawcy Serwisu.",
+        "cs": "Nedal jste souhlas pro zasl\u00e1n\u00ed sv\u00fdch atribut\u016f poskytovateli slu\u017eeb.",
+        "tr": "Bilgilerinizin servis sa\u011flay\u0131c\u0131ya g\u00f6nderilmesi i\u00e7in onay vermediniz.",
+        "fr": "Vous n'avez pas donn\u00e9 votre consentement \u00e0 la divulgation de vos attributs pour ce fournisseur de service.",
+        "it": "Non hai dato il consenso per trasferire i tuoi attributi al service provider.",
+        "lt": "J\u016bs nedav\u0117te sutikimo persi\u0173sti J\u016bs\u0173 atributus SPNAME paslaugos teik\u0117jui.",
+        "ja": "\u3042\u306a\u305f\u306f\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0\u306b\u5c5e\u6027\u3092\u8ee2\u9001\u3059\u308b\u4e8b\u3092\u627f\u8a8d\u3057\u3066\u3044\u307e\u305b\u3093\u3002",
+        "zh-tw": "\u60a8\u4e0d\u540c\u610f\u50b3\u8f38\u60a8\u7684\u5c6c\u6027\u81f3\u670d\u52d9\u63d0\u4f9b\u8005\u3002",
+        "et": "Sa ei andnud n\u00f5usolekut sinu atribuutide teenusepakkujale edastamiseks.",
+        "he": "\u05dc\u05d0 \u05e0\u05ea\u05e0\u05ea \u05d4\u05e1\u05db\u05de\u05d4 \u05dc\u05d4\u05e2\u05d1\u05e8\u05ea \u05d4\u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9\u05dd \u05dc\u05e1\u05e4\u05e7 \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea.",
+        "ru": "\u0412\u044b \u043d\u0435 \u0434\u0430\u043b\u0438 \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0432\u0430\u0448\u0438\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432 \u043a \u043f\u043e\u0441\u0442\u0430\u0432\u0449\u0438\u043a\u0443 \u0443\u0441\u043b\u0443\u0433.",
+        "zh": "\u4f60\u6ca1\u6709\u540c\u610f\u4f20\u8f93\u4f60\u7684\u76f8\u5173\u5c5e\u6027\u7ed9\u670d\u52a1\u63d0\u4f9b\u8005",
+        "ar": "\u0644\u0645 \u062a\u0648\u0627\u0641\u0642 \u0639\u0644\u064a \u062a\u062d\u0648\u064a\u0644 \u0633\u0645\u0627\u062a\u0643 \u0644\u0645\u0642\u062f\u0645 \u0627\u0644\u062e\u062f\u0645\u0629",
+        "lv": "J\u016bs neesat devis at\u013cauju p\u0101rraid\u012bt inform\u0101ciju servisa pieg\u0101d\u0101t\u0101jam.",
+        "id": "Anda tidak memberikan persetujuan untuk mentransfer atribut-atribute Anda ke service provider.",
+        "sr": "Niste odobrili da se va\u0161i podaci po\u0161alju davaocu servisa.",
+        "ro": "Nu a\u021bi fost de acord s\u0103 trimite\u021bi atributele c\u0103tre SPNAME.",
+        "eu": "Ez duzu onespena eman zure atributuak zerbitzuari transferitzeko.",
+        "af": "Jy het nie toestemming gegee vir die oordrag van jou eienskappe na SPNAME nie.",
+        "el": "\u0394\u03b5\u03bd \u03ad\u03c7\u03b5\u03c4\u03b5 \u03b4\u03ce\u03c3\u03b5\u03b9 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7 \u03b3\u03b9\u03b1 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03bc\u03cc \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ce\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
+    },
+    "noconsent_return": {
+        "no": "G\u00e5 tilbake til samtykkesiden",
+        "nn": "G\u00e5 tilbake til samtykkesida",
+        "sv": "\u00c5ter till sidan f\u00f6r samtycke",
+        "es": "Volver a la p\u00e1gina de consentimiento",
+        "de": "Zur\u00fcck",
+        "nl": "Keer terug naar de toestemmingspagina",
+        "sl": "Vrnitev na privolitveno stran",
+        "da": "G\u00e5 tilbage",
+        "hr": "Povratak na stranicu za kreiranje dozvola",
+        "hu": "Vissza az hozz\u00e1j\u00e1rul\u00e1s-kezel\u0151 oldalra",
+        "fi": "Palaa hyv\u00e4ksynt\u00e4sivulle",
+        "pt-br": "Retornar a p\u00e1gina de consentimento",
+        "pt": "Voltar \u00e0 p\u00e1gina de consentimento",
+        "pl": "Powr\u00f3t do strony wydania zezwolenia.",
+        "cs": "Zp\u00e1tky na str\u00e1nku pro souhlas",
+        "tr": "Onay sayfas\u0131na geri d\u00f6n",
+        "fr": "Retour \u00e0 la page de consentement",
+        "it": "Torna alla pagina del consenso",
+        "lt": "Gr\u012f\u017eti \u012f leidim\u0173 puslap\u012f",
+        "ja": "\u627f\u8a8d\u30da\u30fc\u30b8\u306b\u623b\u308b",
+        "zh-tw": "\u56de\u5230\u540c\u610f\u9801\u9762",
+        "et": "Tagasi n\u00f5usoleku lehele",
+        "he": "\u05d7\u05d6\u05d5\u05e8 \u05dc\u05d3\u05e3 \u05d4\u05e1\u05db\u05de\u05d4",
+        "zh": "\u8fd4\u56de\u540c\u610f\u754c\u9762",
+        "ar": "\u0639\u062f \u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
+        "lv": "Atgriezties uz noteikumu lapu",
+        "id": "Kembali ke halaman persetujuan",
+        "sr": "Povratak na stranicu za kreiranje pristanka",
+        "ro": "\u00centoarcere la pagina de consim\u021b\u0103m\u00e2nt",
+        "ru": "\u0412\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0434\u043b\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u043e\u0433\u043b\u0430\u0441\u0438\u044f",
+        "eu": "Itzuli onespen orrira",
+        "af": "Keer terug na die toestemmingsbladsy",
+        "el": "\u0395\u03c0\u03b9\u03c3\u03c4\u03c1\u03bf\u03c6\u03ae \u03c3\u03c4\u03b7 \u03c3\u03b5\u03bb\u03af\u03b4\u03b1 \u03b4\u03ae\u03bb\u03c9\u03c3\u03b7\u03c2 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2"
+    },
+    "consent_header": {
+        "no": "Samtykke om overf\u00f8ring av personinformasjon",
+        "nn": "Samtykke til overf\u00f8ring av personinformasjon",
+        "sv": "Samtycke g\u00e4llande \u00f6verf\u00f6ring av personinformation",
+        "es": "Consentimiento para la liberaci\u00f3n de informaci\u00f3n personal",
+        "de": "Zustimmung zur Weitergabe pers\u00f6nlicher Daten",
+        "nl": "Toestemming voor het vrijgeven van persoonsgegevens",
+        "sl": "Odlo\u010ditev o privolitvi posredovanja va\u0161ih osebnih podatkov",
+        "da": "Samtykke til at frigive personlige oplysninger",
+        "hr": "Dozvola za isporuku osobnih podataka",
+        "hu": "Hozz\u00e1j\u00e1rul\u00e1s szem\u00e9lyes adatok kiad\u00e1s\u00e1hoz",
+        "fi": "Henkil\u00f6tietojen luovutuksen hyv\u00e4ksynt\u00e4",
+        "pt": "Consentimento do envio de informa\u00e7\u00e3o pessoal",
+        "pl": "Zgoda na wys\u0142anie danych osobistych",
+        "cs": "Obsah odes\u00edlan\u00fdch osobn\u00edch informac\u00ed",
+        "tr": "Ki\u015fisel bilgilerin verilmesi hakk\u0131nda onay",
+        "fr": "Consentement pour la divulgation d'informations personnelles",
+        "it": "Consenso al rilascio delle informazioni personali",
+        "lt": "Leidimas perduoti asmenin\u0119 informacij\u0105",
+        "ja": "\u500b\u4eba\u60c5\u5831\u306e\u627f\u8a8d\u3092\u89e3\u9664",
+        "zh-tw": "\u540c\u610f\u6709\u95dc\u65bc\u500b\u4eba\u95dc\u4fc2\u8cc7\u8a0a",
+        "et": "N\u00f5usolek isikuandmete edastamiseks",
+        "he": "\u05d4\u05e1\u05db\u05de\u05d4 \u05dc\u05d4\u05e2\u05d1\u05e8\u05ea \u05de\u05d9\u05d3\u05e2 \u05d0\u05d9\u05e9\u05d9",
+        "pt-br": "Consentimento sobre a libera\u00e7\u00e3o de informa\u00e7\u00f5es pessoais",
+        "zh": "\u540c\u610f\u5f00\u653e\u4e2a\u4eba\u4fe1\u606f",
+        "ar": "\u0627\u0648\u0627\u0641\u0642 \u0639\u0644\u064a \u0646\u0634\u0631 \u0633\u0645\u0627\u062a\u064a \u0627\u0644\u0634\u062e\u0635\u064a\u0629",
+        "lv": "Noteikumi par person\u012bg\u0101s inform\u0101cijas nodo\u0161anu",
+        "id": "Persetujuan tentang melepas informasi personal",
+        "sr": "Pristanak za slanje li\u010dnih podataka",
+        "ro": "Acordul pentru a furniza informa\u021bii personale",
+        "ru": "\u0421\u043e\u0433\u043b\u0430\u0441\u0438\u0435 \u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445",
+        "eu": "Informazio pertsonala askatzeko onespena ",
+        "af": "Toestemming mbt. die vrystelling van persoonlike informasie",
+        "el": "\u0394\u03ae\u03bb\u03c9\u03c3\u03b7 \u03c3\u03c5\u03b3\u03ba\u03b1\u03c4\u03ac\u03b8\u03b5\u03c3\u03b7\u03c2 \u03b3\u03b9\u03b1 \u03c4\u03bf\u03bd \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03bc\u03cc \u03c0\u03c1\u03bf\u03c3\u03c9\u03c0\u03b9\u03ba\u03ce\u03bd \u03b4\u03b5\u03b4\u03bf\u03bc\u03ad\u03bd\u03c9\u03bd"
+    },
+    "consent_attributes_header": {
+        "no": "Opplysninger som vil bli sendt til SPNAME",
+        "nn": "Opplysningar som blir sende til SPNAME",
+        "sv": "Attribut som kommer att skickas till tj\u00e4nsten",
+        "es": "Atributos que ser\u00e1n enviados al servicio",
+        "de": "Informationen, die an SPNAME gesandt werden",
+        "nl": "Informatie die naar SPNAME zal worden gestuurd",
+        "sl": "Atributi, ki bodo poslani SPju",
+        "da": "Attributter som bliver sendt til SPNAME",
+        "hr": "Informacije koje \u0107e biti poslane servisu SPNAME",
+        "hu": "A(z) SPNAME szolg\u00e1ltat\u00f3nak k\u00fcld\u00f6tt adatok",
+        "fi": "Tiedot l\u00e4hetet\u00e4\u00e4n palvelulle SPNAME",
+        "pt": "Informa\u00e7\u00e3o que ir\u00e1 ser enviada para SPNAME",
+        "pl": "Atrybuty, kt\u00f3re zostan\u0105 przes\u0142ane do serwisu",
+        "cs": "Atributy, kter\u00e9 mohou b\u00fdt zasl\u00e1ny slu\u017eb\u011b",
+        "tr": "SPNAME'e g\u00f6nderilecek bilgiler",
+        "fr": "Informations qui seront envoy\u00e9es \u00e0 SPNAME",
+        "it": "Informazioni che saranno inviate a SPNAME",
+        "lt": "Informacija, kuri bus persi\u0173sta \u012f SPNAME",
+        "ja": "SPNAME\u3068\u3057\u3066\u9001\u4fe1\u3055\u308c\u308b\u60c5\u5831",
+        "zh-tw": "\u8cc7\u8a0a\u5c07\u88ab\u50b3\u9001\u81f3 SPNAME",
+        "et": "Andmed saadetakse SPNAME-le",
+        "he": "\u05d4\u05de\u05d9\u05d3\u05e2 \u05d9\u05e9\u05dc\u05d7 \u05dc SPNAME",
+        "zh": "\u4fe1\u606f\u5c06\u4f1a\u53d1\u9001\u7ed9SPNAME",
+        "ar": "\u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u062a\u064a \u0633\u064a\u062a\u0645 \u0625\u0631\u0633\u0627\u0644\u0647\u0627 \u0644 SPNAME",
+        "lv": "Inform\u0101cija, kas tiks s\u016bt\u012bta SPNAME",
+        "id": "Informasi yang akan dikirim ke SPNAME",
+        "sr": "Informacije koje \u0107e biti poslate servisu SPNAME",
+        "ro": "Informa\u021bii care vor fi trimise la SPNAME",
+        "ru": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430 \u0432 SPNAME ",
+        "eu": "Zerbitzura bidaliko diren atributuak",
+        "af": "Informasie wat gestuur sal word na SPNAME",
+        "el": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
+    },
+    "show_attributes": {
+        "no": "Vis opplysninger",
+        "nn": "Vis opplysingar",
+        "sv": "Visa attribut",
+        "es": "Mostrar atributos",
+        "de": "Attribute zeigen",
+        "nl": "Toon attributen",
+        "sl": "Prika\u017ei atribute",
+        "da": "Vis attributter",
+        "hr": "Prika\u017ei atribute",
+        "hu": "Mutasd az attrib\u00fatumokat",
+        "fi": "N\u00e4yt\u00e4 henkil\u00f6tiedot",
+        "pt": "Mostrar atributos",
+        "pl": "Wy\u015bwietl atrybuty",
+        "cs": "Zobraz atributy",
+        "tr": "\u00d6zellikleri g\u00f6ster",
+        "fr": "Montrer les attributs",
+        "it": "Mostra attributi",
+        "lt": "Parodyti atributus",
+        "ja": "\u5c5e\u6027\u3092\u8868\u793a\u3059\u308b",
+        "zh-tw": "\u986f\u793a\u5c6c\u6027",
+        "et": "N\u00e4ita andmeid",
+        "he": "\u05d4\u05e6\u05d2 \u05de\u05d0\u05e4\u05d9\u05d9\u05e0\u05d9\u05dd",
+        "pt-br": "Mostrar atributos",
+        "zh": "\u663e\u793a\u5c5e\u6027",
+        "ar": "\u0627\u0638\u0647\u0631 \u0627\u0644\u0633\u0645\u0627\u062a",
+        "lv": "R\u0101d\u012bt atrib\u016btus",
+        "id": "Perlihatkan atribut-atribut",
+        "sr": "Prika\u017ei atribute",
+        "ro": "Arat\u0103 atributele",
+        "ru": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b",
+        "eu": "Erakutsi atributuak",
+        "af": "Vertoon eienskappe"
+    },
+    "noconsent_goto_about": {
+        "no": "G\u00e5 til informasjonsside om tjenesten",
+        "nn": "G\u00e5 til informasjonssida for tenesta",
+        "sv": "G\u00e5 till tj\u00e4nstens informationssida",
+        "es": "Ir a la p\u00e1gina de informaci\u00f3n del servicio",
+        "de": "Gehe zur Informationsseite dieses Dienstes",
+        "nl": "Ga naar de informatiepagina voor de service",
+        "sl": "Pojdi na spletno stran z informacijami o storitvi",
+        "da": "G\u00e5 til side med information om tjenesten",
+        "hr": "Idi na stranicu s informacijama o servisu",
+        "hu": "A szolg\u00e1ltat\u00e1s inform\u00e1ci\u00f3s oldal\u00e1ra",
+        "fi": "Siirry palvelun tiedot -sivulle",
+        "pt": "Ir para p\u00e1gina de informa\u00e7\u00e3o do servi\u00e7o",
+        "pl": "Przejd\u017a do strony informacyjnej dla tego serwisu",
+        "cs": "Jdi na str\u00e1nku s informacemi o slu\u017eb\u011b",
+        "tr": "Servis i\u00e7in bilgi sayfas\u0131na git",
+        "fr": "Aller \u00e0 la page d'information sur ce service",
+        "it": "Vai alla pagina di informazioni per il servizio",
+        "lt": "Pereiti \u012f \u0161ios paslaugos informacin\u012f puslap\u012f",
+        "ja": "\u30b5\u30fc\u30d3\u30b9\u306e\u70ba\u306e\u60c5\u5831\u30da\u30fc\u30b8\u3092\u53c2\u7167",
+        "zh-tw": "\u81f3\u670d\u52d9\u8cc7\u8a0a\u9801\u9762",
+        "et": "Mine teenuse infolehele",
+        "he": "\u05dc\u05da \u05d0\u05dc \u05d3\u05e3 \u05d4\u05de\u05d9\u05d3\u05e2 \u05e9\u05dc \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea",
+        "pt-br": "Ir para a P\u00e1gina de Informa\u00e7\u00e3o do servi\u00e7o",
+        "zh": "\u83b7\u53d6\u8be5\u670d\u52a1\u7684\u4fe1\u606f",
+        "ar": "\u0627\u0630\u0647\u0628 \u0644\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0639\u0646 \u0627\u0644\u062e\u062f\u0645\u0629",
+        "lv": "Iet uz servisa inform\u0101cijas lapu",
+        "id": "Pergi ke halaman informasi untul layanan",
+        "sr": "Idi na stranicu sa informacijama o servisu",
+        "ro": "Link la pagina serviciului",
+        "ru": "\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u043b\u0443\u0436\u0431\u0435",
+        "eu": "Joan zerbitzuaren informazio orrira",
+        "af": "Gaan na die informasie bladsy vir die diens",
+        "el": "\u0395\u03c0\u03b9\u03c0\u03bb\u03ad\u03bf\u03bd \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03b3\u03b9\u03b1 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1"
+    },
+    "consent_purpose": {
+        "no": "Form\u00e5let med SPNAME er SPDESC",
+        "nn": "Hensikta med SPNAME er SPDESC",
+        "sv": "Syftet med SPNAME \u00e4r SPDESC",
+        "es": "El prop\u00f3sito de SPNAME es SPDESC",
+        "de": "Der Zweck von SPNAME ist SPDESC",
+        "nl": "Het doel van SPNAME is SPDESC",
+        "sl": "Namen %SPNAME%: %SPDESC%",
+        "da": "SPNAME har til form\u00e5l at SPDESC",
+        "hr": "Namjena servisa SPNAME je SPDESC",
+        "hu": "A szolg\u00e1ltat\u00e1s (SPNAME) ezt a c\u00e9lt szolg\u00e1lja: SPDESC",
+        "fi": "Palvelun SPNAME k\u00e4ytt\u00f6tarkoitus on SPDESC",
+        "pt": "O prop\u00f3sito de SPNAME \u00e9 SPDESC",
+        "pl": "Celem SPNAME jest SPDESC",
+        "cs": "C\u00edl SPNAME v SPDESC",
+        "tr": "SPNAME'in amac\u0131 SPDESC'tir",
+        "fr": "L'objet de SPNAME est SPDESC",
+        "it": "Lo scopo di SPNAME \u00e8 SPDESC",
+        "lt": "SPNAME paskirtis yra SPDESC",
+        "ja": "SPNAME\u306e\u76ee\u7684\u306fSPDESC\u3067\u3059",
+        "zh-tw": "SPNAME \u7684\u76ee\u7684\u5730\u70ba SPDESC",
+        "et": "Teenuse SPNAME eesm\u00e4rk on SPDESC",
+        "he": "\u05d4\u05de\u05d8\u05e8\u05d4 \u05e9\u05dc SPNAME \u05d4\u05d9\u05d0 SPDESC",
+        "zh": "SPNAME\u7684\u76ee\u7684\u662fSPDESC",
+        "ar": "\u0627\u0644\u063a\u0631\u0636 \u0645\u0646 SPNAME \u0647\u0648 SPDESC",
+        "lv": "SPNAME nol\u016bks ir SPDESC",
+        "id": "Tujuan dari SPNAME adalah SPDESC",
+        "sr": "Namena servisa SPNAME je SPDESC",
+        "ro": "Scopul SPNAME este SPDESC",
+        "ru": "\u0426\u0435\u043b\u044c SPNAME - SPDESC",
+        "eu": "Zerbtizuaren xedea SPDESC da",
+        "af": "Die doel van SPNAME is SPDESC",
+        "el": "\u03a0\u03b5\u03c1\u03b9\u03b3\u03c1\u03b1\u03c6\u03ae \u03cc\u03c0\u03c9\u03c2 \u03c0\u03b1\u03c1\u03ad\u03c7\u03b5\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1\u003a SPDESC"
+    },
+    "table_caption": {
+        "no": "Bruker innformasjon",
+        "sv": "Anv\u00e4ndarinformation",
+        "es": "Informaci\u00f3n del usuario",
+        "de": "Benutzerdaten",
+        "nl": "Gebruikersinformatie",
+        "sl": "Podatki o uporabniku",
+        "da": "Bruger information",
+        "hu": "Felhaszn\u00e1l\u00f3i inform\u00e1ci\u00f3k",
+        "fi": "K\u00e4ytt\u00e4j\u00e4tiedot",
+        "pt": "Informa\u00e7\u00e3o do utilizador",
+        "tr": "Kullan\u0131c\u0131 bilgisi",
+        "fr": "Information sur l'usager",
+        "hr": "Informacije o korisniku",
+        "nn": "Brukarinformasjon",
+        "it": "Informazioni utente",
+        "lt": "Vartotojo informacija",
+        "ja": "\u30e6\u30fc\u30b6\u30fc\u60c5\u5831",
+        "zh-tw": "\u4f7f\u7528\u8005\u8cc7\u8a0a",
+        "et": "Kasutajainfo",
+        "he": "\u05de\u05d9\u05d3\u05e2 \u05e2\u05dc \u05d4\u05de\u05e9\u05ea\u05de\u05e9",
+        "pt-br": "Informa\u00e7\u00f5es do Usu\u00e1rio",
+        "zh": "\u7528\u6237\u4fe1\u606f",
+        "ar": "\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645",
+        "lv": "Lietot\u0101ja inform\u0101cija",
+        "id": "Informasi User",
+        "sr": "Informacije o korisniku",
+        "ro": "Informa\u021bii despre utilizator",
+        "ru": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435",
+        "cs": "U\u017eivatelsk\u00e9 informace",
+        "eu": "Erabiltzailearen informazioa",
+        "af": "Gebruiker informasie",
+        "el": "\u03a0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7"
+    },
+    "table_summary": {
+        "no": "Her listes den innformasjonen om deg som blir send til den tjenesten du er i ferd med \u00e5 logge p\u00e5",
+        "sv": "Visa den nformation om din anv\u00e4ndare som kommer att skickas till tj\u00e4nsten som du \u00e4r p\u00e5 v\u00e4g att logga in i",
+        "es": "Muestra que informaci\u00f3n relativa a usted va a ser transmitida al servicio en el que se va a identificar",
+        "nl": "De informatie die over jou bekend is en naar de service waarop je wilt inloggen verstuurd zal worden",
+        "sl": "Seznam podatkov o vas, ki bodo posredovani storitvi, v katero se nameravate prijaviti",
+        "da": "Informationer som vil blive sendt til den service du er ved at logge in p\u00e5",
+        "hu": "Ezeket az adatokat fogjuk elk\u00fcldeni \u00d6nr\u0151l annak a szolg\u00e1ltat\u00e1snak, ahov\u00e1 be k\u00edv\u00e1n jelentkezni",
+        "fi": "N\u00e4yt\u00e4 tietosi, joita ollaan siirt\u00e4m\u00e4ss\u00e4 palveluun",
+        "pt": "Listar a informa\u00e7\u00e3o acerca de si que ser\u00e1 enviada para o servi\u00e7o no qual se est\u00e1 autenticar",
+        "tr": "Girmek istedi\u011finiz servise g\u00f6nderilecek bilginizi listeleyin",
+        "de": "Zeige die Information \u00fcber Sie, die an den Service, auf dem Sie sich einloggen werden, \u00fcbermittelt werden",
+        "fr": "Liste des informations vous concernant qui seront envoy\u00e9es au service auquel vous allez vous connecter",
+        "hr": "Prika\u017ei popis va\u0161ih podataka koji \u0107e biti proslje\u0111eni servisu kojem \u017eelite pristupiti",
+        "nn": "List informasjon om deg som blir overf\u00f8rt til tenesta du skal logga inn p\u00e5",
+        "it": "Mostra le informazioni su di te che stanno per essere trasferire al servizio a cui ti vuoi collegare",
+        "lt": "Per\u017ei\u016br\u0117ti informacij\u0105 apie jus, kuri bus persi\u0173sta paslaugai, \u012f kuri\u0105 jungiat\u0117s",
+        "ja": "\u4e00\u89a7\u306e\u60c5\u5831\u306f\u3042\u306a\u305f\u304c\u30ed\u30b0\u30a4\u30f3\u3059\u308b\u969b\u306b\u30b5\u30fc\u30d3\u30b9\u306b\u8ee2\u9001\u3055\u308c\u307e\u3059\u3002",
+        "zh-tw": "\u5c07\u95dc\u65bc\u6211\u50b3\u9001\u81f3\u60a8\u9810\u8a08\u8981\u767b\u5165\u7684\u670d\u52d9",
+        "et": "Teave sinu kohta, mis edastatakse teenusele, millesse asud sisse logima",
+        "he": "\u05d4\u05e6\u05d2 \u05d0\u05ea \u05d4\u05de\u05d9\u05d3\u05e2 \u05e2\u05dc\u05d9\u05da \u05d0\u05e9\u05e8 \u05d9\u05d5\u05e2\u05d1\u05e8 \u05dc\u05e9\u05d9\u05e8\u05d5\u05ea \u05e9\u05d0\u05ea\u05d4 \u05e2\u05d5\u05de\u05d3 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05d0\u05dc\u05d9\u05d5",
+        "pt-br": "Liste as informa\u00e7\u00f5es sobre voc\u00ea que est\u00e1 prestes a ser transmitida para o servi\u00e7o que voc\u00ea est\u00e1 acessando",
+        "zh": "\u5f53\u4f60\u767b\u5f55\u65f6\u5c06\u8981\u4f20\u8f93\u7ed9\u670d\u52a1\u7684\u4fe1\u606f\u5217\u8868",
+        "ar": "\u0642\u0627\u0626\u0645\u0629 \u0645\u0639\u0644\u0648\u0645\u0627\u062a\u0643 \u0627\u0644\u062a\u064a \u0633\u062a\u062d\u0648\u0644 \u0644\u0645\u0642\u062f\u0645 \u0627\u0644\u062e\u062f\u0645\u0629 \u0627\u0644\u0630\u064a \u062a\u0631\u063a\u0628 \u0628\u062a\u0633\u062c\u064a\u0644 \u0627\u0644\u062f\u062e\u0648\u0644 \u0627\u0644\u064a\u0647",
+        "lv": "Inform\u0101cija par Jums, kas tiks s\u016bt\u012bta servisam, kuram J\u016bs piesl\u0113dzaties",
+        "id": "Daftar informasi tentang Anda yang akan dikirimkan ke service tujuan login Anda.",
+        "sr": "Prika\u017ei spisak podataka o vama koji \u0107e biti prosle\u0111eni servisu kome \u017eelite pristupiti",
+        "ro": "Afi\u0219eaz\u0103 informa\u021biile care vor fi trimise la serviciul unde dori\u021bi s\u0103 v\u0103 autentifica\u021bi",
+        "ru": "\u0412\u044b\u0434\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u0430 \u0441\u043b\u0443\u0436\u0431\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0432\u044b \u043f\u044b\u0442\u0430\u0435\u0442\u0435\u0441\u044c \u0432\u043e\u0439\u0442\u0438",
+        "cs": "Seznam informac\u00ed o v\u00e1s, kter\u00e9 budou p\u0159ed\u00e1ny slu\u017eb\u011b, ke kter\u00e9 se p\u0159ihla\u0161ujete",
+        "eu": "Zu identifikatuko zaren zerbitzura zure ze informazio bidaliko den erakusten du ",
+        "af": "Lys die informasie mbt. jou wat op die punt is om gestuur te word vir die diens waarby jy wil aanmeld.",
+        "el": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03b9\u03ce\u03bd \u03c0\u03bf\u03c5 \u03b8\u03b1 \u03b4\u03b9\u03b1\u03bc\u03bf\u03b9\u03c1\u03b1\u03c3\u03c4\u03bf\u03cd\u03bd \u03bc\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 \u03ba\u03b1\u03c4\u03ac \u03c4\u03b7\u03bd \u03c0\u03c1\u03cc\u03c3\u03b2\u03b1\u03c3\u03b7 \u03c3\u03b5 \u03b1\u03c5\u03c4\u03ae"
+    },
+    "show_attribute": {
+        "no": "Vis innhold",
+        "nn": "Vis innhald",
+        "sv": "Visa samtycke",
+        "es": "Mostrart consentimiento",
+        "nl": "Toon inhoud",
+        "sl": "Prika\u017ei vsebino",
+        "da": "Vis indhold",
+        "de": "Zeige Inhalt",
+        "pt": "Mostrar conte\u00fado",
+        "fr": "Montrer le contenu",
+        "hr": "Prika\u017ei sadr\u017eaj",
+        "it": "Mostra contenuto",
+        "hu": "R\u00e9szletek",
+        "lt": "Parodyti leidim\u0105",
+        "ja": "\u5185\u5bb9\u3092\u8868\u793a\u3059\u308b",
+        "zh-tw": "\u986f\u793a\u5167\u5bb9",
+        "pl": "Wy\u015bwietl zawarto\u015b\u0107",
+        "et": "N\u00e4ita sisu",
+        "he": "\u05d4\u05e6\u05d2 \u05ea\u05d5\u05db\u05df",
+        "pt-br": "Mostrar Conte\u00fado",
+        "zh": "\u663e\u793a\u5185\u5bb9",
+        "ar": "\u0627\u0638\u0647\u0631\u0627\u0644\u064a\u0647\u0627 \u0638\u0647\u0631 \u0627\u0644\u0645\u062d\u062a\u0648\u064a",
+        "lv": "R\u0101d\u012bt saturu",
+        "id": "Perlihatkan konten",
+        "sr": "Prika\u017ei sadr\u017eaj",
+        "ro": "Arat\u0103 con\u021binutul",
+        "ru": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435",
+        "cs": "Zobrazit obsah",
+        "eu": "Erakutsi onespena",
+        "af": "Vertoon inhoud",
+        "el": "\u0395\u03bc\u03c6\u03ac\u03bd\u03b9\u03c3\u03b7 \u03bb\u03b5\u03c0\u03c4\u03bf\u03bc\u03b5\u03c1\u03b5\u03b9\u03ce\u03bd"
+    },
+    "abort": {
+        "no": "Avbryt innlogging til SPNAME",
+        "nn": "Avbryt innlogging til SPNAME",
+        "lt": "At\u0161aukti prisijungim\u0105 prie SPNAME",
+        "sr": "Prekini prijavu na SPNAME",
+        "it": "Login interrotto a SPNAME",
+        "fr": "Annuler la connexion au fournisseur de service SPNAME",
+        "de": "Anmeldung am Service Provider SPNAME abbrechen",
+        "et": "Katkesta sisselogimine: SPNAME",
+        "nl": "Inloggen op SPNAME afbreken",
+        "es": "Cancelar la identificaci\u00f3n en SPNAME",
+        "ro": "Anuleaz\u0103 cererea de autentificare la SPNAME",
+        "ar": "\u0625\u0644\u063a\u0627\u0621 \u0639\u0645\u0644\u064a\u0629 \u0627\u0644\u062f\u062e\u0648\u0644 \u0644SPNAME",
+        "ru": "\u041f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043d \u0432 SPNAME",
+        "cs": "Zru\u0161it p\u0159ihl\u00e1\u0161en\u00ed k SPNAME",
+        "hr": "Odustani od prijave u SPNAME",
+        "zh": "\u4e2d\u6b62\u767b\u5f55\u5230SPNAME",
+        "eu": "Bertan behera utzi zerbitzuan identifikazioa",
+        "zh-tw": "\u95dc\u65bc\u767b\u5165\u81f3 SPNAME",
+        "da": "Afbryd login til SPNAME",
+        "af": "Kanseleer aanmelding na SPNAME",
+        "el": "\u0391\u03ba\u03cd\u03c1\u03c9\u03c3\u03b7 \u03b5\u03b9\u03c3\u03cc\u03b4\u03bf\u03c5 \u03c3\u03c4\u03b7\u03bd \u03c5\u03c0\u03b7\u03c1\u03b5\u03c3\u03af\u03b1 SPNAME"
+    }
 }
diff --git a/modules/consent/docs/consent.md b/modules/consent/docs/consent.md
index 886d6fcbd197b12c04c5b23975f73fcf920ae145..3725020154b351ccfc569a1391374f8b275d9573 100644
--- a/modules/consent/docs/consent.md
+++ b/modules/consent/docs/consent.md
@@ -42,7 +42,7 @@ the user logs in.
 Example:
 
     90 => array(
-        'class:Consent',
+        'class' => 'consent:Consent',
     ),
 
 Using storage
@@ -72,8 +72,8 @@ database.
 Here is the initialization SQL script:
 
 	CREATE TABLE consent (
-		consent_date TIMESTAMP NOT NULL,
-		usage_date TIMESTAMP NOT NULL,
+		consent_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+		usage_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 		hashed_user_id VARCHAR(80) NOT NULL,
 		service_id VARCHAR(255) NOT NULL,
 		attribute VARCHAR(80) NOT NULL,
@@ -103,27 +103,27 @@ and defaults to `consent`.
 
 Example config using PostgreSQL database:
 
-	90 => array(
-		'class'	=> 'consent:Consent', 
-		'store'	=> array(
-			'consent:Database', 
-			'dsn' => 'pgsql:host=sql.example.org;dbname=consent',
-			'username' => 'simplesaml',
-			'password' => 'sdfsdf',
-		),
-	),
+    90 => array(
+        'class'	=> 'consent:Consent', 
+        'store'	=> array(
+            'consent:Database', 
+            'dsn' => 'pgsql:host=sql.example.org;dbname=consent',
+            'username' => 'simplesaml',
+            'password' => 'sdfsdf',
+        ),
+    ),
 
 Example config using MySQL database:
 
-	90 => array(
-		'class'	=> 'consent:Consent', 
-		'store'	=> array(
-			'consent:Database', 
+    90 => array(
+        'class'	=> 'consent:Consent', 
+        'store'	=> array(
+            'consent:Database', 
             'dsn' => 'mysql:host=db.example.org;dbname=simplesaml',
-			'username' => 'simplesaml',
-			'password' => 'sdfsdf',
-		),
-	),
+            'username' => 'simplesaml',
+            'password' => 'sdfsdf',
+        ),
+    ),
 
 
 Options
@@ -149,7 +149,7 @@ The following options can be used when configuring the Consent module:
 `store`
 :   Configuration of the Consent storage backend. The store option is given in 
     the format <module>:<class> and refers to the class 
-    sspmod_<module>_Consent_Store_<class>. The consent module comes with two 
+    \SimpleSAML\Module\<module>\Consent\Store\<class>. The consent module comes with two 
     built in storage backends: 'consent:Cookie' and 'consent:Database'. See 
     the separate section on setting up consent using different storage methods. 
     This option is optional. If the option is not set, then the user is asked to 
@@ -160,9 +160,15 @@ The following options can be used when configuring the Consent module:
     the attributes that should have their value hidden. Default behaviour is that 
     all attribute values are shown.
 
+`attributes.exclude`
+:   Allows certain attributes to be excluded from the attribute hash when
+    `includeValues` is `true` (and as a side effect, to be hidden from display
+    as `hiddenAttributes` does). Set to an array of the attributes that should
+    be excluded. Default behaviour is to include all values in the hash.
+
 `showNoConsentAboutService`
 :   Whether we will show a link to more information about the service from the
-    no consent page. Defaults to `TRUE`.
+    no consent page. Defaults to `true`.
 
 External options
 ----------------
diff --git a/modules/consent/lib/Auth/Process/Consent.php b/modules/consent/lib/Auth/Process/Consent.php
index b0a6cd5df378e79599529b2a60bbf3a43b55dd10..f5b6bfc8105732dccc4ed98a80cd2075de87afb1 100644
--- a/modules/consent/lib/Auth/Process/Consent.php
+++ b/modules/consent/lib/Auth/Process/Consent.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Module\consent\Auth\Process;
 
 /**
  * Consent Authentication Processing filter
@@ -9,56 +10,62 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilter
+
+use SimpleSAML\Logger;
+use SimpleSAML\Module;
+use SimpleSAML\Stats;
+use SimpleSAML\Utils;
+
+class Consent extends \SimpleSAML\Auth\ProcessingFilter
 {
     /**
      * Button to receive focus
      *
      * @var string|null
      */
-    private $_focus = null;
+    private $focus = null;
 
     /**
      * Include attribute values
      *
      * @var bool
      */
-    private $_includeValues = false;
+    private $includeValues = false;
 
     /**
      * Check remember consent
      *
      * @var bool
      */
-    private $_checked = false;
+    private $checked = false;
 
     /**
      * Consent backend storage configuration
      *
-     * @var sspmod_consent_Store|null
+     * @var \SimpleSAML\Module\consent\Store|null
      */
-    private $_store = null;
+    private $store = null;
 
     /**
      * Attributes where the value should be hidden
      *
      * @var array
      */
-    private $_hiddenAttributes = array();
+    private $hiddenAttributes = [];
 
     /**
      * Attributes which should not require consent
      *
-     * @var aray
+     * @var array
      */
-    private $_noconsentattributes = array();
+    private $noconsentattributes = [];
 
     /**
      * Whether we should show the "about service"-link on the no consent page.
      *
      * @var bool
      */
-    private $_showNoConsentAboutService = true;
+    private $showNoConsentAboutService = true;
 
 
     /**
@@ -69,7 +76,7 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
      * @param array $config Configuration information.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception if the configuration is not valid.
+     * @throws \SimpleSAML\Error\Exception if the configuration is not valid.
      */
     public function __construct($config, $reserved)
     {
@@ -78,59 +85,68 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
 
         if (array_key_exists('includeValues', $config)) {
             if (!is_bool($config['includeValues'])) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'Consent: includeValues must be boolean. '.
                     var_export($config['includeValues'], true).' given.'
                 );
             }
-            $this->_includeValues = $config['includeValues'];
+            $this->includeValues = $config['includeValues'];
         }
 
         if (array_key_exists('checked', $config)) {
             if (!is_bool($config['checked'])) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'Consent: checked must be boolean. '.
                     var_export($config['checked'], true).' given.'
                 );
             }
-            $this->_checked = $config['checked'];
+            $this->checked = $config['checked'];
         }
 
         if (array_key_exists('focus', $config)) {
-            if (!in_array($config['focus'], array('yes', 'no'), true)) {
-                throw new SimpleSAML_Error_Exception(
+            if (!in_array($config['focus'], ['yes', 'no'], true)) {
+                throw new \SimpleSAML\Error\Exception(
                     'Consent: focus must be a string with values `yes` or `no`. '.
                     var_export($config['focus'], true).' given.'
                 );
             }
-            $this->_focus = $config['focus'];
+            $this->focus = $config['focus'];
         }
 
         if (array_key_exists('hiddenAttributes', $config)) {
             if (!is_array($config['hiddenAttributes'])) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'Consent: hiddenAttributes must be an array. '.
                     var_export($config['hiddenAttributes'], true).' given.'
                 );
             }
-            $this->_hiddenAttributes = $config['hiddenAttributes'];
+            $this->hiddenAttributes = $config['hiddenAttributes'];
         }
 
-        if (array_key_exists('noconsentattributes', $config)) {
+        if (array_key_exists('attributes.exclude', $config)) {
+            if (!is_array($config['attributes.exclude'])) {
+                throw new \SimpleSAML\Error\Exception(
+                    'Consent: attributes.exclude must be an array. '.
+                    var_export($config['attributes.exclude'], true).' given.'
+                );
+            }
+            $this->noconsentattributes = $config['attributes.exclude'];
+        } elseif (array_key_exists('noconsentattributes', $config)) {
+            Logger::warning("The 'noconsentattributes' option has been deprecated in favour of 'attributes.exclude'.");
             if (!is_array($config['noconsentattributes'])) {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'Consent: noconsentattributes must be an array. '.
                     var_export($config['noconsentattributes'], true).' given.'
                 );
             }
-            $this->_noconsentattributes = $config['noconsentattributes'];
+            $this->noconsentattributes = $config['noconsentattributes'];
         }
 
         if (array_key_exists('store', $config)) {
             try {
-                $this->_store = sspmod_consent_Store::parseStoreConfig($config['store']);
-            } catch (Exception $e) {
-                SimpleSAML\Logger::error(
+                $this->store = \SimpleSAML\Module\consent\Store::parseStoreConfig($config['store']);
+            } catch (\Exception $e) {
+                Logger::error(
                     'Consent: Could not create consent storage: '.
                     $e->getMessage()
                 );
@@ -139,9 +155,9 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
 
         if (array_key_exists('showNoConsentAboutService', $config)) {
             if (!is_bool($config['showNoConsentAboutService'])) {
-                throw new SimpleSAML_Error_Exception('Consent: showNoConsentAboutService must be a boolean.');
+                throw new \SimpleSAML\Error\Exception('Consent: showNoConsentAboutService must be a boolean.');
             }
-            $this->_showNoConsentAboutService = $config['showNoConsentAboutService'];
+            $this->showNoConsentAboutService = $config['showNoConsentAboutService'];
         }
     }
 
@@ -213,7 +229,7 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
      *
      * @return void
      *
-     * @throws SimpleSAML_Error_NoPassive if the request was passive and consent is needed.
+     * @throws \SimpleSAML\Error\NoPassive if the request was passive and consent is needed.
      */
     public function process(&$state)
     {
@@ -228,7 +244,7 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
         $spEntityId = $state['Destination']['entityid'];
         $idpEntityId = $state['Source']['entityid'];
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
         /**
          * If the consent module is active on a bridge $state['saml:sp:IdP']
@@ -242,93 +258,93 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
             $state['Source'] = $idpmeta;
         }
 
-        $statsData = array('spEntityID' => $spEntityId);
+        $statsData = ['spEntityID' => $spEntityId];
 
         // Do not use consent if disabled
         if (isset($state['Source']['consent.disable']) &&
             self::checkDisable($state['Source']['consent.disable'], $spEntityId)
         ) {
-            SimpleSAML\Logger::debug('Consent: Consent disabled for entity '.$spEntityId.' with IdP '.$idpEntityId);
-            SimpleSAML_Stats::log('consent:disabled', $statsData);
+            Logger::debug('Consent: Consent disabled for entity '.$spEntityId.' with IdP '.$idpEntityId);
+            Stats::log('consent:disabled', $statsData);
             return;
         }
         if (isset($state['Destination']['consent.disable']) &&
             self::checkDisable($state['Destination']['consent.disable'], $idpEntityId)
         ) {
-            SimpleSAML\Logger::debug('Consent: Consent disabled for entity '.$spEntityId.' with IdP '.$idpEntityId);
-            SimpleSAML_Stats::log('consent:disabled', $statsData);
+            Logger::debug('Consent: Consent disabled for entity '.$spEntityId.' with IdP '.$idpEntityId);
+            Stats::log('consent:disabled', $statsData);
             return;
         }
 
-        if ($this->_store !== null) {
+        if ($this->store !== null) {
             $source = $state['Source']['metadata-set'].'|'.$idpEntityId;
             $destination = $state['Destination']['metadata-set'].'|'.$spEntityId;
             $attributes = $state['Attributes'];
 
             // Remove attributes that do not require consent
             foreach ($attributes as $attrkey => $attrval) {
-                if (in_array($attrkey, $this->_noconsentattributes, true)) {
+                if (in_array($attrkey, $this->noconsentattributes, true)) {
                     unset($attributes[$attrkey]);
                 }
             }
 
-            SimpleSAML\Logger::debug('Consent: userid: '.$state['UserID']);
-            SimpleSAML\Logger::debug('Consent: source: '.$source);
-            SimpleSAML\Logger::debug('Consent: destination: '.$destination);
+            Logger::debug('Consent: userid: '.$state['UserID']);
+            Logger::debug('Consent: source: '.$source);
+            Logger::debug('Consent: destination: '.$destination);
 
             $userId = self::getHashedUserID($state['UserID'], $source);
             $targetedId = self::getTargetedID($state['UserID'], $source, $destination);
-            $attributeSet = self::getAttributeHash($attributes, $this->_includeValues);
+            $attributeSet = self::getAttributeHash($attributes, $this->includeValues);
 
-            SimpleSAML\Logger::debug(
+            Logger::debug(
                 'Consent: hasConsent() ['.$userId.'|'.$targetedId.'|'.
                 $attributeSet.']'
             );
 
             try {
-                if ($this->_store->hasConsent($userId, $targetedId, $attributeSet)) {
+                if ($this->store->hasConsent($userId, $targetedId, $attributeSet)) {
                     // Consent already given
-                    SimpleSAML\Logger::stats('consent found');
-                    SimpleSAML_Stats::log('consent:found', $statsData);
+                    Logger::stats('consent found');
+                    Stats::log('consent:found', $statsData);
                     return;
                 }
 
-                SimpleSAML\Logger::stats('consent notfound');
-                SimpleSAML_Stats::log('consent:notfound', $statsData);
+                Logger::stats('consent notfound');
+                Stats::log('consent:notfound', $statsData);
 
-                $state['consent:store'] = $this->_store;
+                $state['consent:store'] = $this->store;
                 $state['consent:store.userId'] = $userId;
                 $state['consent:store.destination'] = $targetedId;
                 $state['consent:store.attributeSet'] = $attributeSet;
-            } catch (Exception $e) {
-                SimpleSAML\Logger::error('Consent: Error reading from storage: '.$e->getMessage());
-                SimpleSAML\Logger::stats('Ccnsent failed');
-                SimpleSAML_Stats::log('consent:failed', $statsData);
+            } catch (\Exception $e) {
+                Logger::error('Consent: Error reading from storage: '.$e->getMessage());
+                Logger::stats('Consent failed');
+                Stats::log('consent:failed', $statsData);
             }
         } else {
-            SimpleSAML\Logger::stats('consent nostorage');
-            SimpleSAML_Stats::log('consent:nostorage', $statsData);
+            Logger::stats('consent nostorage');
+            Stats::log('consent:nostorage', $statsData);
         }
 
-        $state['consent:focus'] = $this->_focus;
-        $state['consent:checked'] = $this->_checked;
-        $state['consent:hiddenAttributes'] = $this->_hiddenAttributes;
-        $state['consent:noconsentattributes'] = $this->_noconsentattributes;
-        $state['consent:showNoConsentAboutService'] = $this->_showNoConsentAboutService;
+        $state['consent:focus'] = $this->focus;
+        $state['consent:checked'] = $this->checked;
+        $state['consent:hiddenAttributes'] = $this->hiddenAttributes;
+        $state['consent:noconsentattributes'] = $this->noconsentattributes;
+        $state['consent:showNoConsentAboutService'] = $this->showNoConsentAboutService;
 
         // user interaction necessary. Throw exception on isPassive request
         if (isset($state['isPassive']) && $state['isPassive'] === true) {
-            SimpleSAML_Stats::log('consent:nopassive', $statsData);
-            throw new SimpleSAML\Module\saml\Error\NoPassive(
-                    \SAML2\Constants::STATUS_REQUESTER,
-                    'Unable to give consent on passive request.'
+            Stats::log('consent:nopassive', $statsData);
+            throw new Module\saml\Error\NoPassive(
+                \SAML2\Constants::STATUS_REQUESTER,
+                'Unable to give consent on passive request.'
             );
         }
 
         // Save state and redirect
-        $id = SimpleSAML_Auth_State::saveState($state, 'consent:request');
-        $url = SimpleSAML\Module::getModuleURL('consent/getconsent.php');
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
+        $id = \SimpleSAML\Auth\State::saveState($state, 'consent:request');
+        $url = Module::getModuleURL('consent/getconsent.php');
+        Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
     }
 
 
@@ -342,7 +358,7 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
      */
     public static function getHashedUserID($userid, $source)
     {
-        return hash('sha1', $userid.'|'.SimpleSAML\Utils\Config::getSecretSalt().'|'.$source);
+        return hash('sha1', $userid.'|'.Utils\Config::getSecretSalt().'|'.$source);
     }
 
 
@@ -357,7 +373,7 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
      */
     public static function getTargetedID($userid, $source, $destination)
     {
-        return hash('sha1', $userid.'|'.SimpleSAML\Utils\Config::getSecretSalt().'|'.$source.'|'.$destination);
+        return hash('sha1', $userid.'|'.Utils\Config::getSecretSalt().'|'.$source.'|'.$destination);
     }
 
 
@@ -375,6 +391,9 @@ class sspmod_consent_Auth_Process_Consent extends SimpleSAML_Auth_ProcessingFilt
     public static function getAttributeHash($attributes, $includeValues = false)
     {
         if ($includeValues) {
+            foreach ($attributes as &$values) {
+                sort($values);
+            }
             ksort($attributes);
             $hashBase = serialize($attributes);
         } else {
diff --git a/modules/consent/lib/Consent/Store/Cookie.php b/modules/consent/lib/Consent/Store/Cookie.php
index 4d5d1f0d308a19da4feb793f2e6d4b40d21150cd..1a878073525be1850ec912ec36d8bf93b7cc7088 100644
--- a/modules/consent/lib/Consent/Store/Cookie.php
+++ b/modules/consent/lib/Consent/Store/Cookie.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\consent\Consent\Store;
+
 /**
  * Cookie storage for consent
  *
@@ -18,7 +21,8 @@
  * @author  Olav Morken <olav.morken@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
+
+class Cookie extends \SimpleSAML\Module\consent\Store
 {
     /**
      * Check for consent.
@@ -38,37 +42,36 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
         assert(is_string($destinationId));
         assert(is_string($attributeSet));
 
-        $cookieName = self::_getCookieName($userId, $destinationId);
+        $cookieName = self::getCookieName($userId, $destinationId);
 
-        $data = $userId . ':' . $attributeSet . ':' . $destinationId;
+        $data = $userId.':'.$attributeSet.':'.$destinationId;
 
-        SimpleSAML\Logger::debug('Consent cookie - Get [' . $data . ']');
+        \SimpleSAML\Logger::debug('Consent cookie - Get ['.$data.']');
 
         if (!array_key_exists($cookieName, $_COOKIE)) {
-            SimpleSAML\Logger::debug(
-                'Consent cookie - no cookie with name \'' .
-                $cookieName . '\'.'
+            \SimpleSAML\Logger::debug(
+                'Consent cookie - no cookie with name \''.$cookieName.'\'.'
             );
             return false;
         }
         if (!is_string($_COOKIE[$cookieName])) {
-            SimpleSAML\Logger::warning(
-                'Value of consent cookie wasn\'t a string. Was: ' .
+            \SimpleSAML\Logger::warning(
+                'Value of consent cookie wasn\'t a string. Was: '.
                 var_export($_COOKIE[$cookieName], true)
             );
             return false;
         }
 
-        $data = self::_sign($data);
+        $data = self::sign($data);
 
         if ($_COOKIE[$cookieName] !== $data) {
-            SimpleSAML\Logger::info(
+            \SimpleSAML\Logger::info(
                 'Attribute set changed from the last time consent was given.'
             );
             return false;
         }
 
-        SimpleSAML\Logger::debug(
+        \SimpleSAML\Logger::debug(
             'Consent cookie - found cookie with correct name and value.'
         );
 
@@ -94,13 +97,13 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
         assert(is_string($destinationId));
         assert(is_string($attributeSet));
 
-        $name = self::_getCookieName($userId, $destinationId);
-        $value = $userId . ':' . $attributeSet . ':' . $destinationId;
+        $name = self::getCookieName($userId, $destinationId);
+        $value = $userId.':'.$attributeSet.':'.$destinationId;
 
-        SimpleSAML\Logger::debug('Consent cookie - Set [' . $value . ']');
+        \SimpleSAML\Logger::debug('Consent cookie - Set ['.$value.']');
 
-        $value = self::_sign($value);
-        $this->_setConsentCookie($name, $value);
+        $value = self::sign($value);
+        $this->setConsentCookie($name, $value);
     }
 
 
@@ -119,8 +122,8 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
         assert(is_string($userId));
         assert(is_string($destinationId));
 
-        $name = self::_getCookieName($userId, $destinationId);
-        $this->_setConsentCookie($name, null);
+        $name = self::getCookieName($userId, $destinationId);
+        $this->setConsentCookie($name, null);
     }
 
 
@@ -131,14 +134,14 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
      *
      * @return void This method does not return.
      *
-     * @throws Exception This method always throws an exception indicating that it is not possible to delete all given
+     * @throws \Exception This method always throws an exception indicating that it is not possible to delete all given
      * consents with this handler.
      */
     public function deleteAllConsents($userId)
     {
         assert(is_string($userId));
 
-        throw new Exception(
+        throw new \Exception(
             'The cookie consent handler does not support delete of all consents...'
         );
     }
@@ -157,24 +160,24 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
     {
         assert(is_string($userId));
 
-        $ret = array();
+        $ret = [];
 
-        $cookieNameStart = 'sspmod_consent:';
+        $cookieNameStart = '\SimpleSAML\Module\consent:';
         $cookieNameStartLen = strlen($cookieNameStart);
         foreach ($_COOKIE as $name => $value) {
             if (substr($name, 0, $cookieNameStartLen) !== $cookieNameStart) {
                 continue;
             }
 
-            $value = self::_verify($value);
+            $value = self::verify($value);
             if ($value === false) {
                 continue;
             }
 
             $tmp = explode(':', $value, 3);
             if (count($tmp) !== 3) {
-                SimpleSAML\Logger::warning(
-                    'Consent cookie with invalid value: ' . $value
+                \SimpleSAML\Logger::warning(
+                    'Consent cookie with invalid value: '.$value
                 );
                 continue;
             }
@@ -201,13 +204,13 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
      *
      * @return string The signed data.
      */
-    private static function _sign($data)
+    private static function sign($data)
     {
         assert(is_string($data));
 
-        $secretSalt = SimpleSAML\Utils\Config::getSecretSalt();
+        $secretSalt = \SimpleSAML\Utils\Config::getSecretSalt();
 
-        return sha1($secretSalt . $data . $secretSalt) . ':' . $data;
+        return sha1($secretSalt.$data.$secretSalt).':'.$data;
     }
 
 
@@ -220,20 +223,20 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
      *
      * @return string|false The data, or false if the signature is invalid.
      */
-    private static function _verify($signedData)
+    private static function verify($signedData)
     {
         assert(is_string($signedData));
 
         $data = explode(':', $signedData, 2);
         if (count($data) !== 2) {
-            SimpleSAML\Logger::warning('Consent cookie: Missing signature.');
+            \SimpleSAML\Logger::warning('Consent cookie: Missing signature.');
             return false;
         }
         $data = $data[1];
 
-        $newSignedData = self::_sign($data);
+        $newSignedData = self::sign($data);
         if ($newSignedData !== $signedData) {
-            SimpleSAML\Logger::warning('Consent cookie: Invalid signature.');
+            \SimpleSAML\Logger::warning('Consent cookie: Invalid signature.');
             return false;
         }
 
@@ -251,12 +254,12 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
      *
      * @return string The cookie name
      */
-    private static function _getCookieName($userId, $destinationId)
+    private static function getCookieName($userId, $destinationId)
     {
         assert(is_string($userId));
         assert(is_string($destinationId));
 
-        return 'sspmod_consent:' . sha1($userId . ':' . $destinationId);
+        return '\SimpleSAML\Module\consent:'.sha1($userId.':'.$destinationId);
     }
 
 
@@ -268,24 +271,18 @@ class sspmod_consent_Consent_Store_Cookie extends sspmod_consent_Store
      *
      * @return void
      */
-    private function _setConsentCookie($name, $value)
+    private function setConsentCookie($name, $value)
     {
         assert(is_string($name));
         assert(is_string($value) || $value === null);
 
-        $globalConfig = SimpleSAML_Configuration::getInstance();
-        $params = array(
-            'lifetime' => (90*24*60*60),
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
+        $params = [
+            'lifetime' => 7776000, // (90*24*60*60)
             'path' => ($globalConfig->getBasePath()),
-            'httponly' => false,
-        );
-
-        if (\SimpleSAML\Utils\HTTP::isHTTPS()) {
-            // Enable secure cookie for https-requests
-            $params['secure'] = true;
-        } else {
-            $params['secure'] = false;
-        }
+            'httponly' => true,
+            'secure' => \SimpleSAML\Utils\HTTP::isHTTPS(),
+        ];
 
         \SimpleSAML\Utils\HTTP::setCookie($name, $value, $params, false);
     }
diff --git a/modules/consent/lib/Consent/Store/Database.php b/modules/consent/lib/Consent/Store/Database.php
index 82017a2157f48aea11bc5049c34449dde4f26693..a681220209b172f4d7bf4f2a3b4772fd9227584b 100644
--- a/modules/consent/lib/Consent/Store/Database.php
+++ b/modules/consent/lib/Consent/Store/Database.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\consent\Consent\Store;
+
 /**
  * Store consent in database.
  *
@@ -15,51 +18,52 @@
  * @author Olav Morken <olav.morken@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
+
+class Database extends \SimpleSAML\Module\consent\Store
 {
     /**
      * DSN for the database.
      */
-    private $_dsn;
+    private $dsn;
 
     /**
      * The DATETIME SQL function to use
      */
-    private $_dateTime;
+    private $dateTime;
 
     /**
      * Username for the database.
      */
-    private $_username;
+    private $username;
 
     /**
      * Password for the database;
      */
-    private $_password;
+    private $password;
 
     /**
      * Options for the database;
      */
-    private $_options;
+    private $options;
 
     /**
      * Table with consent.
      */
-    private $_table;
+    private $table;
 
     /**
      * The timeout of the database connection.
      *
      * @var int|null
      */
-    private $_timeout = null;
+    private $timeout = null;
 
     /**
      * Database handle.
      *
      * This variable can't be serialized.
      */
-    private $_db;
+    private $db;
 
 
     /**
@@ -69,62 +73,62 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      *
      * @param array $config Configuration for database consent store.
      *
-     * @throws Exception in case of a configuration error.
+     * @throws \Exception in case of a configuration error.
      */
     public function __construct($config)
     {
         parent::__construct($config);
 
         if (!array_key_exists('dsn', $config)) {
-            throw new Exception('consent:Database - Missing required option \'dsn\'.');
+            throw new \Exception('consent:Database - Missing required option \'dsn\'.');
         }
         if (!is_string($config['dsn'])) {
-            throw new Exception('consent:Database - \'dsn\' is supposed to be a string.');
+            throw new \Exception('consent:Database - \'dsn\' is supposed to be a string.');
         }
 
-        $this->_dsn = $config['dsn'];
-        $this->_dateTime = (0 === strpos($this->_dsn, 'sqlite:')) ? 'DATETIME("NOW")' : 'NOW()';
+        $this->dsn = $config['dsn'];
+        $this->dateTime = (0 === strpos($this->dsn, 'sqlite:')) ? 'DATETIME("NOW")' : 'NOW()';
 
         if (array_key_exists('username', $config)) {
             if (!is_string($config['username'])) {
-                throw new Exception('consent:Database - \'username\' is supposed to be a string.');
+                throw new \Exception('consent:Database - \'username\' is supposed to be a string.');
             }
-            $this->_username = $config['username'];
+            $this->username = $config['username'];
         } else {
-            $this->_username = null;
+            $this->username = null;
         }
 
         if (array_key_exists('password', $config)) {
             if (!is_string($config['password'])) {
-                throw new Exception('consent:Database - \'password\' is supposed to be a string.');
+                throw new \Exception('consent:Database - \'password\' is supposed to be a string.');
             }
-            $this->_password = $config['password'];
+            $this->password = $config['password'];
         } else {
-            $this->_password = null;
+            $this->password = null;
         }
 
         if (array_key_exists('options', $config)) {
             if (!is_array($config['options'])) {
-                throw new Exception('consent:Database - \'options\' is supposed to be an array.');
+                throw new \Exception('consent:Database - \'options\' is supposed to be an array.');
             }
-            $this->_options = $config['options'];
+            $this->options = $config['options'];
         } else {
-            $this->_options = null;
+            $this->options = null;
         }
         if (array_key_exists('table', $config)) {
             if (!is_string($config['table'])) {
-                throw new Exception('consent:Database - \'table\' is supposed to be a string.');
+                throw new \Exception('consent:Database - \'table\' is supposed to be a string.');
             }
-            $this->_table = $config['table'];
+            $this->table = $config['table'];
         } else {
-            $this->_table = 'consent';
+            $this->table = 'consent';
         }
 
         if (isset($config['timeout'])) {
             if (!is_int($config['timeout'])) {
-                throw new Exception('consent:Database - \'timeout\' is supposed to be an integer.');
+                throw new \Exception('consent:Database - \'timeout\' is supposed to be an integer.');
             }
-            $this->_timeout = $config['timeout'];
+            $this->timeout = $config['timeout'];
         }
     }
 
@@ -136,14 +140,14 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      */
     public function __sleep()
     {
-        return array(
-            '_dsn',
-            '_dateTime',
-            '_username',
-            '_password',
-            '_table',
-            '_timeout',
-        );
+        return [
+            'dsn',
+            'dateTime',
+            'username',
+            'password',
+            'table',
+            'timeout',
+        ];
     }
 
 
@@ -166,11 +170,11 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
         assert(is_string($destinationId));
         assert(is_string($attributeSet));
 
-        $st = $this->_execute(
-            'UPDATE ' . $this->_table . ' ' .
-            'SET usage_date = ' . $this->_dateTime . ' ' .
+        $st = $this->execute(
+            'UPDATE '.$this->table.' '.
+            'SET usage_date = '.$this->dateTime.' '.
             'WHERE hashed_user_id = ? AND service_id = ? AND attribute = ?',
-            array($userId, $destinationId, $attributeSet)
+            [$userId, $destinationId, $attributeSet]
         );
 
         if ($st === false) {
@@ -179,10 +183,10 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
 
         $rowCount = $st->rowCount();
         if ($rowCount === 0) {
-            SimpleSAML\Logger::debug('consent:Database - No consent found.');
+            \SimpleSAML\Logger::debug('consent:Database - No consent found.');
             return false;
         } else {
-            SimpleSAML\Logger::debug('consent:Database - Consent found.');
+            \SimpleSAML\Logger::debug('consent:Database - Consent found.');
             return true;
         }
     }
@@ -207,11 +211,11 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
         assert(is_string($attributeSet));
 
         // Check for old consent (with different attribute set)
-        $st = $this->_execute(
-            'UPDATE ' . $this->_table . ' ' .
-            'SET consent_date = ' . $this->_dateTime . ', usage_date = ' . $this->_dateTime . ', attribute = ? ' .
+        $st = $this->execute(
+            'UPDATE '.$this->table.' '.
+            'SET consent_date = '.$this->dateTime.', usage_date = '.$this->dateTime.', attribute = ? '.
             'WHERE hashed_user_id = ? AND service_id = ?',
-            array($attributeSet, $userId, $destinationId)
+            [$attributeSet, $userId, $destinationId]
         );
 
         if ($st === false) {
@@ -220,19 +224,19 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
 
         if ($st->rowCount() > 0) {
             // Consent has already been stored in the database
-            SimpleSAML\Logger::debug('consent:Database - Updated old consent.');
+            \SimpleSAML\Logger::debug('consent:Database - Updated old consent.');
             return;
         }
 
         // Add new consent
-        $st = $this->_execute(
-            'INSERT INTO ' . $this->_table . ' (' . 'consent_date, usage_date, hashed_user_id, service_id, attribute' .
-            ') ' . 'VALUES (' . $this->_dateTime . ', ' . $this->_dateTime . ', ?, ?, ?)',
-            array($userId, $destinationId, $attributeSet)
+        $st = $this->execute(
+            'INSERT INTO '.$this->table.' ('.'consent_date, usage_date, hashed_user_id, service_id, attribute'.
+            ') '.'VALUES ('.$this->dateTime.', '.$this->dateTime.', ?, ?, ?)',
+            [$userId, $destinationId, $attributeSet]
         );
 
         if ($st !== false) {
-            SimpleSAML\Logger::debug('consent:Database - Saved new consent.');
+            \SimpleSAML\Logger::debug('consent:Database - Saved new consent.');
         }
         return true;
     }
@@ -253,23 +257,22 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
         assert(is_string($userId));
         assert(is_string($destinationId));
 
-        $st = $this->_execute(
-            'DELETE FROM ' . $this->_table . ' WHERE hashed_user_id = ? AND service_id = ?;',
-            array($userId, $destinationId)
+        $st = $this->execute(
+            'DELETE FROM '.$this->table.' WHERE hashed_user_id = ? AND service_id = ?;',
+            [$userId, $destinationId]
         );
 
         if ($st === false) {
-            return;
+            return 0;
         }
 
         if ($st->rowCount() > 0) {
-            SimpleSAML\Logger::debug('consent:Database - Deleted consent.');
+            \SimpleSAML\Logger::debug('consent:Database - Deleted consent.');
             return $st->rowCount();
-        } else {
-            SimpleSAML\Logger::warning(
-                'consent:Database - Attempted to delete nonexistent consent'
-            );
         }
+
+        \SimpleSAML\Logger::warning('consent:Database - Attempted to delete nonexistent consent');
+        return 0;
     }
 
 
@@ -284,21 +287,22 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
     {
         assert(is_string($userId));
 
-        $st = $this->_execute(
-            'DELETE FROM ' . $this->_table . ' WHERE hashed_user_id = ?',
-            array($userId)
+        $st = $this->execute(
+            'DELETE FROM '.$this->table.' WHERE hashed_user_id = ?',
+            [$userId]
         );
 
         if ($st === false) {
-            return;
+            return 0;
         }
 
         if ($st->rowCount() > 0) {
-            SimpleSAML\Logger::debug('consent:Database - Deleted (' . $st->rowCount() . ') consent(s).');
+            \SimpleSAML\Logger::debug('consent:Database - Deleted ('.$st->rowCount().') consent(s).');
             return $st->rowCount();
-        } else {
-            SimpleSAML\Logger::warning('consent:Database - Attempted to delete nonexistent consent');
         }
+
+        \SimpleSAML\Logger::warning('consent:Database - Attempted to delete nonexistent consent');
+        return 0;
     }
 
 
@@ -315,19 +319,19 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
     {
         assert(is_string($userId));
 
-        $ret = array();
+        $ret = [];
 
-        $st = $this->_execute(
-            'SELECT service_id, attribute, consent_date, usage_date FROM ' . $this->_table .
+        $st = $this->execute(
+            'SELECT service_id, attribute, consent_date, usage_date FROM '.$this->table.
             ' WHERE hashed_user_id = ?',
-            array($userId)
+            [$userId]
         );
 
         if ($st === false) {
-            return array();
+            return [];
         }
 
-        while ($row = $st->fetch(PDO::FETCH_NUM)) {
+        while ($row = $st->fetch(\PDO::FETCH_NUM)) {
             $ret[] = $row;
         }
 
@@ -344,31 +348,31 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      * @param string $statement  The statement which should be executed.
      * @param array  $parameters Parameters for the statement.
      *
-     * @return PDOStatement|false  The statement, or false if execution failed.
+     * @return \PDOStatement|false  The statement, or false if execution failed.
      */
-    private function _execute($statement, $parameters)
+    private function execute($statement, $parameters)
     {
         assert(is_string($statement));
         assert(is_array($parameters));
 
-        $db = $this->_getDB();
+        $db = $this->getDB();
         if ($db === false) {
             return false;
         }
 
         $st = $db->prepare($statement);
         if ($st === false) {
-            SimpleSAML\Logger::error(
-                'consent:Database - Error preparing statement \'' .
-                $statement . '\': ' . self::_formatError($db->errorInfo())
+            \SimpleSAML\Logger::error(
+                'consent:Database - Error preparing statement \''.
+                $statement.'\': '.self::formatError($db->errorInfo())
             );
             return false;
         }
 
         if ($st->execute($parameters) !== true) {
-            SimpleSAML\Logger::error(
-                'consent:Database - Error executing statement \'' .
-                $statement . '\': ' . self::_formatError($st->errorInfo())
+            \SimpleSAML\Logger::error(
+                'consent:Database - Error executing statement \''.
+                $statement.'\': '.self::formatError($st->errorInfo())
             );
             return false;
         }
@@ -389,45 +393,45 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      */
     public function getStatistics()
     {
-        $ret = array();
+        $ret = [];
 
         // Get total number of consents
-        $st = $this->_execute('SELECT COUNT(*) AS no FROM '.$this->_table, array());
+        $st = $this->execute('SELECT COUNT(*) AS no FROM '.$this->table, []);
 
         if ($st === false) {
-            return array();
+            return [];
         }
 
-        if ($row = $st->fetch(PDO::FETCH_NUM)) {
+        if ($row = $st->fetch(\PDO::FETCH_NUM)) {
             $ret['total'] = $row[0];
         }
 
         // Get total number of users that has given consent
-        $st = $this->_execute(
-            'SELECT COUNT(*) AS no ' .
-            'FROM (SELECT DISTINCT hashed_user_id FROM '.$this->_table.' ) AS foo',
-            array()
+        $st = $this->execute(
+            'SELECT COUNT(*) AS no '.
+            'FROM (SELECT DISTINCT hashed_user_id FROM '.$this->table.' ) AS foo',
+            []
         );
 
         if ($st === false) {
-            return array();
+            return [];
         }
 
-        if ($row = $st->fetch(PDO::FETCH_NUM)) {
+        if ($row = $st->fetch(\PDO::FETCH_NUM)) {
             $ret['users'] = $row[0];
         }
 
         // Get total number of services that has been given consent to
-        $st = $this->_execute(
-            'SELECT COUNT(*) AS no FROM (SELECT DISTINCT service_id FROM '.$this->_table.') AS foo',
-            array()
+        $st = $this->execute(
+            'SELECT COUNT(*) AS no FROM (SELECT DISTINCT service_id FROM '.$this->table.') AS foo',
+            []
         );
 
         if ($st === false) {
-            return array();
+            return [];
         }
 
-        if ($row = $st->fetch(PDO::FETCH_NUM)) {
+        if ($row = $st->fetch(\PDO::FETCH_NUM)) {
             $ret['services'] = $row[0];
         }
 
@@ -438,27 +442,27 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
     /**
      * Get database handle.
      *
-     * @return PDO|false Database handle, or false if we fail to connect.
+     * @return \PDO|false Database handle, or false if we fail to connect.
      */
-    private function _getDB()
+    private function getDB()
     {
-        if ($this->_db !== null) {
-            return $this->_db;
+        if ($this->db !== null) {
+            return $this->db;
         }
 
-        $driver_options = array();
-        if (isset($this->_timeout)) {
-            $driver_options[PDO::ATTR_TIMEOUT] = $this->_timeout;
+        $driver_options = [];
+        if (isset($this->timeout)) {
+            $driver_options[\PDO::ATTR_TIMEOUT] = $this->timeout;
         }
-        if (isset($this->_options)) {
-            $this->_options = array_merge($driver_options, $this->_options);
+        if (isset($this->options)) {
+            $this->options = array_merge($driver_options, $this->options);
         } else {
-            $this->_options = $driver_options;
+            $this->options = $driver_options;
         }
 
-        $this->_db = new PDO($this->_dsn, $this->_username, $this->_password, $this->_options);
+        $this->db = new \PDO($this->dsn, $this->username, $this->password, $this->options);
 
-        return $this->_db;
+        return $this->db;
     }
 
 
@@ -471,12 +475,12 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      *
      * @return string Error text.
      */
-    private static function _formatError($error)
+    private static function formatError($error)
     {
         assert(is_array($error));
         assert(count($error) >= 3);
 
-        return $error[0] . ' - ' . $error[2] . ' (' . $error[1] . ')';
+        return $error[0].' - '.$error[2].' ('.$error[1].')';
     }
 
 
@@ -487,9 +491,9 @@ class sspmod_consent_Consent_Store_Database extends sspmod_consent_Store
      */
     public function selftest()
     {
-        $st = $this->_execute(
-            'SELECT * FROM ' . $this->_table . ' WHERE hashed_user_id = ? AND service_id = ? AND attribute = ?',
-            array('test', 'test', 'test')
+        $st = $this->execute(
+            'SELECT * FROM '.$this->table.' WHERE hashed_user_id = ? AND service_id = ? AND attribute = ?',
+            ['test', 'test', 'test']
         );
 
         if ($st === false) {
diff --git a/modules/consent/lib/Logout.php b/modules/consent/lib/Logout.php
index 821a5fdeeb909d6dc1a6bc5ab50c78bbabcc756c..f82961ee3d487f34ca42225d7f400157f1f57894 100644
--- a/modules/consent/lib/Logout.php
+++ b/modules/consent/lib/Logout.php
@@ -1,17 +1,18 @@
 <?php
 
+namespace SimpleSAML\Module\consent;
 
 /**
  * Class defining the logout completed handler for the consent page.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_consent_Logout
-{
 
-    public static function postLogout(SimpleSAML_IdP $idp, array $state)
+class Logout
+{
+    public static function postLogout(\SimpleSAML\IdP $idp, array $state)
     {
-        $url = SimpleSAML\Module::getModuleURL('consent/logout_completed.php');
+        $url = \SimpleSAML\Module::getModuleURL('consent/logout_completed.php');
         \SimpleSAML\Utils\HTTP::redirectTrustedURL($url);
     }
 }
diff --git a/modules/consent/lib/Store.php b/modules/consent/lib/Store.php
index b9f9ae3cebaa6428b2e32944f36968497105a8fb..0e7c612b9e8b8e77124523c40122a735f414d4e4 100644
--- a/modules/consent/lib/Store.php
+++ b/modules/consent/lib/Store.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\consent;
+
 /**
  * Base class for consent storage handlers.
  *
@@ -6,7 +9,8 @@
  * @author Olav Morken <olav.morken@uninett.no>
  * @author JAcob Christiansen <jach@wayf.dk>
  */
-abstract class sspmod_consent_Store
+
+abstract class Store
 {
     /**
      * Constructor for the base class.
@@ -74,11 +78,11 @@ abstract class sspmod_consent_Store
      *
      * @return mixed Should be the number of consent removed
      *
-     * @throws Exception
+     * @throws \Exception
      */
     public function deleteAllConsents($userId)
     {
-        throw new Exception('Not implemented: deleteAllConsents()');
+        throw new \Exception('Not implemented: deleteAllConsents()');
     }
 
 
@@ -87,11 +91,11 @@ abstract class sspmod_consent_Store
      *
      * @return mixed Statistics from the consent store
      *
-     * @throws Exception
+     * @throws \Exception
      */
     public function getStatistics()
     {
-        throw new Exception('Not implemented: getStatistics()');
+        throw new \Exception('Not implemented: getStatistics()');
     }
 
 
@@ -115,28 +119,28 @@ abstract class sspmod_consent_Store
      *
      * @param mixed $config The configuration.
      *
-     * @return sspmod_consent_Store An object which implements the sspmod_consent_Store class.
+     * @return \SimpleSAML\Module\consent\Store An object which implements the \SimpleSAML\Module\consent\Store class.
      *
-     * @throws Exception if the configuration is invalid.
+     * @throws \Exception if the configuration is invalid.
      */
     public static function parseStoreConfig($config)
     {
         if (is_string($config)) {
-            $config = array($config);
+            $config = [$config];
         }
 
         if (!is_array($config)) {
-            throw new Exception('Invalid configuration for consent store option: '.var_export($config, true));
+            throw new \Exception('Invalid configuration for consent store option: '.var_export($config, true));
         }
 
         if (!array_key_exists(0, $config)) {
-            throw new Exception('Consent store without name given.');
+            throw new \Exception('Consent store without name given.');
         }
 
-        $className = SimpleSAML\Module::resolveClass(
+        $className = \SimpleSAML\Module::resolveClass(
             $config[0],
             'Consent_Store',
-            'sspmod_consent_Store'
+            '\SimpleSAML\Module\consent\Store'
         );
 
         unset($config[0]);
diff --git a/modules/consent/templates/consentform.php b/modules/consent/templates/consentform.php
index d9be45d3249e7b3947caed38815ed8080edd00f2..90907e0ed2812bd8654edfa8c10f1b54320b7670 100644
--- a/modules/consent/templates/consentform.php
+++ b/modules/consent/templates/consentform.php
@@ -3,119 +3,50 @@
  * Template form for giving consent.
  *
  * Parameters:
- * - 'srcMetadata': Metadata/configuration for the source.
- * - 'dstMetadata': Metadata/configuration for the destination.
  * - 'yesTarget': Target URL for the yes-button. This URL will receive a POST request.
- * - 'yesData': Parameters which should be included in the yes-request.
  * - 'noTarget': Target URL for the no-button. This URL will receive a GET request.
- * - 'noData': Parameters which should be included in the no-request.
- * - 'attributes': The attributes which are about to be released.
  * - 'sppp': URL to the privacy policy of the destination, or FALSE.
  *
  * @package SimpleSAMLphp
  */
-assert(is_array($this->data['srcMetadata']));
-assert(is_array($this->data['dstMetadata']));
 assert(is_string($this->data['yesTarget']));
-assert(is_array($this->data['yesData']));
 assert(is_string($this->data['noTarget']));
-assert(is_array($this->data['noData']));
-assert(is_array($this->data['attributes']));
-assert(is_array($this->data['hiddenAttributes']));
 assert($this->data['sppp'] === false || is_string($this->data['sppp']));
 
 // Parse parameters
-if (array_key_exists('name', $this->data['srcMetadata'])) {
-    $srcName = $this->data['srcMetadata']['name'];
-} elseif (array_key_exists('OrganizationDisplayName', $this->data['srcMetadata'])) {
-    $srcName = $this->data['srcMetadata']['OrganizationDisplayName'];
-} else {
-    $srcName = $this->data['srcMetadata']['entityid'];
-}
-
-if (is_array($srcName)) {
-    $srcName = $this->t($srcName);
-}
-
-if (array_key_exists('name', $this->data['dstMetadata'])) {
-    $dstName = $this->data['dstMetadata']['name'];
-} elseif (array_key_exists('OrganizationDisplayName', $this->data['dstMetadata'])) {
-    $dstName = $this->data['dstMetadata']['OrganizationDisplayName'];
-} else {
-    $dstName = $this->data['dstMetadata']['entityid'];
-}
-
-if (is_array($dstName)) {
-    $dstName = $this->t($dstName);
-}
-
-$srcName = htmlspecialchars($srcName);
-$dstName = htmlspecialchars($dstName);
-
-$attributes = $this->data['attributes'];
+$dstName = $this->data['dstName'];
+$srcName = $this->data['srcName'];
 
 $this->data['header'] = $this->t('{consent:consent:consent_header}');
-$this->data['head']  = '<link rel="stylesheet" type="text/css" href="/' .
-    $this->data['baseurlpath'] . 'module.php/consent/style.css" />' . "\n";
+$this->data['head'] = '<link rel="stylesheet" type="text/css" href="'.
+    SimpleSAML\Module::getModuleURL("consent/assets/css/consent.css").'" />'."\n";
 
 $this->includeAtTemplateBase('includes/header.php');
 ?>
-<p>
-<?php
-echo $this->t(
-    '{consent:consent:consent_accept}',
-    array( 'SPNAME' => $dstName, 'IDPNAME' => $srcName)
-);
+<p><?php echo $this->data['consent_accept']; ?></p>
 
-if (array_key_exists('descr_purpose', $this->data['dstMetadata'])) {
-    echo '</p><p>' . $this->t(
-        '{consent:consent:consent_purpose}',
-        array(
-            'SPNAME' => $dstName,
-            'SPDESC' => $this->getTranslator()->getPreferredTranslation(
-                SimpleSAML\Utils\Arrays::arrayize(
-                    $this->data['dstMetadata']['descr_purpose'],
-                    'en'
-                )
-            ),
-        )
-    );
+<?php
+if (isset($this->data['consent_purpose'])) {
+    echo '<p>'.$this->data['consent_purpose'].'</p>';
 }
 ?>
-</p>
-
-<form style="display: inline; margin: 0px; padding: 0px"
-      action="<?php echo htmlspecialchars($this->data['yesTarget']); ?>">
-<p style="margin: 1em">
 
+<form id="consent_yes" action="<?php echo htmlspecialchars($this->data['yesTarget']); ?>">
 <?php
 if ($this->data['usestorage']) {
     $checked = ($this->data['checked'] ? 'checked="checked"' : '');
-    echo '<input type="checkbox" name="saveconsent" ' . $checked .
-        ' value="1" /> ' . $this->t('{consent:consent:remember}');
-}
-
-// Embed hidden fields...
-foreach ($this->data['yesData'] as $name => $value) {
-    echo '<input type="hidden" name="' . htmlspecialchars($name) .
-        '" value="' . htmlspecialchars($value) . '" />';
-}
+    echo '<input type="checkbox" name="saveconsent" '.$checked.
+        ' value="1" /> '.$this->t('{consent:consent:remember}');
+} // Embed hidden fields...
 ?>
-    </p>
+    <input type="hidden" name="StateId" value="<?php echo htmlspecialchars($this->data['stateId']); ?>" />
     <button type="submit" name="yes" class="btn" id="yesbutton">
         <?php echo htmlspecialchars($this->t('{consent:consent:yes}')) ?>
     </button>
 </form>
 
-<form style="display: inline; margin-left: .5em;" action="<?php echo htmlspecialchars($this->data['noTarget']); ?>"
-      method="get">
-
-<?php
-foreach ($this->data['noData'] as $name => $value) {
-    echo('<input type="hidden" name="' . htmlspecialchars($name) .
-        '" value="' . htmlspecialchars($value) . '" />');
-}
-?>
+<form id="consent_no" action="<?php echo htmlspecialchars($this->data['noTarget']); ?>">
+    <input type="hidden" name="StateId" value="<?php echo htmlspecialchars($this->data['stateId']); ?>" />
     <button type="submit" class="btn" name="no" id="nobutton">
         <?php echo htmlspecialchars($this->t('{consent:consent:no}')) ?>
     </button>
@@ -123,113 +54,13 @@ foreach ($this->data['noData'] as $name => $value) {
 
 <?php
 if ($this->data['sppp'] !== false) {
-    echo "<p>" . htmlspecialchars($this->t('{consent:consent:consent_privacypolicy}')) . " ";
-    echo '<a target="_blank" href="' . htmlspecialchars($this->data['sppp']) . '">' . $dstName . "</a>";
+    echo "<p>".htmlspecialchars($this->t('{consent:consent:consent_privacypolicy}'))." ";
+    echo '<a target="_blank" href="'.htmlspecialchars($this->data['sppp']).'">'.$dstName."</a>";
     echo "</p>";
 }
 
-/**
- * Recursive attribute array listing function
- *
- * @param SimpleSAML_XHTML_Template $t          Template object
- * @param array                     $attributes Attributes to be presented
- * @param string                    $nameParent Name of parent element
- *
- * @return string HTML representation of the attributes 
- */
-function present_attributes($t, $attributes, $nameParent)
-{
-    $translator = $t->getTranslator();
-
-    $alternate = array('odd', 'even');
-    $i = 0;
-    $summary = 'summary="' . $t->t('{consent:consent:table_summary}') . '"';
-
-    if (strlen($nameParent) > 0) {
-        $parentStr = strtolower($nameParent) . '_';
-        $str = '<table class="attributes" ' . $summary . '>';
-    } else {
-        $parentStr = '';
-        $str = '<table id="table_with_attributes"  class="attributes" '. $summary .'>';
-        $str .= "\n" . '<caption>' . $t->t('{consent:consent:table_caption}') .
-            '</caption>';
-    }
-
-    foreach ($attributes as $name => $value) {
-        $nameraw = $name;
-        $name = $translator->getAttributeTranslation($parentStr . $nameraw);
-
-        if (preg_match('/^child_/', $nameraw)) {
-            // insert child table
-            $parentName = preg_replace('/^child_/', '', $nameraw);
-            foreach ($value as $child) {
-                $str .= "\n" . '<tr class="odd"><td style="padding: 2em">' .
-                    present_attributes($t, $child, $parentName) . '</td></tr>';
-            }
-        } else {
-            // insert values directly
-
-            $str .= "\n" . '<tr class="' . $alternate[($i++ % 2)] .
-                '"><td><span class="attrname">' . htmlspecialchars($name) . '</span>';
-
-            $isHidden = in_array($nameraw, $t->data['hiddenAttributes'], true);
-            if ($isHidden) {
-                $hiddenId = SimpleSAML\Utils\Random::generateID();
-
-                $str .= '<div class="attrvalue" style="display: none;" id="hidden_' . $hiddenId . '">';
-            } else {
-                $str .= '<div class="attrvalue">';
-            }
-
-            if (sizeof($value) > 1) {
-                // we hawe several values
-                $str .= '<ul>';
-                foreach ($value as $listitem) {
-                    if ($nameraw === 'jpegPhoto') {
-                        $str .= '<li><img src="data:image/jpeg;base64,' .
-                            htmlspecialchars($listitem) .
-                            '" alt="User photo" /></li>';
-                    } else {
-                        $str .= '<li>' . htmlspecialchars($listitem) . '</li>';
-                    }
-                }
-                $str .= '</ul>';
-            } elseif (isset($value[0])) {
-                // we hawe only one value
-                if ($nameraw === 'jpegPhoto') {
-                    $str .= '<img src="data:image/jpeg;base64,' .
-                        htmlspecialchars($value[0]) .
-                        '" alt="User photo" />';
-                } else {
-                    $str .= htmlspecialchars($value[0]);
-                }
-            } // end of if multivalue
-            $str .= '</div>';
-
-            if ($isHidden) {
-                $str .= '<div class="attrvalue consent_showattribute" id="visible_' . $hiddenId . '">';
-                $str .= '... ';
-                $str .= '<a class="consent_showattributelink" href="javascript:SimpleSAML_show(\'hidden_' . $hiddenId;
-                $str .= '\'); SimpleSAML_hide(\'visible_' . $hiddenId . '\');">';
-                $str .= $t->t('{consent:consent:show_attribute}');
-                $str .= '</a>';
-                $str .= '</div>';
-            }
-
-            $str .= '</td></tr>';
-        }	// end else: not child table
-    }	// end foreach
-    $str .= isset($attributes)? '</table>':'';
-    return $str;
-}
-
-echo '<h3 id="attributeheader">' .
-    $this->t(
-        '{consent:consent:consent_attributes_header}',
-        array( 'SPNAME' => $dstName, 'IDPNAME' => $srcName)
-    ) .
-    '</h3>';
+echo '<h3 id="attributeheader">'.$this->data['consent_attributes_header'].'</h3>';
 
-echo present_attributes($this, $attributes, '');
+echo $this->data['attributes_html'];
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/consent/templates/consentform.twig b/modules/consent/templates/consentform.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b1433046a9e07af6757ec0453c9b2c14c715f98b
--- /dev/null
+++ b/modules/consent/templates/consentform.twig
@@ -0,0 +1,38 @@
+{% set pagetitle = '{consent:consent:consent_header}'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+<link rel="stylesheet" type="text/css" href="{{ baseurlpath }}assets/css/consent.css" />
+{% endblock %}
+
+{% block content %}
+<p>{{ consent_accept}}</p>
+
+{% if consent_purpose is defined %}
+    <p>{{ consent_purpose }}</p>
+{% endif %}
+
+<form id="consent_yes" action="{{ yesTarget }}">
+    {% if usestorage is defined %}
+    <input type="checkbox" name="saveconsent"{% if checked %} checked="checked"{% endif %} value="1" />
+    {{ '{consent:consent:remember}'|trans }}
+    {% endif %}
+
+    <input type="hidden" name="StateId" value="{{ stateId }}" />
+    <button type="submit" name="yes" class="btn" id="yesbutton"{%- if autofocus == 'yesbutton' %} autofocus{% endif -%}>{{ '{consent:consent:yes}'|trans }}</button>
+</form>
+
+<form id="consent_no" action="{{ noTarget }}">
+    <input type="hidden" name="StateId" value="{{ stateId }}" />
+    <button type="submit" class="btn" name="no" id="nobutton"{%- if autofocus == 'nobutton' %} autofocus{% endif -%}>{{ '{consent:consent:no}'|trans }}</button>
+</form>
+
+{% if sppp != false %}
+<p>{{ '{consent:consent:consent_privacypolicy}'|trans }}
+    <a target='_blank' href='{{ sppp|escape('url') }} '>{{ dstName }}</a>
+</p>
+{% endif %}
+
+<h3 id="attributeheader">{{ consent_attributes_header }}</h3>
+{{ attributes_html|raw }}
+{% endblock %}
diff --git a/modules/consent/templates/logout_completed.php b/modules/consent/templates/logout_completed.php
index 978931c2bdf3aa8231a27cd824d2fec3b7ce9662..d488d490dd0f380cd8531fee0f3cd83c0dca1f31 100644
--- a/modules/consent/templates/logout_completed.php
+++ b/modules/consent/templates/logout_completed.php
@@ -3,7 +3,7 @@
 $this->data['header'] = $this->t('{logout:title}');
 $this->includeAtTemplateBase('includes/header.php');
 
-echo('<h2>' . $this->data['header'] . '</h2>');
-echo('<p>' . $this->t('{logout:logged_out_text}') . '</p>');
+echo '<h2>'.$this->data['header'].'</h2>';
+echo '<p>'.$this->t('{logout:logged_out_text}').'</p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/consent/templates/logout_completed.twig b/modules/consent/templates/logout_completed.twig
new file mode 100644
index 0000000000000000000000000000000000000000..75503847c5bae4bca03e0132b22edae2ce9162da
--- /dev/null
+++ b/modules/consent/templates/logout_completed.twig
@@ -0,0 +1,7 @@
+{% set pagetitle = '{logout:title}'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+<h2>{{ header }}</h2>
+<p>{{ '{logout:logged_out_text}'|trans }}</p>
+{% endblock %}
diff --git a/modules/consent/templates/noconsent.php b/modules/consent/templates/noconsent.php
index f0bc375b39352f156778df2568c15f791ada594e..4ed911533ac0f512e48e5c70935fe074bbdb81d5 100644
--- a/modules/consent/templates/noconsent.php
+++ b/modules/consent/templates/noconsent.php
@@ -1,38 +1,24 @@
 <?php
 
-if (array_key_exists('name', $this->data['dstMetadata'])) {
-    $dstName = $this->data['dstMetadata']['name'];
-} elseif (array_key_exists('OrganizationDisplayName', $this->data['dstMetadata'])) {
-    $dstName = $this->data['dstMetadata']['OrganizationDisplayName'];
-} else {
-    $dstName = $this->data['dstMetadata']['entityid'];
-}
-if (is_array($dstName)) {
-    $dstName = $this->t($dstName);
-}
-$dstName = htmlspecialchars($dstName);
-
-
-$this->data['header'] = $this->t('{consent:consent:noconsent_title}');;
+$this->data['header'] = $this->t('{consent:consent:noconsent_title}');
 
 $this->includeAtTemplateBase('includes/header.php');
 
-echo '<h2>' . $this->data['header'] . '</h2>';
-echo '<p>' . $this->t('{consent:consent:noconsent_text}', array('SPNAME' => $dstName)) . '</p>';
+echo '<h2>'.$this->data['header'].'</h2>';
+echo '<p>'.$this->data['noconsent_text'].'</p>';
 
 if ($this->data['resumeFrom']) {
-    echo('<p><a href="' . htmlspecialchars($this->data['resumeFrom']) . '">');
+    echo('<p><a href="'.htmlspecialchars($this->data['resumeFrom']).'">');
     echo($this->t('{consent:consent:noconsent_return}'));
     echo('</a></p>');
 }
 
 if ($this->data['aboutService']) {
-    echo('<p><a href="' . htmlspecialchars($this->data['aboutService']) . '">');
+    echo('<p><a href="'.htmlspecialchars($this->data['aboutService']).'">');
     echo($this->t('{consent:consent:noconsent_goto_about}'));
     echo('</a></p>');
 }
 
-echo('<p><a href="' . htmlspecialchars($this->data['logoutLink']) . '">' . $this->t('{consent:consent:abort}', array('SPNAME' => $dstName)) . '</a></p>');
-
+echo('<p><a href="'.htmlspecialchars($this->data['logoutLink']).'">'.$this->data['noconsent_abort'].'</a></p>');
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/consent/templates/noconsent.twig b/modules/consent/templates/noconsent.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b76036697d42f9335620169632d5aabdf946ca0d
--- /dev/null
+++ b/modules/consent/templates/noconsent.twig
@@ -0,0 +1,16 @@
+{% set pagetitle = '{consent:consent:noconsent_title}'|trans %}
+{% extends "base.twig" %}
+{% block content %}
+    <h2>{{ header }}</h2>
+    <p>{{ noconsent_text }}</p>
+
+    {% if resumeFrom %}
+    <p><a href="{{ resumeFrom }}">{{ '{consent:consent:noconsent_return}'|trans }}</a></p>
+    {% endif %}
+
+    {% if aboutService %}
+    <p><a href="{{ aboutService }}">{{ '{consent:consent:noconsent_goto_about}'|trans }}</a></p>
+    {% endif %}
+
+    <p><a href="{{ logoutLink }}">{{ noconsent_abort }}</a></p>
+{% endblock %}
diff --git a/modules/consent/www/style.css b/modules/consent/www/assets/consent.css
similarity index 72%
rename from modules/consent/www/style.css
rename to modules/consent/www/assets/consent.css
index 573ca554bd5adf62e97c31f1a5bd6b0914688ab0..33bef3d64a6c17123c12518e796453e5c1465dd4 100644
--- a/modules/consent/www/style.css
+++ b/modules/consent/www/assets/consent.css
@@ -33,3 +33,22 @@ table#table_with_attributes ul {
     margin: 0px;
     padding-left: 1em;
 }
+
+form#consent_yes {
+    display: inline;
+    margin: 0px;
+    padding: 0px;
+}
+
+form#consent_no {
+    display: inline;
+    margin-left: .5em;
+}
+
+.hidden {
+    display: none;
+}
+
+td.td_odd {
+    padding: 2em;
+}
diff --git a/modules/consent/www/assets/css/consent.css b/modules/consent/www/assets/css/consent.css
new file mode 100644
index 0000000000000000000000000000000000000000..33bef3d64a6c17123c12518e796453e5c1465dd4
--- /dev/null
+++ b/modules/consent/www/assets/css/consent.css
@@ -0,0 +1,54 @@
+fieldset {
+    padding: 0px;
+}
+
+fieldset legend {
+    background: #eee;
+}
+
+h3#attributeheader {
+    margin: 1.5em 0em 0.5em 0em;
+}
+
+table#table_with_attributes .attrname {
+    text-align: right;
+    font-weight: bold;
+}
+
+table#table_with_attributes .attrvalue {
+    padding-left: 1em;
+    margin: 0.5em 0em;
+}
+
+table#table_with_attributes tr:last-child td {
+    border-bottom: none;
+}
+
+table#table_with_attributes img {
+    border: 1px solid #777;
+    margin: 4px;
+}
+
+table#table_with_attributes ul {
+    margin: 0px;
+    padding-left: 1em;
+}
+
+form#consent_yes {
+    display: inline;
+    margin: 0px;
+    padding: 0px;
+}
+
+form#consent_no {
+    display: inline;
+    margin-left: .5em;
+}
+
+.hidden {
+    display: none;
+}
+
+td.td_odd {
+    padding: 2em;
+}
diff --git a/modules/consent/www/getconsent.php b/modules/consent/www/getconsent.php
index 34572b231fd199273a5a949da24eae229a2dc00a..d36e5883c3e3e984713cfe105186988e89601206 100644
--- a/modules/consent/www/getconsent.php
+++ b/modules/consent/www/getconsent.php
@@ -6,11 +6,10 @@
  * authorizes the release of attributes.
  *
  * @package SimpleSAMLphp
- */
-/**
- * Explicit instruct consent page to send no-cache header to browsers to make 
+ *
+ * Explicit instruct consent page to send no-cache header to browsers to make
  * sure the users attribute information are not store on client disk.
- * 
+ *
  * In an vanilla apache-php installation is the php variables set to:
  *
  * session.cache_limiter = nocache
@@ -19,22 +18,22 @@
  */
 session_cache_limiter('nocache');
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-SimpleSAML\Logger::info('Consent - getconsent: Accessing consent interface');
+\SimpleSAML\Logger::info('Consent - getconsent: Accessing consent interface');
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-    throw new SimpleSAML_Error_BadRequest(
+    throw new \SimpleSAML\Error\BadRequest(
         'Missing required StateId query parameter.'
     );
 }
 
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'consent:request');
+$state = \SimpleSAML\Auth\State::loadState($id, 'consent:request');
 
 if (array_key_exists('core:SP', $state)) {
     $spentityid = $state['core:SP'];
-} else if (array_key_exists('saml:sp:State', $state)) {
+} elseif (array_key_exists('saml:sp:State', $state)) {
     $spentityid = $state['saml:sp:State']['core:SP'];
 } else {
     $spentityid = 'UNKNOWN';
@@ -44,20 +43,20 @@ if (array_key_exists('core:SP', $state)) {
 // The user has pressed the yes-button
 if (array_key_exists('yes', $_REQUEST)) {
     if (array_key_exists('saveconsent', $_REQUEST)) {
-        SimpleSAML\Logger::stats('consentResponse remember');
+        \SimpleSAML\Logger::stats('consentResponse remember');
     } else {
-        SimpleSAML\Logger::stats('consentResponse rememberNot');
+        \SimpleSAML\Logger::stats('consentResponse rememberNot');
     }
 
-    $statsInfo = array(
+    $statsInfo = [
         'remember' => array_key_exists('saveconsent', $_REQUEST),
-    );
+    ];
     if (isset($state['Destination']['entityid'])) {
         $statsInfo['spEntityID'] = $state['Destination']['entityid'];
     }
-    SimpleSAML_Stats::log('consent:accept', $statsInfo);
+    \SimpleSAML\Stats::log('consent:accept', $statsInfo);
 
-    if (   array_key_exists('consent:store', $state) 
+    if (array_key_exists('consent:store', $state)
         && array_key_exists('saveconsent', $_REQUEST)
         && $_REQUEST['saveconsent'] === '1'
     ) {
@@ -67,18 +66,17 @@ if (array_key_exists('yes', $_REQUEST)) {
         $targetedId = $state['consent:store.destination'];
         $attributeSet = $state['consent:store.attributeSet'];
 
-        SimpleSAML\Logger::debug(
-            'Consent - saveConsent() : [' . $userId . '|' .
-            $targetedId . '|' .  $attributeSet . ']'
-        );	
+        \SimpleSAML\Logger::debug(
+            'Consent - saveConsent() : ['.$userId.'|'.$targetedId.'|'.$attributeSet.']'
+        );
         try {
             $store->saveConsent($userId, $targetedId, $attributeSet);
-        } catch (Exception $e) {
-            SimpleSAML\Logger::error('Consent: Error writing to storage: ' . $e->getMessage());
+        } catch (\Exception $e) {
+            \SimpleSAML\Logger::error('Consent: Error writing to storage: '.$e->getMessage());
         }
     }
 
-    SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+    \SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
 }
 
 // Prepare attributes for presentation
@@ -86,28 +84,78 @@ $attributes = $state['Attributes'];
 $noconsentattributes = $state['consent:noconsentattributes'];
 
 // Remove attributes that do not require consent
-foreach ($attributes AS $attrkey => $attrval) {
+foreach ($attributes as $attrkey => $attrval) {
     if (in_array($attrkey, $noconsentattributes, true)) {
         unset($attributes[$attrkey]);
     }
 }
-$para = array(
+$para = [
     'attributes' => &$attributes
-);
+];
 
 // Reorder attributes according to attributepresentation hooks
-SimpleSAML\Module::callHooks('attributepresentation', $para);
+\SimpleSAML\Module::callHooks('attributepresentation', $para);
+
+// Parse parameters
+if (array_key_exists('name', $state['Source'])) {
+    $srcName = $state['Source']['name'];
+} elseif (array_key_exists('OrganizationDisplayName', $state['Source'])) {
+    $srcName = $state['Source']['OrganizationDisplayName'];
+} else {
+    $srcName = $state['Source']['entityid'];
+}
+
+if (array_key_exists('name', $state['Destination'])) {
+    $dstName = $state['Destination']['name'];
+} elseif (array_key_exists('OrganizationDisplayName', $state['Destination'])) {
+    $dstName = $state['Destination']['OrganizationDisplayName'];
+} else {
+    $dstName = $state['Destination']['entityid'];
+}
 
 // Make, populate and layout consent form
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'consent:consentform.php');
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'consent:consentform.php');
+$translator = $t->getTranslator();
 $t->data['srcMetadata'] = $state['Source'];
 $t->data['dstMetadata'] = $state['Destination'];
-$t->data['yesTarget'] = SimpleSAML\Module::getModuleURL('consent/getconsent.php');
-$t->data['yesData'] = array('StateId' => $id);
-$t->data['noTarget'] = SimpleSAML\Module::getModuleURL('consent/noconsent.php');
-$t->data['noData'] = array('StateId' => $id);
+$t->data['yesTarget'] = \SimpleSAML\Module::getModuleURL('consent/getconsent.php');
+$t->data['yesData'] = ['StateId' => $id];
+$t->data['noTarget'] = \SimpleSAML\Module::getModuleURL('consent/noconsent.php');
+$t->data['noData'] = ['StateId' => $id];
 $t->data['attributes'] = $attributes;
 $t->data['checked'] = $state['consent:checked'];
+$t->data['stateId'] = $id;
+
+$srcName = htmlspecialchars(is_array($srcName) ? $translator->t($srcName) : $srcName);
+$dstName = htmlspecialchars(is_array($dstName) ? $translator->t($dstName) : $dstName);
+
+$t->data['consent_attributes_header'] = $translator->t(
+    '{consent:consent:consent_attributes_header}',
+    ['SPNAME' => $dstName, 'IDPNAME' => $srcName]
+);
+
+$t->data['consent_accept'] = $translator->t(
+    '{consent:consent:consent_accept}',
+    ['SPNAME' => $dstName, 'IDPNAME' => $srcName]
+);
+
+if (array_key_exists('descr_purpose', $state['Destination'])) {
+    $t->data['consent_purpose'] = $translator->t(
+        '{consent:consent:consent_purpose}',
+        [
+            'SPNAME' => $dstName,
+            'SPDESC' => $translator->getPreferredTranslation(
+                \SimpleSAML\Utils\Arrays::arrayize(
+                    $state['Destination']['descr_purpose'],
+                    'en'
+                )
+            ),
+        ]
+    );
+}
+
+$t->data['srcName'] = $srcName;
+$t->data['dstName'] = $dstName;
 
 // Fetch privacypolicy
 if (array_key_exists('privacypolicy', $state['Destination'])) {
@@ -120,7 +168,7 @@ if (array_key_exists('privacypolicy', $state['Destination'])) {
 if ($privacypolicy !== false) {
     $privacypolicy = str_replace(
         '%SPENTITYID%',
-        urlencode($spentityid), 
+        urlencode($spentityid),
         $privacypolicy
     );
 }
@@ -128,27 +176,117 @@ $t->data['sppp'] = $privacypolicy;
 
 // Set focus element
 switch ($state['consent:focus']) {
-case 'yes':
-    $t->data['autofocus'] = 'yesbutton';
-    break;
-case 'no':
-    $t->data['autofocus'] = 'nobutton';
-    break;
-case null:
-default:
-    break;
+    case 'yes':
+        $t->data['autofocus'] = 'yesbutton';
+        break;
+    case 'no':
+        $t->data['autofocus'] = 'nobutton';
+        break;
+    case null:
+    default:
+        break;
 }
 
-if (array_key_exists('consent:store', $state)) {
-    $t->data['usestorage'] = true;
-} else {
-    $t->data['usestorage'] = false;
-}
+$t->data['usestorage'] = array_key_exists('consent:store', $state);
 
 if (array_key_exists('consent:hiddenAttributes', $state)) {
     $t->data['hiddenAttributes'] = $state['consent:hiddenAttributes'];
 } else {
-    $t->data['hiddenAttributes'] = array();
+    $t->data['hiddenAttributes'] = [];
 }
 
+$t->data['attributes_html'] = present_attributes($t, $attributes, '');
+
 $t->show();
+
+
+/**
+ * Recursive attribute array listing function
+ *
+ * @param \SimpleSAML\XHTML\Template $t          Template object
+ * @param array                     $attributes Attributes to be presented
+ * @param string                    $nameParent Name of parent element
+ *
+ * @return string HTML representation of the attributes
+ */
+function present_attributes($t, $attributes, $nameParent)
+{
+    $translator = $t->getTranslator();
+
+    $alternate = ['odd', 'even'];
+    $i = 0;
+    $summary = 'summary="'.$translator->t('{consent:consent:table_summary}').'"';
+
+    if (strlen($nameParent) > 0) {
+        $parentStr = strtolower($nameParent).'_';
+        $str = '<table class="attributes" '.$summary.'>';
+    } else {
+        $parentStr = '';
+        $str = '<table id="table_with_attributes"  class="attributes" '.$summary.'>';
+        $str .= "\n".'<caption>'.$translator->t('{consent:consent:table_caption}').'</caption>';
+    }
+
+    foreach ($attributes as $name => $value) {
+        $nameraw = $name;
+        $name = $translator->getAttributeTranslation($parentStr.$nameraw);
+
+        if (preg_match('/^child_/', $nameraw)) {
+            // insert child table
+            $parentName = preg_replace('/^child_/', '', $nameraw);
+            foreach ($value as $child) {
+                $str .= "\n".'<tr class="odd"><td class="td_odd">'.
+                    present_attributes($t, $child, $parentName).'</td></tr>';
+            }
+        } else {
+            // insert values directly
+
+            $str .= "\n".'<tr class="'.$alternate[($i++ % 2)].
+                '"><td><span class="attrname">'.htmlspecialchars($name).'</span>';
+
+            $isHidden = in_array($nameraw, $t->data['hiddenAttributes'], true);
+            if ($isHidden) {
+                $hiddenId = \SimpleSAML\Utils\Random::generateID();
+                $str .= '<div class="attrvalue hidden" id="hidden_'.$hiddenId.'">';
+            } else {
+                $str .= '<div class="attrvalue">';
+            }
+
+            if (sizeof($value) > 1) {
+                // we hawe several values
+                $str .= '<ul>';
+                foreach ($value as $listitem) {
+                    if ($nameraw === 'jpegPhoto') {
+                        $str .= '<li><img src="data:image/jpeg;base64,'.
+                            htmlspecialchars($listitem).'" alt="User photo" /></li>';
+                    } else {
+                        $str .= '<li>'.htmlspecialchars($listitem).'</li>';
+                    }
+                }
+                $str .= '</ul>';
+            } elseif (isset($value[0])) {
+                // we hawe only one value
+                if ($nameraw === 'jpegPhoto') {
+                    $str .= '<img src="data:image/jpeg;base64,'.
+                        htmlspecialchars($value[0]).'" alt="User photo" />';
+                } else {
+                    $str .= htmlspecialchars($value[0]);
+                }
+            } // end of if multivalue
+            $str .= '</div>';
+
+            if ($isHidden) {
+                $str .= '<div class="attrvalue consent_showattribute" id="visible_'.$hiddenId.'">';
+                $str .= '... ';
+                $str .= '<a class="consent_showattributelink" href="javascript:SimpleSAML_show(\'hidden_'.$hiddenId;
+                $str .= '\'); SimpleSAML_hide(\'visible_'.$hiddenId.'\');">';
+                $str .= $t->t('{consent:consent:show_attribute}');
+                $str .= '</a>';
+                $str .= '</div>';
+            }
+
+            $str .= '</td></tr>';
+        }       // end else: not child table
+    }   // end foreach
+    $str .= isset($attributes) ? '</table>' : '';
+    return $str;
+}
diff --git a/modules/consent/www/logout.php b/modules/consent/www/logout.php
index 2d46540df73b23eb61cf54aeed83ac02c590e27a..f84a51bb246d616206137696002c1cda35aeddf9 100644
--- a/modules/consent/www/logout.php
+++ b/modules/consent/www/logout.php
@@ -6,12 +6,12 @@
  */
 
 if (!array_key_exists('StateId', $_GET)) {
-    throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_GET['StateId'], 'consent:request');
+$state = \SimpleSAML\Auth\State::loadState($_GET['StateId'], 'consent:request');
 
-$state['Responder'] = array('sspmod_consent_Logout', 'postLogout');
+$state['Responder'] = ['\SimpleSAML\Module\consent\Logout', 'postLogout'];
 
-$idp = SimpleSAML_IdP::getByState($state);
+$idp = \SimpleSAML\IdP::getByState($state);
 $idp->handleLogoutRequest($state, null);
 assert(false);
diff --git a/modules/consent/www/logout_completed.php b/modules/consent/www/logout_completed.php
index a543c30574e1725c831435c5fe2dca00f7057fa1..a5124704f3a192dc6c9fd106ced8d69fc3961785 100644
--- a/modules/consent/www/logout_completed.php
+++ b/modules/consent/www/logout_completed.php
@@ -5,6 +5,6 @@
  * @package SimpleSAMLphp
  */
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'consent:logout_completed.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'consent:logout_completed.php');
 $t->show();
diff --git a/modules/consent/www/noconsent.php b/modules/consent/www/noconsent.php
index 7fcd57b1285be5e1056fe5759aabcb8f291bce48..acd6ffc06514c17430e391d6c03d941593899a2e 100644
--- a/modules/consent/www/noconsent.php
+++ b/modules/consent/www/noconsent.php
@@ -1,47 +1,63 @@
 <?php
+
 /**
  * This is the page the user lands on when choosing "no" in the consent form.
  *
  * @package SimpleSAMLphp
  */
+
 if (!array_key_exists('StateId', $_REQUEST)) {
-    throw new SimpleSAML_Error_BadRequest(
+    throw new \SimpleSAML\Error\BadRequest(
         'Missing required StateId query parameter.'
     );
 }
 
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'consent:request');
+$state = \SimpleSAML\Auth\State::loadState($id, 'consent:request');
 
-$resumeFrom = SimpleSAML\Module::getModuleURL(
+$resumeFrom = \SimpleSAML\Module::getModuleURL(
     'consent/getconsent.php',
-    array('StateId' => $id)
+    ['StateId' => $id]
 );
 
-$logoutLink = SimpleSAML\Module::getModuleURL(
+$logoutLink = \SimpleSAML\Module::getModuleURL(
     'consent/logout.php',
-    array('StateId' => $id)
+    ['StateId' => $id]
 );
 
-
 $aboutService = null;
 if (!isset($state['consent:showNoConsentAboutService']) || $state['consent:showNoConsentAboutService']) {
-	if (isset($state['Destination']['url.about'])) {
-		$aboutService = $state['Destination']['url.about'];
-	}
+    if (isset($state['Destination']['url.about'])) {
+        $aboutService = $state['Destination']['url.about'];
+    }
 }
 
-$statsInfo = array();
+$statsInfo = [];
 if (isset($state['Destination']['entityid'])) {
     $statsInfo['spEntityID'] = $state['Destination']['entityid'];
 }
-SimpleSAML_Stats::log('consent:reject', $statsInfo);
+\SimpleSAML\Stats::log('consent:reject', $statsInfo);
+
+if (array_key_exists('name', $state['Destination'])) {
+    $dstName = $state['Destination']['name'];
+} elseif (array_key_exists('OrganizationDisplayName', $state['Destination'])) {
+    $dstName = $state['Destination']['OrganizationDisplayName'];
+} else {
+    $dstName = $state['Destination']['entityid'];
+}
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'consent:noconsent.php');
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'consent:noconsent.php');
+$translator = $t->getTranslator();
 $t->data['dstMetadata'] = $state['Destination'];
 $t->data['resumeFrom'] = $resumeFrom;
 $t->data['aboutService'] = $aboutService;
 $t->data['logoutLink'] = $logoutLink;
+
+$dstName = htmlspecialchars(is_array($dstName) ? $translator->t($dstName) : $dstName);
+
+$t->data['noconsent_text'] = $translator->t('{consent:consent:noconsent_text}', ['SPNAME' => $dstName]);
+$t->data['noconsent_abort'] = $translator->t('{consent:consent:abort}', ['SPNAME' => $dstName]);
+
 $t->show();
diff --git a/modules/consentAdmin/config-templates/module_consentAdmin.php b/modules/consentAdmin/config-templates/module_consentAdmin.php
index 418065c14ec2ddb421cc9809a0ce39a8156693da..9c5420387ecc04b26ade1b5661ce814242359d14 100644
--- a/modules/consentAdmin/config-templates/module_consentAdmin.php
+++ b/modules/consentAdmin/config-templates/module_consentAdmin.php
@@ -5,28 +5,31 @@
  * @author Jacob Christiansen, <jach@wayf.dk>
  * @package SimpleSAMLphp
  */
-$config = array(
-	/*
-	 * Configuration for the database connection.
-	 */
-	'consentadmin'  => array(
-		'consent:Database',
-		'dsn'		=>	'mysql:host=DBHOST;dbname=DBNAME',
-		'username'	=>	'USERNAME', 
-		'password'	=>	'PASSWORD',
-	),
-	
-	// Hash attributes including values or not
-	'attributes.hash' => TRUE,
+$config = [
+    /*
+     * Configuration for the database connection.
+     */
+    'consentadmin'  => [
+        'consent:Database',
+        'dsn'       =>  'mysql:host=DBHOST;dbname=DBNAME',
+        'username'  =>  'USERNAME',
+        'password'  =>  'PASSWORD',
+    ],
 
-	// Where to direct the user after logout
-    // REMEMBER to prefix with http:// otherwise the relaystate is only appended 
+    // Hash attributes including values or not
+    'attributes.hash' => true,
+
+    // If you set attributes.exclude in the consent module, this must match
+    // 'attributes.exclude' => [],
+
+    // Where to direct the user after logout
+    // REMEMBER to prefix with http:// otherwise the relaystate is only appended
     // to saml2 logout URL
-	'returnURL' => 'http://www.wayf.dk',
+    'returnURL' => 'http://www.wayf.dk',
 
     // Shows description of the services if set to true (defaults to true)
     'showDescription' => true,
 
     // Set authority
     'authority' => 'saml2',
-);
+];
diff --git a/modules/consentAdmin/dictionaries/consentadmin.definition.json b/modules/consentAdmin/dictionaries/consentadmin.definition.json
index a887cf3b7681cb12db9758f1495e2e035b39a827..01a48eddb226ef703cd0a5699798c73772e27000 100644
--- a/modules/consentAdmin/dictionaries/consentadmin.definition.json
+++ b/modules/consentAdmin/dictionaries/consentadmin.definition.json
@@ -1,7 +1,4 @@
 {
-	"sp_empty_name": {
-		"en": "(name not specified)"
-	},
 	"sp_empty_description": {
 		"en": "(no description)"
 	},
@@ -62,4 +59,4 @@
 	"consentadmin_purpose": {
 		"en": "The purpose of the service is"
 	}
-}
\ No newline at end of file
+}
diff --git a/modules/consentAdmin/dictionaries/consentadmin.translation.json b/modules/consentAdmin/dictionaries/consentadmin.translation.json
index f138c56d0a547fe7b0b39253ff84754a924f812b..18af923572217905c30575593f096aad44162623 100644
--- a/modules/consentAdmin/dictionaries/consentadmin.translation.json
+++ b/modules/consentAdmin/dictionaries/consentadmin.translation.json
@@ -1,34 +1,4 @@
 {
-	"sp_empty_name": {
-		"da": "(navn ikke angivet)",
-		"no": "(navn ikke spesifisert)",
-		"de": "(Name nicht angegeben)",
-		"sl": "(brez naziva)",
-		"pt": "(nome n\u00e3o especificado)",
-		"sv": "(namn ej angivet)",
-		"fr": "(nom non indiqu\u00e9)",
-		"hr": "(naziv nije specificiran)",
-		"hu": "(nincs n\u00e9v)",
-		"it": "(nome non specificato)",
-		"es": "(nombre no especificado)",
-		"lt": "(pavadinimas nenurodytas)",
-		"nl": "(naam niet opgegeven)",
-		"ja": "(\u540d\u524d\u7121\u3057)",
-		"zh-tw": "(\u672a\u5b9a\u7fa9\u540d\u7a31)",
-		"nn": "(namn ikkje spesifisert)",
-		"et": "(nimi m\u00e4\u00e4ramata)",
-		"he": "(\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05e9\u05dd)",
-		"zh": "\uff08\u6ca1\u6709\u6307\u5b9a\u540d\u5b57\uff09",
-		"ar": "\u0627\u0644\u0627\u0633\u0645 \u063a\u064a\u0631 \u0645\u062d\u062f\u062f",
-		"lv": "(v\u0101rds nav nor\u0101d\u012bts)",
-		"id": "(Nama tidak diisi)",
-		"sr": "(ime nije specificirano)",
-		"ro": "(nu a fost specificat numele)",
-		"ru": "(\u0438\u043c\u044f \u043d\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e)",
-		"cs": "(jm\u00e9no nespecifikov\u00e1no)",
-		"eu": "(izena ez da zehaztu)",
-		"el": "(\u03c7\u03c9\u03c1\u03af\u03c2 \u03cc\u03bd\u03bf\u03bc\u03b1)"
-	},
 	"sp_empty_description": {
 		"da": "(ingen beskrivelse)",
 		"no": "(ingen beskrivelse)",
@@ -435,7 +405,7 @@
 		"ja": "<h3>\u627f\u8a8d\u306e\u524a\u9664\u65b9\u6cd5<\/h3> \u8a72\u5f53\u3059\u308b\u30b5\u30fc\u30d3\u30b9\u30d7\u30ed\u30d0\u30a4\u30c0\u306e\u30c1\u30a7\u30c3\u30af\u3092\u5916\u3057\u307e\u3059\u3002<h3>\u30ea\u30f3\u30af<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">Start<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">FAQ<\/a> <\/li> <\/ul> ",
 		"zh-tw": "<h3>\u5728\u9019\u522a\u9664\u60a8\u7684\u6388\u6b0a<\/h3> \u53d6\u6d88\u52fe\u9078\u670d\u52d9\u63d0\u4f9b\u8005\u5c0d\u61c9\u7684\u6838\u53d6\u65b9\u584a <h3>\u9023\u7d50<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">\u958b\u59cb<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">\u8aaa\u660e<\/a> <\/li> <\/ul> ",
 		"nn": "<h3>Korleis dra tilbake samtykke<\/h3> Fjern haka i boksen for enkelte tenester <h3>Lenker<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">Start<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/da\/om-wayf\/faq-ofte-stillede-sporgsmal\">Ofte stilte sp\u00f8rsm\u00e5l<\/a> <\/li> <\/ul> ",
-		"nl": "<h3>Hoe verwijderdt u toestemmingen<\/h3> Vinkt u het vakje af dat overeenkomt met de dienstverlener <h3>Links<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">Start<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">FAQ<\/a> <\/li> <\/ul>",
+		"nl": "<h3>Hoe verwijdert u toestemmingen<\/h3> Vinkt u het vakje af dat overeenkomt met de dienstverlener <h3>Links<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">Start<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">FAQ<\/a> <\/li> <\/ul>",
 		"et": "<h3>Kuidas eemaldada n\u00f5usolekut<\/h3> Eemalda vastava teenusepakkuja juurest m\u00e4rge <h3>Viited<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">Start<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">KKK<\/a> <\/li> <\/ul>",
 		"he": "<h3>\u05d0\u05d9\u05da \u05dc\u05d4\u05e1\u05d9\u05e8 \u05d0\u05ea \u05d4\u05e1\u05db\u05de\u05ea\u05da<\/h3> \u05dc\u05d7\u05e5 \u05d1\u05ea\u05d9\u05d1\u05d4 \u05d4\u05de\u05ea\u05d0\u05d9\u05de\u05d4 \u05dc\u05e1\u05e4\u05e7 \u05d4\u05e9\u05d9\u05e8\u05d5\u05ea <h3>\u05e7\u05d9\u05e9\u05d5\u05e8\u05d9\u05dd<\/h3>  <ul> <li><a href=\"https:\/\/www.wayf.dk\">\u05d4\u05ea\u05d7\u05dc\u05d4<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">\u05e9\u05d0\u05dc\u05d5\u05ea \u05e0\u05e4\u05d5\u05e6\u05d5\u05ea<\/a> <\/li> <\/ul> ",
 		"zh": "<h3>\u5982\u4f55\u5220\u9664\u4f60\u7684\u8bb8\u53ef<\/h3>\u53cd\u9009\u76f8\u5e94\u7684SP\u9009\u62e9\u6846<h3>Links<\/h3> <ul> <li><a href=\"https:\/\/www.wayf.dk\">\u5f00\u59cb<\/a> <\/li> <li><a href=\"https:\/\/www.wayf.dk\/index.php\/en\/about-wayf\/faq-frequently-asked-questions\">FAQ<\/a> <\/li> <\/ul>",
diff --git a/modules/consentAdmin/docs/consentAdmin.md b/modules/consentAdmin/docs/consentAdmin.md
index 454cd5f47825899530c4128efd1e2a8f0c84c5c9..1dc342e7f917930674a92ef66908e95cd0fafa99 100644
--- a/modules/consentAdmin/docs/consentAdmin.md
+++ b/modules/consentAdmin/docs/consentAdmin.md
@@ -44,7 +44,9 @@ Setting optional parameters
 In order to make the consentAdmin module work together with the consent
 module correctly, you need to set the configuration 'attributes.hash'
 according to the value of 'includeValues' configuration in the consent
-module.
+module. Likewise, if you've used the 'attributes.exclude' configuration
+option in the consent module, you should also set the 'attributes.exclude'
+configuration option here to match.
 
 You should also set the 'returnURL' configuration in order to pass on your
 users when the press the 'Logout' link.
diff --git a/modules/consentAdmin/hooks/hook_frontpage.php b/modules/consentAdmin/hooks/hook_frontpage.php
index 61c4bd6b1f3b119a47b89efe6321b844d3f41888..87edf27d2e41d58fa57f23c12e697612c2c4b9c6 100644
--- a/modules/consentAdmin/hooks/hook_frontpage.php
+++ b/modules/consentAdmin/hooks/hook_frontpage.php
@@ -4,12 +4,14 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function consentAdmin_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
 
-	$links['config'][] = array(
-		'href' => SimpleSAML\Module::getModuleURL('consentAdmin/consentAdmin.php'),
-		'text' => '{consentAdmin:consentadmin:consentadmin_header}',
-	);
+function consentAdmin_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
+
+    $links['config'][] = [
+        'href' => SimpleSAML\Module::getModuleURL('consentAdmin/consentAdmin.php'),
+        'text' => '{core:frontpage:link_consentAdmin}',
+    ];
 }
diff --git a/modules/consentAdmin/locales/ar/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/ar/LC_MESSAGES/consentAdmin.po
index ed203049a1c3669f338dd9deeda66db2ace19d31..d778277bbbd973ea9b48e4d9d45be983a28cf369 100644
--- a/modules/consentAdmin/locales/ar/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/ar/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "لا يوجد وصف"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "مشغلي الخدمة ل"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "الاسم غير محدد"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "لحذف موافقتك</h3>الغي  صندوق مشغل الخدمة<h3>روابط</h3> <ul> <li><a "
diff --git a/modules/consentAdmin/locales/cs/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/cs/LC_MESSAGES/consentAdmin.po
index 7709b6911b51c29f44ac9425b9e81a8b0f749645..42b3f5277700f88d87b40fc7041f039fecf67bf0 100644
--- a/modules/consentAdmin/locales/cs/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/cs/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(žádný popis)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Poskytovatelé služeb pro"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(jméno nespecifikováno)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Jak smazat vaše povolení</h3> Odznačte políčko odpovídající "
diff --git a/modules/consentAdmin/locales/da/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/da/LC_MESSAGES/consentAdmin.po
index 8961aba8256d658aec74a165ea31c0b1dfac5fb1..bdd2573a1065490cef72ee1eb106c9f952eb0ae2 100644
--- a/modules/consentAdmin/locales/da/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/da/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(ingen beskrivelse)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Service Providers for"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(navn ikke angivet)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>SĂĄdan sletter du et samtykke</h3>Fjern fluebenet ud for tjenesten, "
diff --git a/modules/consentAdmin/locales/de/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/de/LC_MESSAGES/consentAdmin.po
index 2e53b5ce2cac6344e26fcd5942c89dcff33fddbb..72b0ae0fa94fba55e3b92e7b3a2c030c0b78de71 100644
--- a/modules/consentAdmin/locales/de/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/de/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(keine Beschreibung)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Diensteanbieter fĂĽr"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(Name nicht angegeben)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Wie Sie Ihre Einverständniserklärung löschen</h3> Entfernen Sie das "
diff --git a/modules/consentAdmin/locales/el/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/el/LC_MESSAGES/consentAdmin.po
index 207fb949db09116809c6fb1aa71512d5679c445e..15e128a24f917975089837dc7d006911fafc8ed6 100644
--- a/modules/consentAdmin/locales/el/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/el/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(χωρίς περιγραφή)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Πάροχοι Υπηρεσιών για"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(χωρίς όνομα)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Πώς να αναιρέσετε τη συγκατάθεσή σας</h3>Αποεπιλέξτε το κουτί "
diff --git a/modules/consentAdmin/locales/en/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/en/LC_MESSAGES/consentAdmin.po
index 9d68f7f24ba110af81afb3da516e9db56563c63e..ea3d3207f8797a56112448c1a83f502544d8d7cd 100644
--- a/modules/consentAdmin/locales/en/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/en/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(no description)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Service Providers for"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(name not specified)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "\n"
diff --git a/modules/consentAdmin/locales/es/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/es/LC_MESSAGES/consentAdmin.po
index 8ddfa631c742ae1a76aebbe0c935da710a006a49..6d937dde8fbd11e3432a25e23aca819de8925cef 100644
--- a/modules/consentAdmin/locales/es/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/es/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(sin descripciĂłn)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Proveedores de servicio para"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nombre no especificado)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Como eliminar su consentimiento</h3> Desmarque la opciĂłn "
diff --git a/modules/consentAdmin/locales/et/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/et/LC_MESSAGES/consentAdmin.po
index 37219898d7f72962d99ed837c73fce14cdcc8dcd..4a815ad5bddb7ad81c3820f8965419c0b8a00233 100644
--- a/modules/consentAdmin/locales/et/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/et/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(kirjeldus puudub)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Teenusepakkujad"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nimi määramata)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kuidas eemaldada nõusolekut</h3> Eemalda vastava teenusepakkuja "
diff --git a/modules/consentAdmin/locales/eu/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/eu/LC_MESSAGES/consentAdmin.po
index 6d67389b76bc15aaf17aaa0df8b9507cc3f4e8d1..adeb050e0426a80810a2b97c469529d8f224343a 100644
--- a/modules/consentAdmin/locales/eu/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/eu/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(deskribapenik gabe)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Zerbitzu hornitzaileak hontarako: "
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(izena ez da zehaztu)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Zure onespena nola ezabatu</h3> Zerbitzu hornitzaileari dagokion "
diff --git a/modules/consentAdmin/locales/fr/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/fr/LC_MESSAGES/consentAdmin.po
index ca3bde7f1215e6c84a940016d6e13c84c3aafe59..65abab4fd1a305ab9fa691c6799fbab8a4070d80 100644
--- a/modules/consentAdmin/locales/fr/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/fr/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(pas de description)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Fournisseurs de service pour"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nom non indiqué)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Comment révoquer un consentement</h3>Décochez la case correspondante "
diff --git a/modules/consentAdmin/locales/he/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/he/LC_MESSAGES/consentAdmin.po
index 30a632e9d8898500052c4420d0ddb5e778d66051..4cb1b7703ef9f872146d4b0046b6cc5c7401c04b 100644
--- a/modules/consentAdmin/locales/he/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/he/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(אין תיאור)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "ספקי שירות עבור"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(לא ניתן שם)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>איך להסיר את הסכמתך</h3> לחץ בתיבה המתאימה לספק השירות "
diff --git a/modules/consentAdmin/locales/hr/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/hr/LC_MESSAGES/consentAdmin.po
index 46436725170845942314a291a4089488ddafaf94..b7be441fd7c5e13fc64e0b9d049fcd27d56e62c0 100644
--- a/modules/consentAdmin/locales/hr/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/hr/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(nema opisa)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Davatelji usluga za"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(naziv nije specificiran)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kako obrisati dozvolu</h3> Maknite kvaÄŤicu iz polja koje se odnosi na"
diff --git a/modules/consentAdmin/locales/hu/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/hu/LC_MESSAGES/consentAdmin.po
index 78b785ca9b07bdf8827a759a2bdefd57d674e93f..51f0166a1313e3fe22cc6bc400707742668ca2be 100644
--- a/modules/consentAdmin/locales/hu/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/hu/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(nincs leírás)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Szolgáltató"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nincs név)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Hogyan kell visszavonni egy hozzájárulást?</h3> A szolgáltatóhoz "
diff --git a/modules/consentAdmin/locales/id/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/id/LC_MESSAGES/consentAdmin.po
index 04468f2620a739789bfd096cf0a00a1da6472808..64e517dbd6b58654d7a3738ace30fb8accd80089 100644
--- a/modules/consentAdmin/locales/id/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/id/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(Tidak ada penjelasan)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Service Provider untuk"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(Nama tidak diisi)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Bagaimana cara menghapus consent anda</h3> Hapus centak pada kotak "
diff --git a/modules/consentAdmin/locales/it/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/it/LC_MESSAGES/consentAdmin.po
index 6b4875d91ef234dbbf4cbd563febf38cb2dd171a..10b213d142448ecf0ffb5b63a0864c6e889bb019 100644
--- a/modules/consentAdmin/locales/it/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/it/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(nessuna descrizione)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Service provider per"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nome non specificato)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Come rimuovere il consenso></h3> Togliere il segno di spunta al "
diff --git a/modules/consentAdmin/locales/ja/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/ja/LC_MESSAGES/consentAdmin.po
index 6cf0c9dc019f10a1f4e00307000fa46134b10a61..5a26c6aa45459759d116c5feef45794524daa12c 100644
--- a/modules/consentAdmin/locales/ja/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/ja/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(記述無し)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "サービスプロバイダ - "
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(名前無し)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>承認の削除方法</h3> 該当するサービスプロバイダのチェックを外します。<h3>リンク</h3> <ul> <li><a "
diff --git a/modules/consentAdmin/locales/lt/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/lt/LC_MESSAGES/consentAdmin.po
index 41e8fb3b0d09f57a617bb267e417be9fe12e7b01..7596d5e822d2e09388136a49a82a403b06322d5f 100644
--- a/modules/consentAdmin/locales/lt/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/lt/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(apibūdinimas nenurodytas)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Paslaugos tiekÄ—jai"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(pavadinimas nenurodytas)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kaip pašalinti savo leidimą</h3> Panaikinkite pažymėjimą ties "
diff --git a/modules/consentAdmin/locales/lv/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/lv/LC_MESSAGES/consentAdmin.po
index fea6d8bd60879d9a6b63aff98b4b3a1f2d30c3ec..6f5ff436fccd52f22f89e44860a9d7d03abf4a8c 100644
--- a/modules/consentAdmin/locales/lv/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/lv/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(nav apraksta)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Servisa piegādātāji priekš"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(vārds nav norādīts)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kā dzēst noteikumus</h3> Izņemiet ķeksīti pie atbilstošā servisa "
diff --git a/modules/consentAdmin/locales/nb/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/nb/LC_MESSAGES/consentAdmin.po
index c6d1c68b309c614fa525c5e00e8c16e8f3157547..d981bba9d2827e2f8b6cb04274cb75b6f7263237 100644
--- a/modules/consentAdmin/locales/nb/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/nb/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(ingen beskrivelse)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Tjenesteleverandører for"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(navn ikke spesifisert)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Hvordan trekke samtykke tilbake</h3> Fjern haken i boksen for gitte "
diff --git a/modules/consentAdmin/locales/nl/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/nl/LC_MESSAGES/consentAdmin.po
index 9e031e9cb0139e6c2179206c717700ab038d6af8..77c74edc95b9b1b5616238ff9dadb6133771a107 100644
--- a/modules/consentAdmin/locales/nl/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/nl/LC_MESSAGES/consentAdmin.po
@@ -54,12 +54,9 @@ msgstr "(geen omschrijving)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Service Providers voor"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(naam niet opgegeven)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
-"<h3>Hoe verwijderdt u toestemmingen</h3> Vinkt u het vakje af dat "
+"<h3>Hoe verwijdert u toestemmingen</h3> Vinkt u het vakje af dat "
 "overeenkomt met de dienstverlener <h3>Links</h3> <ul> <li><a "
 "href=\"https://www.wayf.dk\">Start</a> </li> <li><a "
 "href=\"https://www.wayf.dk/index.php/en/about-wayf/faq-frequently-asked-"
diff --git a/modules/consentAdmin/locales/nn/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/nn/LC_MESSAGES/consentAdmin.po
index 35aba2cd0132416dc9132c35f2a68444877007c5..dcfd7cba639b552d509c9cf1116c7db5571215ad 100644
--- a/modules/consentAdmin/locales/nn/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/nn/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(mangler informasjon)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Tenesteleverandør for "
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(namn ikkje spesifisert)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Korleis dra tilbake samtykke</h3> Fjern haka i boksen for enkelte "
diff --git a/modules/consentAdmin/locales/pt/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/pt/LC_MESSAGES/consentAdmin.po
index 0673dcb7e9dd1c3eaaf247d63f1ca414429b80b0..85983c36f722c0a1222a87fc79261f044b969a1b 100644
--- a/modules/consentAdmin/locales/pt/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/pt/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(sem descrição)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Fornecedores de Serviços para"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nome nĂŁo especificado)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Como remover o seu consentimento</h3> Retire a marca correspondente "
diff --git a/modules/consentAdmin/locales/ro/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/ro/LC_MESSAGES/consentAdmin.po
index e83dbf971376c429f7379b9fc77ae4919ba15f93..6c1943bfc757495f46d83fcf2e76732383d62b77 100644
--- a/modules/consentAdmin/locales/ro/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/ro/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(fără descriere)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Furnizori de servicii pentru"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(nu a fost specificat numele)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Cum poate fi anulat acordul dumneavoastră</h3>Debifați căsuța "
diff --git a/modules/consentAdmin/locales/ru/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/ru/LC_MESSAGES/consentAdmin.po
index 9169cfd9130b0f950e37357b677c460e435cff4b..a641ee0e4cc58939b9aef9aea5f0da0a36d8cce7 100644
--- a/modules/consentAdmin/locales/ru/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/ru/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(описание отсутствует)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Сервис провайдеры для"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(имя не указано)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Как удалить ваше согласие</h3> Снимите выделение с сервис провайдера "
diff --git a/modules/consentAdmin/locales/sl/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/sl/LC_MESSAGES/consentAdmin.po
index 7afe72a12de1174e0cd4acc94ccc563b8b1e32cb..915d1669df449f9c89a576b2a8e74040ad42808c 100644
--- a/modules/consentAdmin/locales/sl/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/sl/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(brez opisa)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Ponudniki storitev za"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(brez naziva)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kako razveljavim dano privolitev?</h3> Odstranite kljukico pred "
diff --git a/modules/consentAdmin/locales/sr/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/sr/LC_MESSAGES/consentAdmin.po
index 5cd0b78871f939ea3419e2bbbec6906e409f6d5a..6099ce86fc2b0291084bfe30dc98fda6b3834e51 100644
--- a/modules/consentAdmin/locales/sr/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/sr/LC_MESSAGES/consentAdmin.po
@@ -55,9 +55,6 @@ msgstr "(nema opisa)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Davaoci Servisa za"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(ime nije specificirano)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Kako obrisati dozvolu</h3> Uklonite kvaÄŤicu iz polja koje se odnosi "
diff --git a/modules/consentAdmin/locales/sv/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/sv/LC_MESSAGES/consentAdmin.po
index d825178b11084d6263753a422eb21332b9754a23..6777d22f6b70fbd554d3866d917683109ca50dea 100644
--- a/modules/consentAdmin/locales/sv/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/sv/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(ingen beskrivning)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "Tjänsteleverantörer för"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(namn ej angivet)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>Hur du tar bort ditt samtycke</h3> Ta bort markeringen i rutan "
diff --git a/modules/consentAdmin/locales/zh-tw/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/zh-tw/LC_MESSAGES/consentAdmin.po
index b7d2e43bea97dfd1f6777ed056b0f36662932f44..79766547053c53e48b0d5ad4390f0e4893e05be0 100644
--- a/modules/consentAdmin/locales/zh-tw/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/zh-tw/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(無描述)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "服務提供者的"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(未定義名稱)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>在這刪除您的授權</h3> 取消勾選服務提供者對應的核取方塊 <h3>連結</h3> <ul> <li><a "
diff --git a/modules/consentAdmin/locales/zh/LC_MESSAGES/consentAdmin.po b/modules/consentAdmin/locales/zh/LC_MESSAGES/consentAdmin.po
index 0a3b247785351bba5d0793d8c792aa76bcd5fbfa..ab6ab8d229baa7f56d50013f391ffb47c212f4e6 100644
--- a/modules/consentAdmin/locales/zh/LC_MESSAGES/consentAdmin.po
+++ b/modules/consentAdmin/locales/zh/LC_MESSAGES/consentAdmin.po
@@ -54,9 +54,6 @@ msgstr "(没有描述)"
 msgid "{consentAdmin:consentadmin:service_providers_for}"
 msgstr "服务提供商服务于"
 
-msgid "{consentAdmin:consentadmin:sp_empty_name}"
-msgstr "(没有指定名字)"
-
 msgid "{consentAdmin:consentadmin:consentadmin_description2}"
 msgstr ""
 "<h3>如何删除你的许可</h3>反选相应的SP选择框<h3>Links</h3> <ul> <li><a "
diff --git a/modules/consentAdmin/templates/consentadmin.php b/modules/consentAdmin/templates/consentadmin.php
index ce3386c4c82e28366da238425ffbd96cbac1fcef..e8c3bcc839735c465ff979ab1a9994eb21c93995 100644
--- a/modules/consentAdmin/templates/consentadmin.php
+++ b/modules/consentAdmin/templates/consentadmin.php
@@ -1,56 +1,11 @@
-<?php $this->includeAtTemplateBase('includes/header.php'); ?>
-<!--  default theme -->
-
-<script>
-    function setConsentText(consentStatus, show_spid) {
-        document.getElementById("consentText" + show_spid).innerHTML = consentStatus;
-    }
-</script>
-
-<script src="includes/consentSimpleAjax.js"></script>
-
-<style>
-.caSPName {
-    font-weight: bold;
-}
-
-td.caSPName {
-    vertical-align: top;
-}
-
-.caAllowed {
-
-}
-
-td.caAllowed {
-    vertical-align: top;
-}
-
-td.caAttributes {
-
-}
-
-tr.row0 td {
-    background-color: #888888;
-    color: black;
-}
-
-tr.row1 td {
-    background-color: #aaaaaa;
-    color: black;
-}
-
-a.orange {
-    color: #ffd633;
-}
-
-span.showhide {
-
-}
-</style>
-
-
-        <!-- <h2><?php if (isset($this->data['header'])) { echo $this->t($this->data['header']); } else { echo "Some error occurred"; } ?></h2> -->
+<?php
+    $this->data['head'] = '<link rel="stylesheet" type="text/css" href="'.
+        SimpleSAML\Module::getModuleURL("consentAdmin/assets/css/consentAdmin.css").'" />'."\n";
+    $this->data['head'] .= '<script type="text/javascript" src="'.
+        SimpleSAML\Module::getModuleURL("consentAdmin/assets/js/consentAdmin.js").'"></script>';
+    // default theme
+    $this->includeAtTemplateBase('includes/header.php');
+?>
         <h2><?php echo $this->t('{consentAdmin:consentadmin:consentadmin_header}') ?></h2>
         <p>
         <?php echo $this->t('{consentAdmin:consentadmin:consentadmin_description1}') ?> </p>
@@ -59,7 +14,7 @@ span.showhide {
             <table>
             <tr>
                 <th width="80%"><?php echo $this->t('{consentAdmin:consentadmin:service_provider_header}') ?></th>
-                <th width="140"><?php echo $this->t('{consentAdmin:consentadmin:status_header}') ?></th>
+                <th><?php echo $this->t('{consentAdmin:consentadmin:status_header}') ?></th>
             </tr>
             <?php
             $spList = $this->data['spList'];
@@ -67,15 +22,14 @@ span.showhide {
             $show_text = $this->t('{consentAdmin:consentadmin:show}');
             $hide_text = $this->t('{consentAdmin:consentadmin:hide}');
             $attributes_text = $this->t('{consentAdmin:consentadmin:attributes_text}');
-            foreach ($spList AS $spName => $spValues) {
-                $this->getTranslator()->includeInlineTranslation('spname', $spValues['name']);
-                $this->getTranslator()->includeInlineTranslation('spdescription', $spValues['description']);
+            foreach ($spList as $spName => $spValues) {
                 if (!is_null($spValues['serviceurl'])) {
-                    $htmlSpName = '<a href="' . $spValues['serviceurl'] . '" style="color: black; font-weight: bold;">' . htmlspecialchars($this->t('spname', array(), false, true)) . '</a>';
+                    $htmlSpName = '<a class="serviceUrl" href="'.$spValues['serviceurl'].'">'.
+                        htmlspecialchars($spValues['name']).'</a>';
                 } else {
-                    $htmlSpName = htmlspecialchars($this->t('spname', array(), false, true));
+                    $htmlSpName = htmlspecialchars($spValues['name']);
                 }
-                $spDescription = htmlspecialchars($this->t('spdescription',array(), false, true));
+                $spDescription = htmlspecialchars($spValues['description']);
                 $checkedAttr = $spValues['consentStatus'] == 'ok' ? 'checked="checked"' : '';
                 $consentValue = $spValues['consentValue'];
                 $consentText = $spValues['consentStatus'] == 'changed' ? "attributes has changed" : "";
@@ -84,28 +38,26 @@ span.showhide {
 <tr class="$row_class">
 <td>
     <table>
-      <tr class="$row_class"><td><span class='caSPName'><span title='$spDescription'>$htmlSpName</span>&emsp;<span style="font-size: 80%;"onclick="javascript:toggleShowAttributes('$show_spid');"><span id=showing_$show_spid >$show_text</span><span id=hiding_$show_spid style='display:none;'>$hide_text</span> $attributes_text</span></span></td>
-      <tr><td colspan="2" class="caAttributes"><div id="attributes_$show_spid" style="display: none;">
+      <tr class="$row_class">
+          <td><span class='caSPName'><span title='$spDescription'>$htmlSpName</span>&emsp;
+          <span class="show_hide" id="show_hide_$show_spid"><span id='showing_$show_spid'>$show_text</span>
+          <span id='hiding_$show_spid'>$hide_text</span> $attributes_text</span></span></td></tr>
+      <tr><td colspan="2" class="caAttributes"><div id="attributes_$show_spid">
 TRSTART;
                 $attributes = $spValues['attributes_by_sp'];
                 if ($this->data['showDescription']) {
-                    echo '<p>' . $this->t('{consentAdmin:consentadmin:consentadmin_purpose}') . ' ' . $spDescription . '</p>';
+                    echo '<p>'.$this->t('{consentAdmin:consentadmin:consentadmin_purpose}').' '.$spDescription.'</p>';
                 }
                 echo "\n<ul>\n";
-                foreach ($attributes AS $name => $value) {
-
-                if (isset($this->data['attribute_' . htmlspecialchars(strtolower($name)) ])) {
-                  $name = $this->data['attribute_' . htmlspecialchars(strtolower($name))];
-                }
-                $name = $this->getTranslator()->getAttributeTranslation($name); // translate
-                if (sizeof($value) > 1) {
-                        echo "<li>" . htmlspecialchars($name) . ":\n<ul>\n";
-                        foreach ($value AS $v) {
-                            echo '<li>' . htmlspecialchars($v) . "</li>\n";
+                foreach ($attributes as $name => $value) {
+                    if (sizeof($value) > 1) {
+                        echo "<li>".htmlspecialchars($name).":\n<ul>\n";
+                        foreach ($value as $v) {
+                            echo '<li>'.htmlspecialchars($v)."</li>\n";
                         }
                         echo "</ul>\n</li>\n";
                     } else {
-                        echo "<li>" . htmlspecialchars($name) . ": " . htmlspecialchars($value[0]) . "</li>\n";
+                        echo "<li>".htmlspecialchars($name).": ".htmlspecialchars($value[0])."</li>\n";
                     }
                 }
                 echo "</ul>";
@@ -114,10 +66,12 @@ TRSTART;
   </table>
 </td>
 
-<td class='caAllowed'><input onClick="javascript:checkConsent(this.value, $show_spid, this.checked)" value='$consentValue' type='checkbox' $checkedAttr><span id="consentText$show_spid">$consentText</span></td>
+<td class='caAllowed'>
+    <input id="checkbox_$show_spid" class="checkbox" value='$consentValue' type='checkbox' $checkedAttr />
+    <span id="consentText_$show_spid">$consentText</span></td>
 TRSTART;
-            echo "</td></tr>\n";
-            $show_spid++;
+                echo "</tr>\n";
+                $show_spid++;
             }
             ?>
             </table>
@@ -126,7 +80,11 @@ TRSTART;
         <?php echo $this->t('{consentAdmin:consentadmin:consentadmin_description2}') ?> </p>
 
         <h2>Logout</h2>
-
-            <p><a href="<?php echo \SimpleSAML\Module::getModuleURL('consentAdmin/consentAdmin.php', array('logout' => 1)); ?>">Logout</a></p>
+        <p>
+            <a href="
+            <?php
+                echo \SimpleSAML\Module::getModuleURL('consentAdmin/consentAdmin.php', ['logout' => 1]);
+            ?>">Logout</a>
+        </p>
 
 <?php $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/consentAdmin/templates/consentadmin.twig b/modules/consentAdmin/templates/consentadmin.twig
new file mode 100644
index 0000000000000000000000000000000000000000..d27b8a63d399432c22585deb97e35d6aa7f54156
--- /dev/null
+++ b/modules/consentAdmin/templates/consentadmin.twig
@@ -0,0 +1,82 @@
+{% set pagetitle = '{consentAdmin:consentadmin:consentadmin_header}'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+<link rel="stylesheet" type="text/css" href="{{ basepathurl }}assets/css/consentAdmin.css" />
+{% endblock %}
+
+{% block postload %}
+<script src="{{ baseurlpath }}assets/js/consentAdmin.js"></script>
+{% endblock %}
+
+{% block content %}
+
+<h2>{{ '{consentAdmin:consentadmin:consentadmin_header}'|trans }}</h2>
+<p>{{ '{consentAdmin:consentadmin:consentadmin_description1}'|trans }}</p>
+
+<table>
+    <tr>
+        <th colspan="2" width="80%">{{ '{consentAdmin:consentadmin:service_provider_header}'|trans }}</th>
+        <th width="140">{{ '{consentAdmin:consentadmin:status_header}'|trans }}</th>
+    </tr>
+
+{% for spName, spValues in spList %}
+
+    {% if loop.index0 % 2 == 0 %}
+        {% set rowClass = 'row0' %}
+    {% else %}
+        {% set rowClass = 'row1' %}
+    {% endif %}
+
+    <tr class="{{ rowClass }}">
+        <td>
+            <span class='caSPName'>
+                <span title='{{ spValues.description|escape('html') }}'>
+                {% if spValues.serviceurl is defined %}
+                    {{ spValues.name|escape('html') }}
+                {% else %}
+                    <a class="serviceUrl" href="{{ spValues.serviceurl }}">{{ spValues.name|escape('html') }}</a>
+                {% endif %}
+                </span>
+                <span class="show_hide" id="show_hide_{{ loop.index0 }}">
+                    <span id="showing_{{ loop.index0 }}">{{ '{consentAdmin:consentadmin:show}'|trans }}</span>
+                    <span id="hiding_{{ loop.index0 }}">{{ '{consentAdmin:consentadmin:hide}'|trans }}</span>
+                    {{ '{consentAdmin:consentadmin:attributes_text}'|trans }}
+                </span>
+            </span>
+        </td>
+        <td class="caAttributes">
+            <div id="attributes_{{ loop.index0 }}">
+            {% if showDescription %}
+                <p>{{ '{consentAdmin:consentadmin:consentadmin_purpose}'|trans }}{{ spValues.description|escape('html') }}</p>
+            {% endif %}
+                <ul>
+                {% for attrName, attrValue in spValues.attributes_by_sp %}
+                {% if attrValue|length > 1 %}
+                    <li>{{ attrName|escape('html') }}:
+                        <ul>
+                        {% for valKey, value in attrValue %}
+                            <li>{{ value|escape('html') }}</li>
+                        {% endfor %}
+                        </ul>
+                    </li>
+                {% else %}
+                    <li>{{ attrName|escape('html') }}: {{ attrValue|first|escape('html') }}</li>
+                {% endif %}
+                {% endfor %}
+                </ul>
+            </div>
+        </td>
+        <td class="caAllowed">
+            <input class="checkbox" id="checkbox_{{ loop.index0 }}" value='{{ spValues.consentValue }}' type='checkbox'{% if spValues.consentStatus == 'ok'%} checked="checked"{% endif %} /><span id="consentText_{{ loop.index0 }}">{% if spValues.consentStatus == 'changed' %}attributes has changed{% endif %}</span>
+        </td>
+    </tr>
+{% endfor %}
+</table>
+
+<p>{{ '{consentAdmin:consentadmin:consentadmin_description2}'|trans|raw }}</p>
+
+<h2>Logout</h2>
+<p><a href="{{ baseurlpath }}consentAdmin.php?logout=1">Logout</a></p>
+
+{% endblock %}
diff --git a/modules/consentAdmin/templates/consentadminajax.php b/modules/consentAdmin/templates/consentadminajax.php
index 6055428960b6ee18ab6ebab76a6d426957d16ea4..c8520b085576ddfdde6850fd8920f5566a022d2d 100644
--- a/modules/consentAdmin/templates/consentadminajax.php
+++ b/modules/consentAdmin/templates/consentadminajax.php
@@ -1,2 +1,2 @@
-<?php 
-print $this->t($this->data['res']);
+<?php
+echo $res;
diff --git a/modules/consentAdmin/templates/consentadminajax.twig b/modules/consentAdmin/templates/consentadminajax.twig
new file mode 100644
index 0000000000000000000000000000000000000000..2b8211892e9dc8a49342025ba38024ef60417924
--- /dev/null
+++ b/modules/consentAdmin/templates/consentadminajax.twig
@@ -0,0 +1,3 @@
+{% block content %}
+{{ res }}
+{% endblock %}
diff --git a/modules/consentAdmin/www/assets/css/consentAdmin.css b/modules/consentAdmin/www/assets/css/consentAdmin.css
new file mode 100644
index 0000000000000000000000000000000000000000..94c4a190c4c796224a8ad9a7c9ed4b6449552a9f
--- /dev/null
+++ b/modules/consentAdmin/www/assets/css/consentAdmin.css
@@ -0,0 +1,39 @@
+.caSPName {
+    font-weight: bold;
+}
+td.caSPName {
+    vertical-align: top;
+}
+td.caAllowed {
+    vertical-align: top;
+}
+td.caAttributes {
+}
+tr.row0 td {
+    background-color: #888888;
+    color: black;
+}
+tr.row1 td {
+    background-color: #aaaaaa;
+    color: black;
+}
+a.orange {
+    color: #ffd633;
+}
+
+span.show_hide {
+    font-size: 80%;
+}
+
+a.serviceUrl {
+    color: black;
+    font-weight: bold;
+}
+
+span[id^='hiding_'], span[id*='hiding_'] {
+    display: none;
+}
+
+div[id^='attributes_'], div[id*='attributes_'] {
+    display: none;
+}
diff --git a/modules/consentAdmin/www/assets/js/consentAdmin.js b/modules/consentAdmin/www/assets/js/consentAdmin.js
new file mode 100644
index 0000000000000000000000000000000000000000..59cf4e17b4bbf471ed32249df7df163e45be1368
--- /dev/null
+++ b/modules/consentAdmin/www/assets/js/consentAdmin.js
@@ -0,0 +1,79 @@
+var xmlHttp;
+
+function checkConsent()
+{
+    var show_spid = this.id.charAt(this.id.length-1);
+    var checkbox = document.getElementById("checkbox_"+show_spid);
+
+    xmlHttp = GetXmlHttpObject()
+    if (xmlHttp == null) {
+        alert("Browser does not support HTTP Request")
+        return
+    }
+
+    var url = "consentAdmin.php"
+    url = url+"?cv="+checkbox.value
+    url = url+"&action="+checkbox.checked
+    url = url+"&sid="+Math.random()
+
+    xmlHttp.onreadystatechange = function () {
+        if (xmlHttp.readyState == 4 || xmlHttp.readyState == "complete") {
+            document.getElementById("consentText_" + show_spid).innerHTML = xmlHttp.responseText;
+        }
+    }
+
+    xmlHttp.open("GET", url, true)
+    xmlHttp.send(null)
+}
+
+// This function creates an XMLHttpRequest
+function GetXmlHttpObject()
+{
+    var xmlHttp = null;
+    try {
+        // Firefox, Opera 8.0+, Safari
+        xmlHttp = new XMLHttpRequest();
+    } catch (e) {
+        //Internet Explorer
+        try {
+            xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
+        } catch (e) {
+            xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
+        }
+    }
+    return xmlHttp;
+}
+
+function toggleShowAttributes()
+{
+    var show_spid = this.id.charAt(this.id.length-1);
+
+    var disp = document.getElementById('attributes_' + show_spid);
+    var showing = document.getElementById('showing_' + show_spid);
+    var hiding = document.getElementById('hiding_' + show_spid);
+
+    disp.style.display = (disp.style.display == 'none' ? 'block' : 'none');
+    showing.style.display = (disp.style.display == 'none' ? 'inline' : 'none');
+    hiding.style.display = (disp.style.display == 'none' ? 'none' : 'inline');
+}
+
+document.addEventListener(
+    'DOMContentLoaded',
+    function () {
+        var show_hide = document.getElementsByClassName("show_hide");
+        for (var i = 0; i < show_hide.length; i++) {
+            show_hide[i].addEventListener(
+                'click',
+                toggleShowAttributes
+            );
+        }
+
+        var checkbox = document.getElementsByClassName("checkbox");
+        for (var i = 0; i < checkbox.length; i++) {
+            checkbox[i].addEventListener(
+                'click',
+                checkConsent
+            );
+        }
+    }
+);
diff --git a/modules/consentAdmin/www/consentAdmin.php b/modules/consentAdmin/www/consentAdmin.php
index ebc09fc30e49e7eac72ece346ec53bf6bbb27410..17a091d0871c7a32efdc150c074f7daaaeb8a3c3 100644
--- a/modules/consentAdmin/www/consentAdmin.php
+++ b/modules/consentAdmin/www/consentAdmin.php
@@ -22,24 +22,30 @@ function driveProcessingChain(
     $sp_entityid,
     $attributes,
     $userid,
-    $hashAttributes = false
+    $hashAttributes = false,
+    $excludeAttributes = []
 ) {
-
     /*
      * Create a new processing chain
      */
-    $pc = new SimpleSAML_Auth_ProcessingChain($idp_metadata, $sp_metadata, 'idp');
+    $pc = new \SimpleSAML\Auth\ProcessingChain($idp_metadata, $sp_metadata, 'idp');
 
     /*
      * Construct the state.
      * REMEMBER: Do not set Return URL if you are calling processStatePassive
      */
-    $authProcState = array(
+    $authProcState = [
         'Attributes'  => $attributes,
         'Destination' => $sp_metadata,
+        'SPMetadata'  => $sp_metadata,
         'Source'      => $idp_metadata,
+        'IdPMetadata' => $idp_metadata,
         'isPassive'   => true,
-    );
+    ];
+    /* we're being bridged, so add that info to the state */
+    if (strpos($source, '-idp-remote|') !== false) {
+        $authProcState['saml:sp:IdP'] = substr($source, strpos($source, '|') + 1);
+    }
 
     /*
      * Call processStatePAssive.
@@ -48,26 +54,32 @@ function driveProcessingChain(
     $pc->processStatePassive($authProcState);
 
     $attributes = $authProcState['Attributes'];
+    // Remove attributes that do not require consent/should be excluded
+    foreach ($attributes as $attrkey => $attrval) {
+        if (in_array($attrkey, $excludeAttributes)) {
+            unset($attributes[$attrkey]);
+        }
+    }
 
     /*
      * Generate identifiers and hashes
      */
     $destination = $sp_metadata['metadata-set'].'|'.$sp_entityid;
 
-    $targeted_id = sspmod_consent_Auth_Process_Consent::getTargetedID($userid, $source, $destination);
-    $attribute_hash = sspmod_consent_Auth_Process_Consent::getAttributeHash($attributes, $hashAttributes);
+    $targeted_id = \SimpleSAML\Module\consent\Auth\Process\Consent::getTargetedID($userid, $source, $destination);
+    $attribute_hash = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes, $hashAttributes);
 
-    SimpleSAML\Logger::info('consentAdmin: user: '.$userid);
-    SimpleSAML\Logger::info('consentAdmin: target: '.$targeted_id);
-    SimpleSAML\Logger::info('consentAdmin: attribute: '.$attribute_hash);
+    \SimpleSAML\Logger::info('consentAdmin: user: '.$userid);
+    \SimpleSAML\Logger::info('consentAdmin: target: '.$targeted_id);
+    \SimpleSAML\Logger::info('consentAdmin: attribute: '.$attribute_hash);
 
     // Return values
-    return array($targeted_id, $attribute_hash, $attributes);
+    return [$targeted_id, $attribute_hash, $attributes];
 }
 
 // Get config object
-$config = SimpleSAML_Configuration::getInstance();
-$cA_config = SimpleSAML_Configuration::getConfig('module_consentAdmin.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$cA_config = \SimpleSAML\Configuration::getConfig('module_consentAdmin.php');
 $authority = $cA_config->getValue('authority');
 
 $as = new \SimpleSAML\Auth\Simple($authority);
@@ -80,6 +92,8 @@ if (array_key_exists('logout', $_REQUEST)) {
 
 $hashAttributes = $cA_config->getValue('attributes.hash');
 
+$excludeAttributes = $cA_config->getValue('attributes.exclude', []);
+
 // Check if valid local session exists
 $as->requireAuth();
 
@@ -87,33 +101,36 @@ $as->requireAuth();
 $attributes = $as->getAttributes();
 
 // Get metadata storage handler
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
 /*
  * Get IdP id and metadata
  */
 
 
-$local_idp_entityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
-$local_idp_metadata = $metadata->getMetaData($local_idp_entityid, 'saml20-idp-hosted');
+$idp_entityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
+$idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-hosted');
 
+// Calc correct source
 if ($as->getAuthData('saml:sp:IdP') !== null) {
     // from a remote idp (as bridge)
-    $idp_entityid = $as->getAuthData('saml:sp:IdP');
-    $idp_metadata = $metadata->getMetaData($idp_entityid, 'saml20-idp-remote');
+    $source = 'saml20-idp-remote|'.$as->getAuthData('saml:sp:IdP');
 } else {
     // from the local idp
-    $idp_entityid = $local_idp_entityid;
-    $idp_metadata = $local_idp_metadata;
+    $source = $idp_metadata['metadata-set'].'|'.$idp_entityid;
 }
 
 // Get user ID
-$userid_attributename = (isset($local_idp_metadata['userid.attribute']) && is_string($local_idp_metadata['userid.attribute'])) ? $local_idp_metadata['userid.attribute'] : 'eduPersonPrincipalName';
+if (isset($idp_metadata['userid.attribute']) && is_string($idp_metadata['userid.attribute'])) {
+    $userid_attributename = $idp_metadata['userid.attribute'];
+} else {
+    $userid_attributename = 'eduPersonPrincipalName';
+}
 
 $userids = $attributes[$userid_attributename];
 
 if (empty($userids)) {
-    throw new Exception('Could not generate useridentifier for storing consent. Attribute ['.
+    throw new \Exception('Could not generate useridentifier for storing consent. Attribute ['.
         $userid_attributename.'] was not available.');
 }
 
@@ -132,44 +149,56 @@ if (!empty($_GET['action'])) {
     $action = $_GET["action"];
 }
 
-SimpleSAML\Logger::critical('consentAdmin: sp: '.$sp_entityid.' action: '.$action);
+\SimpleSAML\Logger::critical('consentAdmin: sp: '.$sp_entityid.' action: '.$action);
 
 // Remove services, whitch have consent disabled
 if (isset($idp_metadata['consent.disable'])) {
-    foreach ($idp_metadata['consent.disable'] AS $disable) {
+    foreach ($idp_metadata['consent.disable'] as $disable) {
         if (array_key_exists($disable, $all_sp_metadata)) {
             unset($all_sp_metadata[$disable]);
         }
     }
 }
 
-SimpleSAML\Logger::info('consentAdmin: '.$idp_entityid);
-
-// Calc correct source
-$source = $idp_metadata['metadata-set'].'|'.$idp_entityid;
+\SimpleSAML\Logger::info('consentAdmin: '.$idp_entityid);
 
 // Parse consent config
-$consent_storage = sspmod_consent_Store::parseStoreConfig($cA_config->getValue('consentadmin'));
+$consent_storage = \SimpleSAML\Module\consent\Store::parseStoreConfig($cA_config->getValue('consentadmin'));
 
 // Calc correct user ID hash
-$hashed_user_id = sspmod_consent_Auth_Process_Consent::getHashedUserID($userid, $source);
+$hashed_user_id = \SimpleSAML\Module\consent\Auth\Process\Consent::getHashedUserID($userid, $source);
 
 // If a checkbox have been clicked
 if ($action !== null && $sp_entityid !== null) {
+    // init template to enable translation of status messages
+    $template = new \SimpleSAML\XHTML\Template(
+        $config,
+        'consentAdmin:consentadminajax.php',
+        'consentAdmin:consentadmin'
+    );
+
     // Get SP metadata
     $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
 
     // Run AuthProc filters
-    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata,
-        $sp_entityid, $attributes, $userid, $hashAttributes);
+    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain(
+        $idp_metadata,
+        $source,
+        $sp_metadata,
+        $sp_entityid,
+        $attributes,
+        $userid,
+        $hashAttributes,
+        $excludeAttributes
+    );
 
     // Add a consent (or update if attributes have changed and old consent for SP and IdP exists)
     if ($action == 'true') {
         $isStored = $consent_storage->saveConsent($hashed_user_id, $targeted_id, $attribute_hash);
         if ($isStored) {
-            $res = "added";
+            $res = $translator->t("added");
         } else {
-            $res = "updated";
+            $res = $translator->t("updated");
         }
         // Remove consent
     } else {
@@ -177,16 +206,14 @@ if ($action !== null && $sp_entityid !== null) {
             // Got consent, so this is a request to remove it
             $rowcount = $consent_storage->deleteConsent($hashed_user_id, $targeted_id);
             if ($rowcount > 0) {
-                $res = "removed";
+                $res = $translator->t("removed");
             }
             // Unknown action (should not happen)
         } else {
-            SimpleSAML\Logger::info('consentAdmin: unknown action');
-            $res = "unknown";
+            \SimpleSAML\Logger::info('consentAdmin: unknown action');
+            $res = $translator->t("unknown");
         }
     }
-    // init template to enable translation of status messages
-    $template = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadminajax.php', 'consentAdmin:consentadmin');
     $template->data['res'] = $res;
     $template->show();
     exit;
@@ -196,18 +223,18 @@ if ($action !== null && $sp_entityid !== null) {
 $user_consent_list = $consent_storage->getConsents($hashed_user_id);
 
 // Parse list of consents
-$user_consent = array();
+$user_consent = [];
 foreach ($user_consent_list as $c) {
     $user_consent[$c[0]] = $c[1];
 }
 
-$template_sp_content = array();
+$template_sp_content = [];
 
 // Init template
-$template = new SimpleSAML_XHTML_Template($config, 'consentAdmin:consentadmin.php', 'consentAdmin:consentadmin');
+$template = new \SimpleSAML\XHTML\Template($config, 'consentAdmin:consentadmin.php', 'consentAdmin:consentadmin');
 $translator = $template->getTranslator();
-$translator->includeLanguageFile('attributes.php'); // attribute listings translated by this dictionary
-$sp_empty_name = $translator->getTag('sp_empty_name');
+$translator->includeLanguageFile('attributes'); // attribute listings translated by this dictionary
+
 $sp_empty_description = $translator->getTag('sp_empty_description');
 
 // Process consents for all SP
@@ -216,16 +243,35 @@ foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
     $sp_metadata = $metadata->getMetaData($sp_entityid, 'saml20-sp-remote');
 
     // Run attribute filters
-    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain($idp_metadata, $source, $sp_metadata,
-        $sp_entityid, $attributes, $userid, $hashAttributes);
+    list($targeted_id, $attribute_hash, $attributes_new) = driveProcessingChain(
+        $idp_metadata,
+        $source,
+        $sp_metadata,
+        $sp_entityid,
+        $attributes,
+        $userid,
+        $hashAttributes,
+        $excludeAttributes
+    );
+
+    // Translate attribute-names
+    foreach ($attributes_new as $orig_name => $value) {
+        if (isset($template->data['attribute_'.htmlspecialchars(strtolower($orig_name))])) {
+            $old_name = $template->data['attribute_'.htmlspecialchars(strtolower($orig_name))];
+        }
+        $name = $translator->getAttributeTranslation(strtolower($orig_name)); // translate
+
+        $attributes_new[$name] = $value;
+        unset($attributes_new[$orig_name]);
+    }
 
     // Check if consent exists
     if (array_key_exists($targeted_id, $user_consent)) {
         $sp_status = "changed";
-        SimpleSAML\Logger::info('consentAdmin: changed');
+        \SimpleSAML\Logger::info('consentAdmin: changed');
         // Check if consent is valid. (Possible that attributes has changed)
         if ($user_consent[$targeted_id] == $attribute_hash) {
-            SimpleSAML\Logger::info('consentAdmin: ok');
+            \SimpleSAML\Logger::info('consentAdmin: ok');
             $sp_status = "ok";
         }
         // Consent does not exists
@@ -243,7 +289,7 @@ foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
         } elseif (isset($sp_values['OrganizationDisplayName']) && is_array($sp_values['OrganizationDisplayName'])) {
             $sp_name = $sp_metadata['OrganizationDisplayName'];
         } else {
-            $sp_name = $sp_empty_name;
+            $sp_name = $sp_entityid;
         }
     }
 
@@ -257,8 +303,15 @@ foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
     // Add a URL to the service if present in metadata
     $sp_service_url = isset($sp_metadata['ServiceURL']) ? $sp_metadata['ServiceURL'] : null;
 
+    // Translate SP name and description
+    $translator->includeInlineTranslation('spname', $sp_name);
+    $translator->includeInlineTranslation('spdescription', $sp_description);
+
+    $sp_name = $translator->getPreferredTranslation($translator->getTag('spname'));
+    $sp_description = $translator->getPreferredTranslation($translator->getTag('spdescription'));
+
     // Fill out array for the template
-    $sp_list[$sp_entityid] = array(
+    $sp_list[$sp_entityid] = [
         'spentityid'       => $sp_entityid,
         'name'             => $sp_name,
         'description'      => $sp_description,
@@ -266,7 +319,7 @@ foreach ($all_sp_metadata as $sp_entityid => $sp_values) {
         'consentValue'     => $sp_entityid,
         'attributes_by_sp' => $attributes_new,
         'serviceurl'       => $sp_service_url,
-    );
+    ];
 }
 
 $template->data['header'] = 'Consent Administration';
diff --git a/modules/consentAdmin/www/includes/consentSimpleAjax.js b/modules/consentAdmin/www/includes/consentSimpleAjax.js
deleted file mode 100644
index 7ea896c630fa05a2f269330d63f7d70a4837232f..0000000000000000000000000000000000000000
--- a/modules/consentAdmin/www/includes/consentSimpleAjax.js
+++ /dev/null
@@ -1,70 +0,0 @@
-var xmlHttp;
-
-function checkConsent(consentValue, show_spid, checkAction)
-{ 
-	xmlHttp=GetXmlHttpObject()
-	if (xmlHttp==null) {
- 		alert ("Browser does not support HTTP Request")
- 		
- 		return
-	}
-	
-	var url="consentAdmin.php"
-	url=url+"?cv="+consentValue
-	url=url+"&action="+checkAction
-	url=url+"&sid="+Math.random()
-	xmlHttp.onreadystatechange=function() { 
-	if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
-	{ 
-		setConsentText(xmlHttp.responseText, show_spid);
-	} 
-}
-
-	xmlHttp.open("GET",url,true)
-	xmlHttp.send(null)
-}
-
-// This function will be automaticly called when the Ajax call is done returning data
-function stateChanged() { 
-	if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
-	{ 
-		//Alert("Status of consent:"  + xmlHttp.responseText );
-	} 
-}
-
-// This function creates an XMLHttpRequest
-function GetXmlHttpObject() {
-	var xmlHttp=null;
-	try
- 	{
-		// Firefox, Opera 8.0+, Safari
-		xmlHttp=new XMLHttpRequest();
-	}
-	catch (e)
-	{
-		//Internet Explorer
-		try
-		{
-			xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
-		}
-		catch (e)
-		{
-			xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
-		}
-	}
-	
-	return xmlHttp;
-}
-
-function toggleShowAttributes(show_spid) {
-	var disp = document.getElementById('attributes_' + show_spid);
-	//var showhide = document.getElementById('showhide_' + show_spid);
-	var showing = document.getElementById('showing_' + show_spid);
-	var hiding = document.getElementById('hiding_' + show_spid);
-	
-	disp.style.display = (disp.style.display == 'none' ? 'block' : 'none');
-	//showhide.innerHTML = (disp.style.display == 'none' ? 'Show' : 'Hide')
-	showing.style.display = (disp.style.display == 'none' ? 'inline' : 'none');
-	hiding.style.display = (disp.style.display == 'none' ? 'none' : 'inline');
-	//alert('hiding display'+hiding.display);
-}
diff --git a/modules/core/dictionaries/cardinality.definition.json b/modules/core/dictionaries/cardinality.definition.json
new file mode 100644
index 0000000000000000000000000000000000000000..b9059cb93a389ad4422be193ae8b17371ed426cf
--- /dev/null
+++ b/modules/core/dictionaries/cardinality.definition.json
@@ -0,0 +1,14 @@
+{
+    "cardinality_header": {
+        "en": "Incorrect Attributes"
+    },
+    "cardinality_text": {
+        "en": "One or more of the attributes supplied by your identity provider did not contain the expected number of values."
+    },
+    "problematic_attributes": {
+        "en": "The problematic attribute(s) are:"
+    },
+    "got_want": {
+        "en": "got %GOT% values, want %WANT%"
+    }
+}
diff --git a/modules/core/dictionaries/cardinality.translation.json b/modules/core/dictionaries/cardinality.translation.json
new file mode 100644
index 0000000000000000000000000000000000000000..9f479dc0fb9c19f913e12cf6f2177b447214ad4b
--- /dev/null
+++ b/modules/core/dictionaries/cardinality.translation.json
@@ -0,0 +1,27 @@
+{
+  "cardinality_header": {
+    "af": "Verkeerde Eienskappe",
+    "nl": "Niet de juiste attributen",
+    "es": "Atributos inválidos",
+    "no": "Ugyldige atributter"
+
+  },
+  "cardinality_text": {
+    "af": "Een of meer van die eienskappe wat deur u identiteits-verskaffer voorsien was, bevat nie die verwagte aantal waardes nie.",
+    "nl": "Één of meer door de Identity Provider geleverde attributen bevat niet het vereiste aantal attributen.",
+    "es": "Uno o más atributos proporcionados por su proveedor de identidad no contiene la cantidad de valores esperada.",
+    "no": "Én eller flere atributter levert av din identitetsleverandør har ikke så mange verdier som forventes."
+  },
+  "problematic_attributes": {
+    "af": "Die problematiese eienskap(pe) is:",
+    "nl": "De onjuiste attributen zijn:",
+    "es": "Los atributos problemáticos son:",
+    "no": "De ugyldige atributter er:"
+  },
+  "got_want": {
+    "af": "%GOT% waarde ontvang, %WANT% nodig",
+    "nl": "%GOT% ontvangen waarden, %WANT% vereist",
+    "es": "contiene %GOT% valores, se esperaban %WANT%",
+    "no": "har %GOT% verdier, forventer %WANT%"
+  }
+}
diff --git a/modules/core/dictionaries/frontpage.definition.json b/modules/core/dictionaries/frontpage.definition.json
index ee509f4b53fe35c94d5050a3ba4745eadd7c1982..bb5b229a8b7548462dcc06fb8cf08a0013b01715 100644
--- a/modules/core/dictionaries/frontpage.definition.json
+++ b/modules/core/dictionaries/frontpage.definition.json
@@ -17,12 +17,6 @@
 	"checkphp": {
 		"en": "Checking your PHP installation"
 	},
-	"about_header": {
-		"en": "About SimpleSAMLphp"
-	},
-	"about_text": {
-		"en": "This SimpleSAMLphp thing is pretty cool, where can I read more about it? You can find more information about it at the <a href=\"https:\/\/simplesamlphp.org\/\">SimpleSAMLphp web page <\/a> over at <a href=\"http:\/\/uninett.no\">UNINETT<\/a>."
-	},
 	"required": {
 		"en": "Required"
 	},
@@ -41,6 +35,9 @@
 	"warnings": {
 		"en": "Warnings"
 	},
+	"warnings_curlmissing": {
+		"en": "PHP cURL extension missing. Cannot check for SimpleSAMLphp updates."
+	},
 	"warnings_https": {
 		"en": "<strong>You are not using HTTPS<\/strong> - encrypted communication with the user. HTTP works fine for test purposes, but in a production environment, you should use HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Read more about SimpleSAMLphp maintenance<\/a> ]"
 	},
@@ -134,6 +131,9 @@
 	"loggedin_as_admin": {
 		"en": "You are logged in as administrator"
 	},
+	"logout": {
+		"en": "Logout"
+	},
 	"auth": {
 		"en": "Authentication"
 	},
diff --git a/modules/core/dictionaries/frontpage.translation.json b/modules/core/dictionaries/frontpage.translation.json
index 767bf766fc5b72fa190c5df32cdd845e2acf7f47..0cb5eed172acb3f95e6c212331a4e31ddc3025c4 100644
--- a/modules/core/dictionaries/frontpage.translation.json
+++ b/modules/core/dictionaries/frontpage.translation.json
@@ -174,76 +174,6 @@
 		"ro": "Verificarea instal\u0103rii PHP",
 		"el": "\u0388\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 \u03b5\u03b3\u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2 PHP"
 	},
-	"about_header": {
-		"no": "Om SimpleSAMLphp",
-		"nn": "Om SimpleSAMLphp",
-		"sv": "Om SimpleSAMLphp",
-		"es": "Sobre SimpleSAMLphp",
-		"fr": "\u00c0 propos de SimpleSAMLphp",
-		"de": "\u00dcber SimpleSAMLphp",
-		"nl": "Over SimpleSAMLphp",
-		"lb": "Iwwert SimpleSAMLphp",
-		"sl": "O SimpleSAMLphp",
-		"da": "Om SimpleSAMLphp",
-		"hr": "O programskom alatu SimpleSAMLphp",
-		"hu": "A SimpleSAMLphp-r\u00f3l b\u0151vebben",
-		"fi": "SimpleSAMLphp:st\u00e4",
-		"pt-br": "Sobre o SimpleSAMLphp",
-		"pt": "Sobre o SimpleSAMLphp",
-		"pl": "O SimpleSAMLphp",
-		"cs": "O aplikaci SimpleSAMLphp",
-		"eu": "SimpleSAMLphp-ari buruz",
-		"tr": "SimpleSAMLphp hakk\u0131nda",
-		"it": "A proposito di SimpleSAMLphp",
-		"lt": "Apie SimpleSAMLphp",
-		"ja": "SimpleSAMLphp \u306b\u3064\u3044\u3066",
-		"zh-tw": "\u6709\u95dc SimpleSAMLphp",
-		"ru": "\u041e SimpleSAMLphp",
-		"et": "Teave SimpleSAMLphp kohta",
-		"he": "\u05d0\u05d5\u05d3\u05d5\u05ea SimpleSAMLphp",
-		"zh": "\u5173\u4e8eSimpleSAMLphp",
-		"ar": "\u0639\u0646 SimpleSAMLphp",
-		"id": "Tentang SimpleSAMLphp",
-		"lv": "Par SimpleSAMLphp",
-		"sr": "O SimpleSAMLphp-u",
-		"ro": "Despre SimpleSAMLphp",
-		"el": "\u03a3\u03c7\u03b5\u03c4\u03b9\u03ba\u03ac \u03bc\u03b5 \u03c4\u03bf SimpleSAMLphp"
-	},
-	"about_text": {
-		"no": "Yey! SimpleSAMLphp virker jammen kult, hvor kan jeg finne ut mer om det? Du kan lese mer om SimpleSAMLphp p\u00e5 <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp sin hjemmeside<\/a>.",
-		"nn": "Yey! SimpleSAMLphp er jammen kult, kvar finn eg ut meir? Du kan lesa meir om SimpleSAMLphp p\u00e5 <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">heimesida til SimpleSAMLphp<\/a>.",
-		"sv": "SimpleSAMLphp \u00e4r cool, var kan jag l\u00e4sa mer om det? Du kan hitta mer information om <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp p\u00e5 Feide RnD blogg<\/a> hos <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"es": "&iexcl;Eh! Esto de SimpleSAMLphp es interesante, &iquest;d&oacute;nde puedo averiguar m&aacute;s? Puedes encontrar m&aacute;s informaci&oacute;n en la <a href=\"https:\/\/simplesamlphp.org\/\">p&aacute;gina web de SimpleSAMLphp<\/a>, en <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"fr": "Ce logiciel SimpleSAMLphp est plut\u00f4t sympa, o\u00f9 puis-je en lire plus \u00e0 son sujet? Vous trouverez plus d'informations sur <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp sur le blog de la R&amp;D de Feide<\/a> sur <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"de": "Hey, dieses SimpleSAMLphp ist eine ziemlich coole Sache, wo kann ich mehr dar\u00fcber lesen? Sie finden mehr Informationen \u00fcber <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp auf dem Feide RnD blog<\/a> auf <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"nl": "H\u00e9, dat SimpleSAMLphp dingetje is vet cool, waar kan ik er meer over vinden? Je kan meer informatie over <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp<\/a> vinden op de Feide RnD blog van <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"lb": "Desen SimpleSAMLphp system as nach ew\u00ebll d\u00ebcken Gas, wou kann ech m\u00e9i doriwwer gewuer gin? Mei Informatiounen iwer <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp at the Feide RnD blog<\/a> op <a href=\"http:\/\/uninett.no\">UNINETT<\/a>",
-		"sl": "Da! SimpleSAMLphp je zares kul! Kje si lahko preberem kaj ve\u010d o tem? Dodatne informacije se nahajajo na <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp Feide RnD blogu<\/a>.",
-		"da": "Yes, det er cool! Hvor kan jeg l\u00e6se mere om det? G\u00e5 til <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp's hjemmeside<\/a>",
-		"hr": "Vi\u0161e informacija o programskom alatu SimpleSAMLphp mo\u017eete prona\u0107i na <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp stranici Feide RnD bloga<\/a>.",
-		"hu": "Ez a SimpleSAMLphp-dolog nagyon hasznos, hol olvashatn\u00e9k t\u00f6bbet r\u00f3la? Tov\u00e1bbi inform\u00e1ci\u00f3kat a <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\"> Feide RnD SimpleSAMLphp-r\u00f3l sz\u00f3l\u00f3 blogj\u00e1ban <\/a> tal\u00e1lhat a <a href=\"http:\/\/uninett.no\">UNINETT-en<\/a>.",
-		"fi": "T\u00e4\u00e4 simpleSAMPphp on aiga magee, mutta mist\u00e4 voin lukea enemm\u00e4n asiasta? L\u00f6yd\u00e4t enemm\u00e4n tietoa <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp blogista Feide RnD:ll\u00e4<\/a> <a href=\"http:\/\/uninett.no\">UNINETT<\/a>issa.",
-		"pt-br": "Este SimpleSAMLphp \u00e9 uma coisa muito legal, onde posso ler mais sobre isso? Voc\u00ea pode encontrar mais informa\u00e7\u00f5es sobre o <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp no blog de Feide RnD<\/a> durante a <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"pt": "Pode encontrar mais informa\u00e7\u00e3o sobre o <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp no blog da Feide RnD<\/a> em <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"pl": "Ten SimpleSAMLphp jest niez\u0142y, gdzie mog\u0119 poczyta\u0107 o tym? Mo\u017cesz znale\u017a\u0107 wi\u0119cej informacji o <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp na blogu Feide RnD<\/a> oraz na stronie <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"cs": "Tato vlastnost SimpleSAMLphp je velmi p\u011bkn\u00e1, kde se o n\u00ed mohu do\u010d\u00edst v\u00edce? Dal\u0161\u00ed informace o SimpleSAMLphp z\u00edsk\u00e1te <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">na blogu Feide RnD<\/a> na <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"tr": "Bu SimpleSAMLphp olduk\u00e7a iyiymi\u015f, daha fazla bilgiyi nereden okuyabilirim? <a href=\"http:\/\/uninett.no\">UNINETT<\/a> \u00fczerinde <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">Feide RnD blog'unda SimpleSAMLphp <\/a> hakk\u0131nda daha fazlas\u0131n\u0131 bulabilirsiniz.",
-		"it": "Questo SimpleSAMLphp &egrave; davvero un bel prodotto, dove trovo ulteriori informazioni a riguardo? Puoi trovare maggiori informazioni su <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp nel Blog di Feide RnD<\/a> oltre che <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"lt": "\u0160is SimpleSAMLphp dalykas yra gana puikus, kur gal\u0117\u010diau daugiau apie j\u012f paskaityti? Daugiau informacijos apie <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp galite rasti Feide RnD blog'e<\/a> bei <a href=\"http:\/\/uninett.no\">UNINETT<\/a> svetain\u0117je.",
-		"ja": "\u3053\u306e SimpleSAMLphp \u306f\u7d20\u6674\u3089\u3057\u3044\u3082\u306e\u3067\u3059\u3002\u3053\u308c\u4ee5\u4e0a\u306e\u8aac\u660e\u304c\u5728\u308a\u307e\u3059\u304b\uff1f\u3053\u3061\u3089\u306e\u30ea\u30f3\u30af\u3067\u66f4\u306a\u308b\u60c5\u5831\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u51fa\u6765\u307e\u3059 <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp at the Feide RnD blog<\/a>",
-		"zh-tw": "\u89ba\u5f97 SimpleSAMLphp \u9084\u883b\u9177\u7684\u561b\uff0c\u5728\u54ea\u53ef\u4ee5\u627e\u5230\u66f4\u591a\u76f8\u95dc\u8cc7\u8a0a\u5462\uff1f\u4f60\u53ef\u4ee5\u5728\u4e0b\u5217\u7db2\u5740\u627e\u5230\u66f4\u591a\u76f8\u95dc\u8cc7\u8a0a\uff0c\u65bc <a href=\"http:\/\/uninett.no\">UNINETT<\/a> \u7684 <a href=\"https:\/\/simplesamlphp.org\/\">SimpleSAMLphp<\/a>",
-		"ru": "SimpleSAMLphp - \u0432\u0435\u0449\u044c \u043a\u043b\u0430\u0441\u0441\u043d\u0430\u044f, \u0433\u0434\u0435 \u044f \u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0431 \u044d\u0442\u043e\u043c? \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp \u0432 \u0431\u043b\u043e\u0433\u0435 Feide RnD<\/a> \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430 <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"et": "See SimpleSAMLphp on p\u00e4ris \u00e4ge! Kust ma saaks selle kohta t\u00e4psemalt lugeda? Rohkem infot leiad <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp blogist<\/a>, mis asub <a href=\"http:\/\/uninett.no\">UNINETT<\/a>-is.",
-		"he": "\u05d4-SimpleSAMLphp \u05d4\u05d6\u05d4 \u05d4\u05d5\u05d0 \u05de\u05d4 \u05d6\u05d4 \u05de\u05d2\u05e0\u05d9\u05d1, \u05d0\u05d9\u05dd\u05d4 \u05d0\u05e0\u05d9 \u05d9\u05db\u05d5\u05dc \u05dc\u05e7\u05e8\u05d5\u05d0 \u05d9\u05d5\u05ea\u05e8 \u05e2\u05dc\u05d9\u05d5?\u05d0\u05ea\u05d4 \u05d9\u05db\u05d5\u05dc \u05dc\u05de\u05e6\u05d5\u05d0 \u05de\u05d9\u05d3\u05e2 \u05e0\u05d5\u05e1\u05e3 \u05d1- <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\"> SimpleSAMLphp \u05d1 Feide \u05d1\u05d1\u05dc\u05d5\u05d2 \u05d4\u05e4\u05d9\u05ea\u05d5\u05d7 \u05e9\u05dc \u05e9\u05e0\u05de\u05e6\u05d0 \u05d1- <a href=\"http:\/\/uninett.no\">UNINETT<\/a>. ",
-		"zh": "\u662f\u4e0d\u662f\u89c9\u5f97SimpleSAMLphp\u5f88\u9177\uff1f\u6211\u5728\u54ea\u91cc\u80fd\u627e\u5230\u66f4\u591a\u8d44\u6599\u5462\uff1f\u4f60\u53ef\u4ee5\u5728\u4e0b\u5217\u7f51\u5740\u627e\u5230\u66f4\u591a\u4fe1\u606f\uff1a <a href=\"http:\/\/uninett.no\">UNINETT<\/a> \u7684 <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp at the Feide RnD \u5f00\u53d1\u8005\u535a\u5ba2<\/a>",
-		"ar": "\u0644\u0644\u0645\u0632\u064a\u062f \u0639\u0646 SimpleSAMLphp \u0627\u0630\u0647\u0628 \u0627\u0644\u064a<a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp \u0628\u0645\u062f\u0648\u0646\u0629 Feide RnD <\/a> over at <a href=\"http:\/\/uninett.no\">UNINETT<\/a>",
-		"lv": "SimpleSAMLphp ir baigi for\u0161s, kur par to var palas\u012bt vair\u0101k? Vair\u0101k inform\u0101cijas ir <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp Feide RnD blog\u0101<\/a> pie <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"id": "SimpleSAMLphp sangat menarik, dimana Saya bisa membaca lebih jauh tentang hal ini ? Anda dapat mencari informasi lebih jauh tentang <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp pada blog Feide RnD<\/a> ke arah <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"sr": "SimpleSAMLphp je veoma kul, gde mogu da pro\u010ditam vi\u0161e o njemu? Vi\u0161e informacija o SimpleSAMLphp-u mo\u017eete prona\u0107i na <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp stranici Feide RnD bloga<\/a>.",
-		"ro": "Acest SimpleSAMLphp este interesant, unde pot g\u0103si mai multe informa\u021bii ? Pute\u021bi g\u0103si mai multe informa\u021bii despre <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\"> la blog-ul Feide despre SimpleSAMLphp<\/a> de la <a href=\"http:\/\/uninett.no\">UNINETT<\/a>.",
-		"eu": "SimpleSAMLphp-en kontu hau interesgarria da benetan, non bila nezake informazio gehiago honen inguruan? <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">SimpleSAMLphp Feideren I+G blogeko <a href=\"http:\/\/uninett.no\">UNINETT<\/a>n.",
-		"el": "\u03a4\u03bf SimpleSAMLphp \u03b5\u03af\u03bd\u03b1\u03b9 \u03c0\u03bf\u03bb\u03cd \u03b5\u03bd\u03b4\u03b9\u03b1\u03c6\u03ad\u03c1\u03bf\u03bd, \u03c0\u03bf\u03cd \u03bc\u03c0\u03bf\u03c1\u03ce \u03bd\u03b1 \u03bc\u03ac\u03b8\u03c9 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1 \u03b3\u03b9\u0027 \u03b1\u03c5\u03c4\u03cc\u003b \u039c\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03bd\u03b1 \u03b2\u03c1\u03b5\u03af\u03c4\u03b5 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b5\u03c2 \u03c0\u03bb\u03b7\u03c1\u03bf\u03c6\u03bf\u03c1\u03af\u03b5\u03c2 \u03c3\u03c4\u03bf\u03bd <a href=\"http:\/\/rnd.feide.no\/simplesamlphp\">\u03b9\u03c3\u03c4\u03cc\u03c4\u03bf\u03c0\u03bf \u03c4\u03bf\u03c5 SimpleSAMLphp<\/a> \u03c0\u03bf\u03c5 \u03c6\u03b9\u03bb\u03bf\u03be\u03b5\u03bd\u03b5\u03af\u03c4\u03b1\u03b9 \u03b1\u03c0\u03cc \u03c4\u03bf <a href=\"http:\/\/uninett.no\">UNINETT<\/a>."
-	},
 	"required": {
 		"no": "P\u00e5krevd",
 		"nn": "Naudsynt",
@@ -455,39 +385,39 @@
 		"el": "\u03a0\u03c1\u03bf\u03b5\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03b9\u03c2"
 	},
 	"warnings_https": {
-		"no": "<strong>Du bruker ikke HTTPS<\/strong> - kryptert kommunikasjon med brukeren. HTTP fungerer utmerket til testform\u00e5l, men  i et produksjonsmilj\u00f8 anbefales sterkt \u00e5 skru p\u00e5 sikker kommunikasjon med HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Les mer i dokumentet: SimpleSAMLphp maintenance<\/a> ]",
-		"nn": "<strong>Du bruker ikkje HTTPS<\/strong> - kryptert kommunikasjon med brukaren. Du kan bruka SimpleSAMLphp uten HTTPS til testform\u00e5l, men dersom du skal bruka SimpleSAMLphp i eit produksjonsmilj\u00f8, vil vi sterkt tilr\u00e5 \u00e5 skru p\u00e5 sikker kommunikasjon med HTTPS. [ Les meir i dokumentet: <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">SimpleSAMLphp maintenance<\/a> ]",
-		"sv": "<strong>Du anv\u00e4nder inte HTTPS<\/strong> - krypterad kommunikation med anv\u00e4ndaren. HTTP fungerar bra under test men i produktion ska du anv\u00e4nda HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">L\u00e4s mer i dokumentet SimpleSAMLphp maintenance<\/a> ]",
+		"no": "<strong>Du bruker ikke HTTPS<\/strong> - kryptert kommunikasjon med brukeren. HTTP fungerer utmerket til testform\u00e5l, men  i et produksjonsmilj\u00f8 anbefales sterkt \u00e5 skru p\u00e5 sikker kommunikasjon med HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Les mer i dokumentet: SimpleSAMLphp maintenance<\/a> ]",
+		"nn": "<strong>Du bruker ikkje HTTPS<\/strong> - kryptert kommunikasjon med brukaren. Du kan bruka SimpleSAMLphp uten HTTPS til testform\u00e5l, men dersom du skal bruka SimpleSAMLphp i eit produksjonsmilj\u00f8, vil vi sterkt tilr\u00e5 \u00e5 skru p\u00e5 sikker kommunikasjon med HTTPS. [ Les meir i dokumentet: <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">SimpleSAMLphp maintenance<\/a> ]",
+		"sv": "<strong>Du anv\u00e4nder inte HTTPS<\/strong> - krypterad kommunikation med anv\u00e4ndaren. HTTP fungerar bra under test men i produktion ska du anv\u00e4nda HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">L\u00e4s mer i dokumentet SimpleSAMLphp maintenance<\/a> ]",
 		"es": "<strong>No est\u00e1 usando HTTPS<\/strong> - comunicaciones cifradas con el usuario. HTTP funciona bien en entornos de evaluaci\u00f3n, pero si va a emplearlo en producci\u00f3n, deber\u00eda emplear HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Lea m\u00e1s acerca del mantenimiento de SimpleSAMLphp <\/a> ]",
-		"fr": "<strong>Vous n'utilisez pas HTTPS<\/strong> - communications chiffr\u00e9es avec l'utilisateur.  Utiliser SimpleSAMLphp marchera parfaitement avec HTTP pour des tests, mais si vous voulez l'utiliser dans un environnement de production, vous devriez utiliser HTTPS. [  <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">En lire plus sur la maintenance de SimpleSAMLphp<\/a> ]",
-		"de": "<strong>Sie benutzen keine HTTPS<\/strong> - verschl\u00fcsselte Kommunikation mit dem Nutzer. SimpleSAMLphp funktioniert zum Testen auch mit HTTP problemlos, aber in einer Produktionsumgebung sollten Sie HTTPS benutzen. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Lesen sie mehr \u00fcber die Verwaltung von SimpleSAMLphp<\/a> ]",
-		"nl": "<strong>Je gebruikt geen HTTPS<\/strong> - versleutelde communicatie met de gebruiker. SimpleSAMLphp werkt prima op HTTP voor testdoeleinden, maar als je SimpleSAMLphp in een productieomgeving gaat gebruiken, zou je dat moeten doen over HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">lees meer over SimpleSAMLphp-onderhoud<\/a> ]",
-		"lb": "<strong>Der benotzt ken HTTPS<\/strong> - verschl\u00ebsselt Kommunikatioun mat dem Benotzer. SimpleSAMLphp funktion\u00e9iert einwandfr\u00e4i mat HTTP fir Testzw\u00e9ecker mais an engem produktiven Emfeld sollt et besser mat HTTPS lafen. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Liest m\u00e9i iwert Maintenance vun SimpleSAMLphp<\/a> ]",
-		"sl": "<strong>Ne uporabljate HTTPS<\/strong>-\u0161ifrirane komunikacije. SimpleSAMLphp deluje brez te\u017eav na HTTP, vendar le za testne namene, za uporabo SimpleSAMLphp v produkcijskem okolju uporabite HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Preberite ve\u010d o SimpleSAMLphp vzdr\u017eevanju<\/a> ]",
-		"da": "<strong>Du benytter ikke HTTPS<\/strong>-krypteret kommunikation med brugeren. SimpleSAMLphp vil fungere uden problemer med HTTP alene, men hvis du anvender systemet i produktionssystemer, anbefales det st\u00e6rkt at benytte sikker kommunikation i form af HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">l\u00e6s mere i dokumentet: SimpleSAMLphp maintenance<\/a> ] ",
-		"hr": "<strong>Ne koristite HTTPS<\/strong> - kriptiranu komunikaciju s korisnikom. HTTP se mo\u017ee koristiti za potrebe testiranja, ali u produkcijskom okru\u017eenju trebali biste koristiti HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Pro\u010ditajte vi\u0161e o SimpleSAMLphp postavkama<\/a> ]",
-		"hu": "<strong>Nem HTTPS protokollt haszn\u00e1l<\/strong> - nem titkos\u00edtott a kommunik\u00e1ci\u00f3! HTTP j\u00f3 megold\u00e1s lehet teszt rendszerek eset\u00e9ben, de az \u00e9les rendszerben lehet\u0151s\u00e9g szerint haszn\u00e1ljon HTTPS-t! [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">T\u00f6bbet olvashat a SimpleSAMLphp be\u00e1ll\u00edt\u00e1s\u00e1r\u00f3l<\/a> ]",
-		"fi": "<strong>Et k\u00e4yt\u00e4 HTTPS<\/strong> - vahvaa yhteyst\u00e4 k\u00e4ytt\u00e4j\u00e4\u00e4n. HTTP-protokolla on sopiva testeihin, mutta tuotantoj\u00e4rjestelm\u00e4ss\u00e4 sinun tulee k\u00e4ytt\u00e4\u00e4 HTTPS:\u00e4\u00e4. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Lue SimpleSAMLphp yll\u00e4pidosta (eng)<\/a> ]",
-		"pt-br": "<strong>Voc\u00ea n\u00e3o est\u00e1 utilizando HTTPS<\/strong> - comunica\u00e7\u00e3o encriptada com o usu\u00e1rio. HTTP funciona bem para testes, mas voc\u00ea deve utilizar HTTPS para produ\u00e7\u00e3o. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Leia mais sobre manuten\u00e7\u00e3o do SimpleSAMLphp<\/a> ]",
-		"pt": "<strong>N\u00e3o est\u00e1 a ser usado HTTPS<\/strong> - comunica\u00e7\u00e3o cifrada com o utilizador. Para ambientes de teste, liga\u00e7\u00f5es HTTP s\u00e3o suficientes, mas num ambiente de produ\u00e7\u00e3o deve ser usado HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Ler mais sobre manuten\u00e7\u00e3o do SimpleSAMLphp<\/a> ]",
-		"pl": "<strong>Nie u\u017cywasz HTTPS<\/strong> - szyfrowana komunikacja z u\u017cytkownikiem. HTTP jest OK dla test\u00f3w, ale na produkcji powiniene\u015b u\u017cywa\u0107 tylko HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Przeczytaj wi\u0119cej o zarz\u0105dzaniu SimpleSAMLphp<\/a> ]",
-		"cs": "<strong>Nepou\u017e\u00edv\u00e1te HTTPS<\/strong> - \u0161ivrovanou komunikaci s u\u017eivatelem. HTTP je vhodn\u00e9 jen k testovac\u00edm \u00fa\u010del\u016fm, pro produk\u010dn\u00ed \u00fa\u010dely pou\u017eijte HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">\u010ctete v\u00edce o \u00fadr\u017eb\u011b SimpleSAMLphp<\/a> ]",
-		"tr": "Kullan\u0131c\u0131yla \u015fifreli ileti\u015fim -<strong>HTTPS kullanm\u0131yorsunuz<\/strong>. HTTP test ama\u00e7l\u0131 olarak kullan\u0131labilir, ancak \u00fcretim ortam\u0131nda, HTTPS kullanmal\u0131s\u0131n\u0131z. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">SimpleSAMLphp bak\u0131m\u0131 hakk\u0131nda daha fazlas\u0131n\u0131 okuyun<\/a> ]",
-		"it": "<strong>Non stai usando HTTPS<\/strong> - comunicazione cifrata con l'utente. HTTP pu&ograve; funzionare per i test, ma in un ambiente di produzione si dovrebbe usare HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Maggiori informazioni sulla manutenzione di SimpleSAMLphp<\/a> ]",
-		"lt": "<strong>J\u016bs nenaudojate HTTPS<\/strong> - \u0161ifruotos komunikacijos su vartotoju. HTTP puikiai tinka testavimo reikm\u0117ms, ta\u010diau realioje aplinkoje tur\u0117tum\u0117te naudoti HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Skaityti daugiau apie SimpleSAMLphp prie\u017ei\u016br\u0105<\/a> ]",
-		"ja": "<strong>\u3042\u306a\u305f\u306fHTTPS(\u6697\u53f7\u5316\u901a\u4fe1)\u3092\u884c\u3063\u3066\u3044\u307e\u305b\u3093\u3002<\/strong>HTTP\u306f\u30c6\u30b9\u30c8\u74b0\u5883\u3067\u3042\u308c\u3070\u6b63\u5e38\u306b\u52d5\u4f5c\u3057\u307e\u3059\u3001\u3057\u304b\u3057\u88fd\u54c1\u74b0\u5883\u3067\u306fHTTPS\u3092\u4f7f\u7528\u3059\u308b\u3079\u304d\u3067\u3059\u3002[ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">\u8a73\u3057\u304f\u306f SimpleSAMLphp \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u60c5\u5831\u3092\u8aad\u3093\u3067\u304f\u3060\u3055\u3044\u3002<\/a> ]",
+		"fr": "<strong>Vous n'utilisez pas HTTPS<\/strong> - communications chiffr\u00e9es avec l'utilisateur.  Utiliser SimpleSAMLphp marchera parfaitement avec HTTP pour des tests, mais si vous voulez l'utiliser dans un environnement de production, vous devriez utiliser HTTPS. [  <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">En lire plus sur la maintenance de SimpleSAMLphp<\/a> ]",
+		"de": "<strong>Sie benutzen keine HTTPS<\/strong> - verschl\u00fcsselte Kommunikation mit dem Nutzer. SimpleSAMLphp funktioniert zum Testen auch mit HTTP problemlos, aber in einer Produktionsumgebung sollten Sie HTTPS benutzen. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Lesen sie mehr \u00fcber die Verwaltung von SimpleSAMLphp<\/a> ]",
+		"nl": "<strong>Je gebruikt geen HTTPS<\/strong> - versleutelde communicatie met de gebruiker. SimpleSAMLphp werkt prima op HTTP voor testdoeleinden, maar als je SimpleSAMLphp in een productieomgeving gaat gebruiken, zou je dat moeten doen over HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">lees meer over SimpleSAMLphp-onderhoud<\/a> ]",
+		"lb": "<strong>Der benotzt ken HTTPS<\/strong> - verschl\u00ebsselt Kommunikatioun mat dem Benotzer. SimpleSAMLphp funktion\u00e9iert einwandfr\u00e4i mat HTTP fir Testzw\u00e9ecker mais an engem produktiven Emfeld sollt et besser mat HTTPS lafen. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Liest m\u00e9i iwert Maintenance vun SimpleSAMLphp<\/a> ]",
+		"sl": "<strong>Ne uporabljate HTTPS<\/strong>-\u0161ifrirane komunikacije. SimpleSAMLphp deluje brez te\u017eav na HTTP, vendar le za testne namene, za uporabo SimpleSAMLphp v produkcijskem okolju uporabite HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Preberite ve\u010d o SimpleSAMLphp vzdr\u017eevanju<\/a> ]",
+		"da": "<strong>Du benytter ikke HTTPS<\/strong>-krypteret kommunikation med brugeren. SimpleSAMLphp vil fungere uden problemer med HTTP alene, men hvis du anvender systemet i produktionssystemer, anbefales det st\u00e6rkt at benytte sikker kommunikation i form af HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">l\u00e6s mere i dokumentet: SimpleSAMLphp maintenance<\/a> ] ",
+		"hr": "<strong>Ne koristite HTTPS<\/strong> - kriptiranu komunikaciju s korisnikom. HTTP se mo\u017ee koristiti za potrebe testiranja, ali u produkcijskom okru\u017eenju trebali biste koristiti HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Pro\u010ditajte vi\u0161e o SimpleSAMLphp postavkama<\/a> ]",
+		"hu": "<strong>Nem HTTPS protokollt haszn\u00e1l<\/strong> - nem titkos\u00edtott a kommunik\u00e1ci\u00f3! HTTP j\u00f3 megold\u00e1s lehet teszt rendszerek eset\u00e9ben, de az \u00e9les rendszerben lehet\u0151s\u00e9g szerint haszn\u00e1ljon HTTPS-t! [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">T\u00f6bbet olvashat a SimpleSAMLphp be\u00e1ll\u00edt\u00e1s\u00e1r\u00f3l<\/a> ]",
+		"fi": "<strong>Et k\u00e4yt\u00e4 HTTPS<\/strong> - vahvaa yhteyst\u00e4 k\u00e4ytt\u00e4j\u00e4\u00e4n. HTTP-protokolla on sopiva testeihin, mutta tuotantoj\u00e4rjestelm\u00e4ss\u00e4 sinun tulee k\u00e4ytt\u00e4\u00e4 HTTPS:\u00e4\u00e4. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Lue SimpleSAMLphp yll\u00e4pidosta (eng)<\/a> ]",
+		"pt-br": "<strong>Voc\u00ea n\u00e3o est\u00e1 utilizando HTTPS<\/strong> - comunica\u00e7\u00e3o encriptada com o usu\u00e1rio. HTTP funciona bem para testes, mas voc\u00ea deve utilizar HTTPS para produ\u00e7\u00e3o. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Leia mais sobre manuten\u00e7\u00e3o do SimpleSAMLphp<\/a> ]",
+		"pt": "<strong>N\u00e3o est\u00e1 a ser usado HTTPS<\/strong> - comunica\u00e7\u00e3o cifrada com o utilizador. Para ambientes de teste, liga\u00e7\u00f5es HTTP s\u00e3o suficientes, mas num ambiente de produ\u00e7\u00e3o deve ser usado HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Ler mais sobre manuten\u00e7\u00e3o do SimpleSAMLphp<\/a> ]",
+		"pl": "<strong>Nie u\u017cywasz HTTPS<\/strong> - szyfrowana komunikacja z u\u017cytkownikiem. HTTP jest OK dla test\u00f3w, ale na produkcji powiniene\u015b u\u017cywa\u0107 tylko HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Przeczytaj wi\u0119cej o zarz\u0105dzaniu SimpleSAMLphp<\/a> ]",
+		"cs": "<strong>Nepou\u017e\u00edv\u00e1te HTTPS<\/strong> - \u0161ivrovanou komunikaci s u\u017eivatelem. HTTP je vhodn\u00e9 jen k testovac\u00edm \u00fa\u010del\u016fm, pro produk\u010dn\u00ed \u00fa\u010dely pou\u017eijte HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u010ctete v\u00edce o \u00fadr\u017eb\u011b SimpleSAMLphp<\/a> ]",
+		"tr": "Kullan\u0131c\u0131yla \u015fifreli ileti\u015fim -<strong>HTTPS kullanm\u0131yorsunuz<\/strong>. HTTP test ama\u00e7l\u0131 olarak kullan\u0131labilir, ancak \u00fcretim ortam\u0131nda, HTTPS kullanmal\u0131s\u0131n\u0131z. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">SimpleSAMLphp bak\u0131m\u0131 hakk\u0131nda daha fazlas\u0131n\u0131 okuyun<\/a> ]",
+		"it": "<strong>Non stai usando HTTPS<\/strong> - comunicazione cifrata con l'utente. HTTP pu&ograve; funzionare per i test, ma in un ambiente di produzione si dovrebbe usare HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Maggiori informazioni sulla manutenzione di SimpleSAMLphp<\/a> ]",
+		"lt": "<strong>J\u016bs nenaudojate HTTPS<\/strong> - \u0161ifruotos komunikacijos su vartotoju. HTTP puikiai tinka testavimo reikm\u0117ms, ta\u010diau realioje aplinkoje tur\u0117tum\u0117te naudoti HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Skaityti daugiau apie SimpleSAMLphp prie\u017ei\u016br\u0105<\/a> ]",
+		"ja": "<strong>\u3042\u306a\u305f\u306fHTTPS(\u6697\u53f7\u5316\u901a\u4fe1)\u3092\u884c\u3063\u3066\u3044\u307e\u305b\u3093\u3002<\/strong>HTTP\u306f\u30c6\u30b9\u30c8\u74b0\u5883\u3067\u3042\u308c\u3070\u6b63\u5e38\u306b\u52d5\u4f5c\u3057\u307e\u3059\u3001\u3057\u304b\u3057\u88fd\u54c1\u74b0\u5883\u3067\u306fHTTPS\u3092\u4f7f\u7528\u3059\u308b\u3079\u304d\u3067\u3059\u3002[ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u8a73\u3057\u304f\u306f SimpleSAMLphp \u30e1\u30f3\u30c6\u30ca\u30f3\u30b9\u60c5\u5831\u3092\u8aad\u3093\u3067\u304f\u3060\u3055\u3044\u3002<\/a> ]",
 		"zh-tw": "<strong>\u60a8\u672a\u4f7f\u7528 HTTPS <\/strong> \u5c0d\u50b3\u8f38\u904e\u7a0b\u9032\u884c\u52a0\u5bc6\u901a\u8a0a\u3002HTTP \u53ef\u4ee5\u6b63\u5e38\u7684\u904b\u4f5c\u65bc\u6e2c\u8a66\u74b0\u5883\u3002\u4f46\u5728\u6b63\u5f0f\u74b0\u5883\u88e1\uff0c\u60a8\u61c9\u8a72\u8981\u4f7f\u7528 HTTPS\u3002[ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u95b1\u8b80\u66f4\u591a\u6709\u95dc\u65bc SimpleSAMLphp \u7684\u7dad\u8b77\u65b9\u5f0f<\/a> ]",
-		"ru": "<strong>\u0412\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 HTTPS<\/strong> - \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. HTTP \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0446\u0435\u043b\u0435\u0439, \u043d\u043e \u0432 \u044d\u043a\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438 \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">\u0423\u0437\u043d\u0430\u0439\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0431 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438 SimpleSAMLphp<\/a> ]",
-		"et": "<strong>Sa ei kasuta andmete vahetamiseks HTTPS kr\u00fcpteeritud sidet<\/strong>. HTTP sobib testimiseks h\u00e4sti, kuid toodangus peaksid kindlasti HTTPS-i kasutama. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Loe t\u00e4psemalt SimpleSAMLphp hooldamisest<\/a> ]",
-		"he": "<strong>\u05d0\u05ea\u05d4 \u05dc\u05d0 \u05de\u05e9\u05ea\u05de\u05e9 \u05d1- HTTPS <\/strong> - \u05d4\u05ea\u05e7\u05e9\u05e8\u05d5\u05ea \u05de\u05d5\u05e6\u05e4\u05e0\u05ea \u05e2\u05dd \u05d4\u05de\u05e9\u05ea\u05de\u05e9. HTTP \u05e2\u05d5\u05d1\u05d3 \u05d1\u05e1\u05d3\u05e8 \u05dc\u05de\u05d8\u05e8\u05d5\u05ea \u05d1\u05d3\u05d9\u05e7\u05d4, \u05d0\u05d5\u05dc\u05dd \u05dc\u05de\u05e2\u05e8\u05db\u05d5\u05ea \u05d0\u05de\u05d9\u05ea\u05d9\u05d5\u05ea, \u05db\u05d3\u05d9 \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d4 HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\"> \u05e7\u05e8\u05d0 \u05e2\u05d5\u05d3 \u05e2\u05dc \u05ea\u05d7\u05d6\u05d5\u05e7 SimpleSAMLphp <\/a> ]",
-		"zh": "<strong>\u4f60\u6ca1\u6709\u4f7f\u7528HTTPS<\/strong> - \u548c\u7528\u6237\u52a0\u5bc6\u7684\u901a\u4fe1\u3002HTTP\u5728\u6d4b\u8bd5\u76ee\u7684\u4e0b\u5f88\u597d,\u4f46\u751f\u4ea7\u73af\u5883\u8bf7\u4f7f\u7528HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">\u83b7\u53d6\u66f4\u591aSimpleSAMLphp\u7ef4\u62a4\u7684\u4fe1\u606f<\/a> ]",
-		"ar": "<strong>\u0627\u0646\u062a \u0644\u0627 \u062a\u0633\u062a\u062e\u062f\u0645 HTTPS<\/strong> - \u0645\u062d\u0627\u062f\u062b\u0629 \u0645\u0634\u0641\u0631\u0629 \u0645\u0639 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645. HTTP \u062c\u064a\u062f \u0644\u0644\u0627\u062e\u062a\u0628\u0627\u0631\u0627\u062a \u0644\u0643\u0646 \u0641\u064a \u0628\u064a\u0626\u0629 \u0627\u0644\u0646\u0638\u0627\u0645 \u0627\u0644\u0645\u0628\u062f\u0626\u064a \u064a\u0646\u0628\u063a\u064a \u0627\u0633\u062a\u062e\u062f\u0627\u0645 HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/contents\/simplesamlphp-maintenance-and-configuration\">read more about SimpleSAMLphp maintenance<\/a>]",
-		"lv": "<strong>J\u016bs neizmantojat HTTPS<\/strong> - \u0161ifr\u0113tu komunik\u0101ciju ar lietot\u0101ju. HTTP ir labs testa nol\u016bkiem, bet ra\u017eo\u0161an\u0101 j\u0101izmanto HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Lasiet vair\u0101k par SimpleSAMLphp uztur\u0113\u0161anu<\/a> ]",
-		"id": "<strong>Anda tidak menggunakan HTTPS<\/strong> - komunikasi yang dienkripsi dengan user. HTTP bekerja baik-baik saja untuk tujuan pengetesan , tapi dalam lingkungan produksi, Anda sebaiknya menggunakan HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Baca lebih lanjut tentang proses pemeliraan SimpleSAMLphp.<\/a> ]",
-		"sr": "<strong>Ne koristite HTTPS<\/strong> - kriptovanu komunikaciju s korisnikom. HTTP se mo\u017ee koristiti za potrebe testiranja, ali u produkcionom okru\u017eenju trebali biste koristiti HTTPS. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Pro\u010ditajte vi\u0161e o SimpleSAMLphp pode\u0161avanjima<\/a> ]",
-		"ro": "<strong>Aten\u021bie, nu utiliza\u021bi HTTPS<\/strong> - comunicare criptat\u0103 cu utilizatorul. HTTP func\u021bioneaza bine pentru teste, dar \u00een produc\u021bie trebuie folosit HTTPS. [<a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Citi\u021bi mai multe despre \u00eentre\u021binerea SimpleSAMLphp<\/a> ]",
-		"eu": "<strong>Ez zara erabiltzen ari HTTPSak<\/strong> - erabiltzailearekin zifratutako komunikazioak. HTTP zuzen ibiltzen da ebaluaketa ingurunetan, baina ustiapenean erabili behar baduzu, HTTPS erabili beharko zenuke. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei buruz <\/a> ]",
-		"el": "\u0394\u03b5\u03bd \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b5\u03af\u03c4\u03b5 <strong>HTTPS<\/strong> \u03b3\u03b9\u03b1 \u03ba\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03af\u03b1 \u03bc\u03b5 \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7. \u03a4\u03bf HTTP \u03b5\u03c0\u03b1\u03c1\u03ba\u03b5\u03af \u03b3\u03b9\u03b1 \u03b4\u03bf\u03ba\u03b9\u03bc\u03b1\u03c3\u03c4\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c3\u03ba\u03bf\u03c0\u03bf\u03cd\u03c2, \u03c9\u03c3\u03c4\u03cc\u03c3\u03bf \u03c3\u03b5 \u03c0\u03b5\u03c1\u03b9\u03b2\u03ac\u03bb\u03bb\u03bf\u03bd \u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03b8\u03b1 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u0048\u0054\u0054\u0050\u0053. [ <a href=\"http:\/\/rnd.feide.no\/content\/simplesamlphp-maintenance-and-configuration\">\u0394\u03b9\u03b1\u03b2\u03ac\u03c3\u03c4\u03b5 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1...<\/a> ]"
+		"ru": "<strong>\u0412\u044b \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0435 HTTPS<\/strong> - \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c. HTTP \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0445\u043e\u0440\u043e\u0448\u043e \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0445 \u0446\u0435\u043b\u0435\u0439, \u043d\u043e \u0432 \u044d\u043a\u043f\u043b\u0443\u0430\u0442\u0430\u0446\u0438\u0438 \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u0423\u0437\u043d\u0430\u0439\u0442\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 \u043e\u0431 \u043e\u0431\u0441\u043b\u0443\u0436\u0438\u0432\u0430\u043d\u0438\u0438 SimpleSAMLphp<\/a> ]",
+		"et": "<strong>Sa ei kasuta andmete vahetamiseks HTTPS kr\u00fcpteeritud sidet<\/strong>. HTTP sobib testimiseks h\u00e4sti, kuid toodangus peaksid kindlasti HTTPS-i kasutama. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Loe t\u00e4psemalt SimpleSAMLphp hooldamisest<\/a> ]",
+		"he": "<strong>\u05d0\u05ea\u05d4 \u05dc\u05d0 \u05de\u05e9\u05ea\u05de\u05e9 \u05d1- HTTPS <\/strong> - \u05d4\u05ea\u05e7\u05e9\u05e8\u05d5\u05ea \u05de\u05d5\u05e6\u05e4\u05e0\u05ea \u05e2\u05dd \u05d4\u05de\u05e9\u05ea\u05de\u05e9. HTTP \u05e2\u05d5\u05d1\u05d3 \u05d1\u05e1\u05d3\u05e8 \u05dc\u05de\u05d8\u05e8\u05d5\u05ea \u05d1\u05d3\u05d9\u05e7\u05d4, \u05d0\u05d5\u05dc\u05dd \u05dc\u05de\u05e2\u05e8\u05db\u05d5\u05ea \u05d0\u05de\u05d9\u05ea\u05d9\u05d5\u05ea, \u05db\u05d3\u05d9 \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d4 HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\"> \u05e7\u05e8\u05d0 \u05e2\u05d5\u05d3 \u05e2\u05dc \u05ea\u05d7\u05d6\u05d5\u05e7 SimpleSAMLphp <\/a> ]",
+		"zh": "<strong>\u4f60\u6ca1\u6709\u4f7f\u7528HTTPS<\/strong> - \u548c\u7528\u6237\u52a0\u5bc6\u7684\u901a\u4fe1\u3002HTTP\u5728\u6d4b\u8bd5\u76ee\u7684\u4e0b\u5f88\u597d,\u4f46\u751f\u4ea7\u73af\u5883\u8bf7\u4f7f\u7528HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u83b7\u53d6\u66f4\u591aSimpleSAMLphp\u7ef4\u62a4\u7684\u4fe1\u606f<\/a> ]",
+		"ar": "<strong>\u0627\u0646\u062a \u0644\u0627 \u062a\u0633\u062a\u062e\u062f\u0645 HTTPS<\/strong> - \u0645\u062d\u0627\u062f\u062b\u0629 \u0645\u0634\u0641\u0631\u0629 \u0645\u0639 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645. HTTP \u062c\u064a\u062f \u0644\u0644\u0627\u062e\u062a\u0628\u0627\u0631\u0627\u062a \u0644\u0643\u0646 \u0641\u064a \u0628\u064a\u0626\u0629 \u0627\u0644\u0646\u0638\u0627\u0645 \u0627\u0644\u0645\u0628\u062f\u0626\u064a \u064a\u0646\u0628\u063a\u064a \u0627\u0633\u062a\u062e\u062f\u0627\u0645 HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">read more about SimpleSAMLphp maintenance<\/a>]",
+		"lv": "<strong>J\u016bs neizmantojat HTTPS<\/strong> - \u0161ifr\u0113tu komunik\u0101ciju ar lietot\u0101ju. HTTP ir labs testa nol\u016bkiem, bet ra\u017eo\u0161an\u0101 j\u0101izmanto HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Lasiet vair\u0101k par SimpleSAMLphp uztur\u0113\u0161anu<\/a> ]",
+		"id": "<strong>Anda tidak menggunakan HTTPS<\/strong> - komunikasi yang dienkripsi dengan user. HTTP bekerja baik-baik saja untuk tujuan pengetesan , tapi dalam lingkungan produksi, Anda sebaiknya menggunakan HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Baca lebih lanjut tentang proses pemeliraan SimpleSAMLphp.<\/a> ]",
+		"sr": "<strong>Ne koristite HTTPS<\/strong> - kriptovanu komunikaciju s korisnikom. HTTP se mo\u017ee koristiti za potrebe testiranja, ali u produkcionom okru\u017eenju trebali biste koristiti HTTPS. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Pro\u010ditajte vi\u0161e o SimpleSAMLphp pode\u0161avanjima<\/a> ]",
+		"ro": "<strong>Aten\u021bie, nu utiliza\u021bi HTTPS<\/strong> - comunicare criptat\u0103 cu utilizatorul. HTTP func\u021bioneaza bine pentru teste, dar \u00een produc\u021bie trebuie folosit HTTPS. [<a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Citi\u021bi mai multe despre \u00eentre\u021binerea SimpleSAMLphp<\/a> ]",
+		"eu": "<strong>Ez zara erabiltzen ari HTTPSak<\/strong> - erabiltzailearekin zifratutako komunikazioak. HTTP zuzen ibiltzen da ebaluaketa ingurunetan, baina ustiapenean erabili behar baduzu, HTTPS erabili beharko zenuke. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei buruz <\/a> ]",
+		"el": "\u0394\u03b5\u03bd \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b5\u03af\u03c4\u03b5 <strong>HTTPS<\/strong> \u03b3\u03b9\u03b1 \u03ba\u03c1\u03c5\u03c0\u03c4\u03bf\u03b3\u03c1\u03b1\u03c6\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03c0\u03b9\u03ba\u03bf\u03b9\u03bd\u03c9\u03bd\u03af\u03b1 \u03bc\u03b5 \u03c4\u03bf\u03bd \u03c7\u03c1\u03ae\u03c3\u03c4\u03b7. \u03a4\u03bf HTTP \u03b5\u03c0\u03b1\u03c1\u03ba\u03b5\u03af \u03b3\u03b9\u03b1 \u03b4\u03bf\u03ba\u03b9\u03bc\u03b1\u03c3\u03c4\u03b9\u03ba\u03bf\u03cd\u03c2 \u03c3\u03ba\u03bf\u03c0\u03bf\u03cd\u03c2, \u03c9\u03c3\u03c4\u03cc\u03c3\u03bf \u03c3\u03b5 \u03c0\u03b5\u03c1\u03b9\u03b2\u03ac\u03bb\u03bb\u03bf\u03bd \u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03b8\u03b1 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u0048\u0054\u0054\u0050\u0053. [ <a href=\"https:\/\/simplesamlphp.org\/docs\/stable\/simplesamlphp-maintenance\">\u0394\u03b9\u03b1\u03b2\u03ac\u03c3\u03c4\u03b5 \u03c0\u03b5\u03c1\u03b9\u03c3\u03c3\u03cc\u03c4\u03b5\u03c1\u03b1...<\/a> ]"
 	},
 	"link_saml2example": {
 		"no": "SAML 2.0 SP eksempel - test innlogging med SAML 2.0 via din IdP",
@@ -1425,6 +1355,10 @@
 		"ro": "V-a\u021bi autentificat ca administrator",
 		"el": "\u03a3\u03c5\u03bd\u03b4\u03b5\u03b4\u03b5\u03bc\u03ad\u03bd\u03bf\u03c2 \u03c9\u03c2 \u03b4\u03b9\u03b1\u03c7\u03b5\u03b9\u03c1\u03b9\u03c3\u03c4\u03ae\u03c2"
 	},
+	"logout": {
+		"en": "Logout",
+		"nl": "Uitloggen"
+	},
 	"auth": {
 		"no": "Autentisering",
 		"sv": "Autentisering",
@@ -1630,5 +1564,8 @@
 		"es": "Su instalaci&oacute;n de SimpleSAMLphp est&aacute; desactualizada. Por favor, actualice a la <a href=\"%LATEST_URL%\">&uacute;ltima versi&oacute;n</a> lo antes posible.",
 		"zh-tw": "\u60a8\u6b63\u5728\u4f7f\u7528\u5df2\u904e\u6642\u7684 SimpleSAMLphp \u7248\u672c\uff0c\u8acb\u76e1\u5feb\u66f4\u65b0\u81f3<a href=\"%LATEST_URL%\">\u6700\u65b0\u7248\u672c</a>\u3002",
 		"nl": "Deze installatie van SimpleSAMLphp is verouderd. Het is aan te raden zo snel mogelijk te upgraden naar <a href=\"%LATEST_URL%\">de meest recente versie</a>."
+	},
+	"warnings_curlmissing": {
+		"nl": "PHP cURL-extensie ontbreekt. Kan niet controleren op updates voor simpleSAMLphp."
 	}
 }
diff --git a/modules/core/docs/authproc_attributelimit.md b/modules/core/docs/authproc_attributelimit.md
index 5b640fd82144a100b41688dc0c545e22ad0b40c6..73c4406efd4875c5c72ea8503ea32adcc3036c45 100644
--- a/modules/core/docs/authproc_attributelimit.md
+++ b/modules/core/docs/authproc_attributelimit.md
@@ -32,6 +32,41 @@ Allow `eduPersonTargetedID` and `eduPersonAffiliation` by default, but allow the
         ),
     ),
 
+Only allow specific values for an attribute.
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeLimit',
+            'eduPersonEntitlement' => array('urn:x-surfnet:surf.nl:surfdrive:quota:100')
+        ),
+    ),
+
+Only allow specific values for an attribute ignoring case.
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeLimit',
+            'eduPersonEntitlement' => array(
+                'ignoreCase' => true,
+                'URN:x-surfnet:surf.nl:SURFDRIVE:quota:100'
+             )
+        ),
+    ),
+    
+Only allow specific values for an attribute that match a regex pattern
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeLimit',
+            'eduPersonEntitlement' => array(
+                'regex' => true,
+                '/^urn:x-surfnet:surf/',
+                '/^urn:x-IGNORE_Case/i',
+            )
+        ),
+    ),
+    
+    
 Don't allow any attributes by default, but allow the metadata to override it.
 
     'authproc' => array(
diff --git a/modules/core/docs/authproc_cardinality.md b/modules/core/docs/authproc_cardinality.md
new file mode 100644
index 0000000000000000000000000000000000000000..97b73f86619cb70db8e4c104b2f8cf52e9e9fe46
--- /dev/null
+++ b/modules/core/docs/authproc_cardinality.md
@@ -0,0 +1,49 @@
+`core:Cardinality`
+==================
+
+Ensure the number of attribute values is within the specified multiplicity.
+
+This filter should contain a set of attribute name => rule pairs describing the multiplicity rules for an attribute.
+
+The special parameter `%ignoreEntities` can be used to give an array of entity IDs that should be ignored for testing, etc purposes.
+
+A separate [`core:CardinalitySingle`](./core:authproc_cardinalitysingle) authproc filter provides additional functionality for the special case where attributes are single valued.
+
+Specifying Rules
+----------------
+
+Multiplicity rules are specified as an associative array containing one or more of the following parameters:
+
+`min`
+:   The minimum number of values (participation) this attribute should have. Defaults to `zero`.
+
+`max`
+:   The maximum number of values (cardinality) this attribute should have. Defaults to no upper bound.
+
+`warn`
+:   Log a warning rather than generating an error. Defaults to `false`.
+
+For convenience, minimum and maximum values can also be specified using a shorthand list notation.
+
+Examples
+--------
+
+Require at least one `givenName`, no more than two email addresses, and between two and four values for `eduPersonScopedAffiliation`.
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:Cardinality',
+            'givenName' => array('min' => 1),
+            'mail' => array('max' => 2),
+            'eduPersonScopedAffiliation' => array('min' => 2, 'max' => 4),
+        ),
+    ),
+
+Use the shorthand notation for min, max:
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:Cardinality',
+            'mail' => array(0, 2),
+        ),
+    ),
diff --git a/modules/core/docs/authproc_cardinalitysingle.md b/modules/core/docs/authproc_cardinalitysingle.md
new file mode 100644
index 0000000000000000000000000000000000000000..62d2fa7998b666f9d1a0ae1ed63f0d1452e986bd
--- /dev/null
+++ b/modules/core/docs/authproc_cardinalitysingle.md
@@ -0,0 +1,88 @@
+`core:CardinalitySingle`
+========================
+
+Ensure the correct cardinality of single-valued attributes. This filter is a special case
+of the more generic [`core:Cardinality`](./core:authproc_cardinality) filter that allows for optional corrective measures
+when multi-valued attributes are received where single-valued ones are expected.
+
+Parameters
+----------
+
+This filter implements a number of optional parameters:
+
+`singleValued`
+:   array of attribute names that *must* be single-valued, or a 403 error is generated.
+
+`firstValue`
+:   array of attribute names where only the first value of a multi-valued assertion should be returned.
+
+`flatten`
+:   array of attribute names where a multi-valued assertion is flattened into a single delimited string.
+
+`flattenWith`
+:   the delimiter for `flatten`. Defaults to ";".
+
+`ignoreEntities`
+:   array of entity IDs that should be ignored for testing, etc purposes.
+
+When the same attribute name appears in multiple stanzas, they are processed in the order above.
+
+Examples
+--------
+
+Abort with an error if any attribute defined as single-valued in the eduPerson or SCHAC schemas exists and has more than one value:
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:CardinalitySingle',
+            'singleValued' => array(
+                /* from eduPerson (internet2-mace-dir-eduperson-201602) */
+                'eduPersonOrgDN', 'eduPersonPrimaryAffiliation', 'eduPersonPrimaryOrgUnitDN',
+                'eduPersonPrincipalName', 'eduPersonUniqueId',
+                /* from inetOrgPerson (RFC2798), referenced by internet2-mace-dir-eduperson-201602 */
+                'displayName', 'preferredLanguage',
+                /* from SCHAC-IAD Version 1.3.0 */
+                'schacMotherTongue', 'schacGender', 'schacDateOfBirth', 'schacPlaceOfBirth',
+                'schacPersonalTitle', 'schacHomeOrganization', 'schacHomeOrganizationType',
+                'schacExpiryDate',
+            ),
+        ),
+    ),
+
+Abort if multiple values are received for `eduPersonPrincipalName`, but take the first value for `eduPersonPrimaryAffiliation`:
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:CardinalitySingle',
+            'singleValued' => array('eduPersonPrincipalName'),
+            'firstValue' => array('eduPersonPrimaryAffiliation'),
+            ),
+        ),
+    ),
+
+Construct `eduPersonPrimaryAffiliation` using the first value in `eduPersonAffiliation`:
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeCopy',
+            'eduPersonAffiliation' => 'eduPersonPrimaryAffiliation',
+        ),
+        51 => array(
+            'class' => 'core:CardinalitySingle',
+            'firstValue' => array('eduPersonPrimaryAffiliation'),
+        ),
+    ),
+
+Construct a single, comma-separated value version of `eduPersonAffiliation`:
+
+    'authproc' => array(
+        50 => array(
+            'class' => 'core:AttributeCopy',
+            'eduPersonAffiliation' => 'eduPersonAffiliationWithCommas',
+        ),
+        51 => array(
+            'class' => 'core:CardinalitySingle',
+            'flatten' => array('eduPersonAffiliationWithCommas'),
+			'flattenWith' => ',',
+        ),
+    ),
diff --git a/modules/core/docs/authproc_languageadaptor.md b/modules/core/docs/authproc_languageadaptor.md
index 1464b0540fd36905a3a5e485f065bd4d079d05f0..c6d681db8d651649c4b5788b1e39072ba63e5fe0 100644
--- a/modules/core/docs/authproc_languageadaptor.md
+++ b/modules/core/docs/authproc_languageadaptor.md
@@ -37,6 +37,6 @@ Custon attribute:
     'authproc' => array(
         50 => array(
             'class' => 'core:LanguageAdaptor',
-	    'attributename' => 'lang',
+            'attributename' => 'lang',
         ),
     ),
diff --git a/modules/core/docs/authproc_php.md b/modules/core/docs/authproc_php.md
index 66968eda1a7b9853c2a3b9eafacb784cd7e0d79b..b913d8fe6d242d613b82afe2d1728ac409c5b174 100644
--- a/modules/core/docs/authproc_php.md
+++ b/modules/core/docs/authproc_php.md
@@ -1,7 +1,7 @@
 `core:PHP`
 ==========
 
-This is a filter which makes it possible to run arbitrary PHP code to modify the attributes of an user.
+This is a filter which makes it possible to run arbitrary PHP code to modify the attributes or state of an user.
 
 Parameters
 ----------
@@ -11,8 +11,14 @@ Parameters
     It must be `'core:PHP'`.
 
 `code`
-:   The PHP code that should be run. This code will have only one variable available: `$attributes`.
+:   The PHP code that should be run. This code will have two variables available: 
+
+* `$attributes`.
     This is an associative array of attributes, and can be modified to add or remove attributes.
+    
+* `$state`.
+    This is an associative array of request state. It can be modified to adjust data related to the authentication
+    such as desired NameId, requested Attributes, authnContextRef and many more.
 
 Examples
 --------
@@ -43,3 +49,10 @@ Create a random number variable:
             );
         ',
     ),
+
+Force a specific NameIdFormat. Useful if an SP misbehaves and requests (or publishes) an incorrect NameId
+
+    90 => array(
+         'class' => 'core:PHP',
+         'code' => '$state["saml:NameIDFormat"] = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient";'
+    ),
\ No newline at end of file
diff --git a/modules/core/docs/authproc_scopefromattribute.md b/modules/core/docs/authproc_scopefromattribute.md
index 0b7f92b9882897918cc1fd66fd4566140aa3659c..5eba851b9f8702fbbb322bf6c28ee48d0bbf895b 100644
--- a/modules/core/docs/authproc_scopefromattribute.md
+++ b/modules/core/docs/authproc_scopefromattribute.md
@@ -25,7 +25,7 @@ Set the `scope` attribute to the scope from the `eduPersonPrincipalName` attribu
     'authproc' => array(
         50 => array(
             'class' => 'core:ScopeFromAttribute',
-            'sourceAttribute' => 'eduPersonPrincipal'
-            'targetAttribute' => 'scope'
+            'sourceAttribute' => 'eduPersonPrincipalName',
+            'targetAttribute' => 'scope',
         ),
     ),
diff --git a/modules/core/hooks/hook_frontpage.php b/modules/core/hooks/hook_frontpage.php
index caf392928acf6bb285524b9b963d3ce23cc8a91c..d2b6eef9c0b15aa8d0020dd8cdd29472c1cf2edf 100644
--- a/modules/core/hooks/hook_frontpage.php
+++ b/modules/core/hooks/hook_frontpage.php
@@ -4,29 +4,30 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function core_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
 
-	$links['links']['frontpage_welcome'] = array(
-		'href' => SimpleSAML\Module::getModuleURL('core/frontpage_welcome.php'),
-		'text' => '{core:frontpage:welcome}',
-		'shorttext' => '{core:frontpage:welcome}',
-	);
-	$links['links']['frontpage_config'] = array(
-		'href' => SimpleSAML\Module::getModuleURL('core/frontpage_config.php'),
-		'text' => '{core:frontpage:configuration}',
-		'shorttext' => '{core:frontpage:configuration}',
-	);
-	$links['links']['frontpage_auth'] = array(
-		'href' => SimpleSAML\Module::getModuleURL('core/frontpage_auth.php'),
-		'text' => '{core:frontpage:auth}',
-		'shorttext' => '{core:frontpage:auth}',
-	);
-	$links['links']['frontpage_federation'] = array(
-		'href' => SimpleSAML\Module::getModuleURL('core/frontpage_federation.php'),
-		'text' => '{core:frontpage:federation}',
-		'shorttext' => '{core:frontpage:federation}',
-	);
+function core_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
 
+    $links['links']['frontpage_welcome'] = [
+        'href' => SimpleSAML\Module::getModuleURL('core/frontpage_welcome.php'),
+        'text' => '{core:frontpage:welcome}',
+        'shorttext' => '{core:frontpage:welcome}',
+    ];
+    $links['links']['frontpage_config'] = [
+        'href' => SimpleSAML\Module::getModuleURL('core/frontpage_config.php'),
+        'text' => '{core:frontpage:configuration}',
+        'shorttext' => '{core:frontpage:configuration}',
+    ];
+    $links['links']['frontpage_auth'] = [
+        'href' => SimpleSAML\Module::getModuleURL('core/frontpage_auth.php'),
+        'text' => '{core:frontpage:auth}',
+        'shorttext' => '{core:frontpage:auth}',
+    ];
+    $links['links']['frontpage_federation'] = [
+        'href' => SimpleSAML\Module::getModuleURL('core/frontpage_federation.php'),
+        'text' => '{core:frontpage:federation}',
+        'shorttext' => '{core:frontpage:federation}',
+    ];
 }
diff --git a/modules/core/hooks/hook_sanitycheck.php b/modules/core/hooks/hook_sanitycheck.php
index 237a295caab09d56f89fd9dbd2a8f752a0a83ad0..ef4af3049f99106c63bac2cbcad9d7f4a9fe578b 100644
--- a/modules/core/hooks/hook_sanitycheck.php
+++ b/modules/core/hooks/hook_sanitycheck.php
@@ -4,45 +4,47 @@
  *
  * @param array &$hookinfo  hookinfo
  */
-function core_hook_sanitycheck(&$hookinfo) {
-	assert(is_array($hookinfo));
-	assert(array_key_exists('errors', $hookinfo));
-	assert(array_key_exists('info', $hookinfo));
 
-	$config = SimpleSAML_Configuration::getInstance();
-	
-	if($config->getString('auth.adminpassword', '123') === '123') {
-		$hookinfo['errors'][] = '[core] Password in config.php is not set properly';
-	} else {
-		$hookinfo['info'][] = '[core] Password in config.php is set properly';
-	}
+function core_hook_sanitycheck(&$hookinfo)
+{
+    assert(is_array($hookinfo));
+    assert(array_key_exists('errors', $hookinfo));
+    assert(array_key_exists('info', $hookinfo));
 
-	if($config->getString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
-		$hookinfo['errors'][] = '[core] In config.php technicalcontact_email is not set properly';
-	} else {
-		$hookinfo['info'][] = '[core] In config.php technicalcontact_email is set properly';
-	}
-	
-	if (version_compare(phpversion(), '5.4', '>=')) {
-		$hookinfo['info'][] = '[core] You are running a PHP version suitable for SimpleSAMLphp.';
-	} else {
-		$hookinfo['errors'][] = '[core] You are running an old PHP installation. Please check the requirements for your SimpleSAMLphp version and upgrade.';
-	}
-	
-	$info = array();
-	$mihookinfo = array(
-		'info' => &$info,
-	);
-	$availmodules = SimpleSAML\Module::getModules();
-	SimpleSAML\Module::callHooks('moduleinfo', $mihookinfo);
-	foreach($info AS $mi => $i) {
-		if (isset($i['dependencies']) && is_array($i['dependencies'])) {
-			foreach ($i['dependencies'] AS $dep) {
-				if (!in_array($dep, $availmodules, true)) {
-					$hookinfo['errors'][] = '[core] Module dependency not met: ' . $mi . ' requires ' . $dep;
-				}
-			}
-		}
-	}
-	
+    $config = \SimpleSAML\Configuration::getInstance();
+
+    if ($config->getString('auth.adminpassword', '123') === '123') {
+        $hookinfo['errors'][] = '[core] Password in config.php is not set properly';
+    } else {
+        $hookinfo['info'][] = '[core] Password in config.php is set properly';
+    }
+
+    if ($config->getString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
+        $hookinfo['errors'][] = '[core] In config.php technicalcontact_email is not set properly';
+    } else {
+        $hookinfo['info'][] = '[core] In config.php technicalcontact_email is set properly';
+    }
+
+    if (version_compare(phpversion(), '5.5', '>=')) {
+        $hookinfo['info'][] = '[core] You are running a PHP version suitable for SimpleSAMLphp.';
+    } else {
+        $hookinfo['errors'][] = '[core] You are running an old PHP installation. '.
+            'Please check the requirements for your SimpleSAMLphp version and upgrade.';
+    }
+
+    $info = [];
+    $mihookinfo = [
+        'info' => &$info,
+    ];
+    $availmodules = SimpleSAML\Module::getModules();
+    SimpleSAML\Module::callHooks('moduleinfo', $mihookinfo);
+    foreach ($info as $mi => $i) {
+        if (isset($i['dependencies']) && is_array($i['dependencies'])) {
+            foreach ($i['dependencies'] as $dep) {
+                if (!in_array($dep, $availmodules, true)) {
+                    $hookinfo['errors'][] = '[core] Module dependency not met: '.$mi.' requires '.$dep;
+                }
+            }
+        }
+    }
 }
diff --git a/modules/core/lib/ACL.php b/modules/core/lib/ACL.php
index 175c6c2620fc7037400d8daea103916c3f797d9c..2c682a3e08d6bfa8aab90ae4eadcdee1f95e8fdf 100644
--- a/modules/core/lib/ACL.php
+++ b/modules/core/lib/ACL.php
@@ -1,306 +1,301 @@
 <?php
 
+namespace SimpleSAML\Module\core;
+
 /**
  * Generic library for access control lists.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_ACL {
-
-	/**
-	 * The access control list, as an array.
-	 *
-	 * @var array
-	 */
-	private $acl;
-
-
-	/**
-	 * Initializer for this access control list.
-	 *
-	 * @param array|string $acl  The access control list.
-	 */
-	public function __construct($acl) {
-		assert(is_string($acl) || is_array($acl));
-
-		if (is_string($acl)) {
-			$acl = self::getById($acl);
-		}
-
-		foreach ($acl as $rule) {
-			if (!is_array($rule)) {
-				throw new SimpleSAML_Error_Exception('Invalid rule in access control list: ' . var_export($rule, TRUE));
-			}
-			if (count($rule) === 0) {
-				throw new SimpleSAML_Error_Exception('Empty rule in access control list.');
-			}
-
-			$action = array_shift($rule);
-			if ($action !== 'allow' && $action !== 'deny') {
-				throw new SimpleSAML_Error_Exception('Invalid action in rule in access control list: ' . var_export($action, TRUE));
-			}
-
-		}
-
-		$this->acl = $acl;
-	}
-
-
-	/**
-	 * Retrieve an access control list with the given id.
-	 *
-	 * @param string $id  The id of the access control list.
-	 * @return array  The access control list array.
-	 */
-	private static function getById($id) {
-		assert(is_string($id));
-
-		$config = SimpleSAML_Configuration::getOptionalConfig('acl.php');
-		if (!$config->hasValue($id)) {
-			throw new SimpleSAML_Error_Exception('No ACL with id ' . var_export($id, TRUE) . ' in config/acl.php.');
-		}
-
-		return $config->getArray($id);
-	}
-
-
-	/**
-	 * Match the attributes against the access control list.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @return boolean  TRUE if the user is allowed to access the resource, FALSE if not.
-	 */
-	public function allows(array $attributes) {
-
-		foreach ($this->acl as $rule) {
-			$action = array_shift($rule);
-
-			if (!self::match($attributes, $rule)) {
-				continue;
-			}
-
-			if ($action === 'allow') {
-				return TRUE;
-			} else {
-				return FALSE;
-			}
-		}
-	}
-
-
-	/**
-	 * Match the attributes against the given rule.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function match(array $attributes, array $rule) {
-
-		$op = array_shift($rule);
-		if ($op === NULL) {
-			// An empty rule always matches
-			return TRUE;
-		}
-
-		switch($op) {
-		case 'and':
-			return self::opAnd($attributes, $rule);
-		case 'equals':
-			return self::opEquals($attributes, $rule);
-		case 'equals-preg':
-			return self::opEqualsPreg($attributes, $rule);
-		case 'has':
-			return self::opHas($attributes, $rule);
-		case 'has-preg':
-			return self::opHasPreg($attributes, $rule);
-		case 'not':
-			return !self::match($attributes, $rule);
-		case 'or':
-			return self::opOr($attributes, $rule);
-		default:
-			throw new SimpleSAML_Error_Exception('Invalid ACL operation: ' . var_export($op, TRUE));
-		}
-	}
-
-
-	/**
-	 * 'and' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opAnd($attributes, $rule) {
-
-		foreach ($rule as $subRule) {
-			if (!self::match($attributes, $subRule)) {
-				return FALSE;
-			}
-		}
-
-		// All matches
-		return TRUE;
-	}
-
-
-	/**
-	 * 'equals' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opEquals($attributes, $rule) {
-
-		$attributeName = array_shift($rule);
-
-		if (!array_key_exists($attributeName, $attributes)) {
-			$attributeValues = array();
-		} else {
-			$attributeValues = $attributes[$attributeName];
-		}
-
-		foreach ($rule as $value) {
-			$found = FALSE;
-			foreach ($attributeValues as $i => $v) {
-				if ($value !== $v) {
-					continue;
-				}
-				unset($attributeValues[$i]);
-				$found = TRUE;
-				break;
-			}
-			if (!$found) {
-				return FALSE;
-			}
-		}
-		if (!empty($attributeValues)) {
-			/* One of the attribute values didn't match. */
-			return FALSE;
-		}
-
-		/* All the values in the attribute matched one in the rule. */
-		return TRUE;
-	}
-
-
-	/**
-	 * 'equals-preg' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opEqualsPreg($attributes, $rule) {
-
-		$attributeName = array_shift($rule);
-
-		if (!array_key_exists($attributeName, $attributes)) {
-			$attributeValues = array();
-		} else {
-			$attributeValues = $attributes[$attributeName];
-		}
-
-		foreach ($rule as $pattern) {
-			$found = FALSE;
-			foreach ($attributeValues as $i => $v) {
-				if (!preg_match($pattern, $v)) {
-					continue;
-				}
-				unset($attributeValues[$i]);
-				$found = TRUE;
-				break;
-			}
-			if (!$found) {
-				return FALSE;
-			}
-		}
-
-		if (!empty($attributeValues)) {
-			/* One of the attribute values didn't match. */
-			return FALSE;
-		}
-
-		/* All the values in the attribute matched one in the rule. */
-		return TRUE;
-	}
-
-
-	/**
-	 * 'has' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opHas($attributes, $rule) {
-
-		$attributeName = array_shift($rule);
-
-		if (!array_key_exists($attributeName, $attributes)) {
-			$attributeValues = array();
-		} else {
-			$attributeValues = $attributes[$attributeName];
-		}
-
-		foreach ($rule as $value) {
-			if (!in_array($value, $attributeValues, TRUE)) {
-				return FALSE;
-			}
-		}
-
-		/* Found all values in the rule in the attribute. */
-		return TRUE;
-	}
-
-
-	/**
-	 * 'has-preg' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opHasPreg($attributes, $rule) {
-
-		$attributeName = array_shift($rule);
-
-		if (!array_key_exists($attributeName, $attributes)) {
-			$attributeValues = array();
-		} else {
-			$attributeValues = $attributes[$attributeName];
-		}
-
-		foreach ($rule as $pattern) {
-			$matches = preg_grep($pattern, $attributeValues);
-			if (count($matches) === 0) {
-				return FALSE;
-			}
-		}
-
-		/* Found all values in the rule in the attribute. */
-		return TRUE;
-	}
-
-
-	/**
-	 * 'or' match operator.
-	 *
-	 * @param array $attributes  The attributes of an user.
-	 * @param array $rule  The rule we should check.
-	 * @return boolean  TRUE if the rule matches, FALSE if not.
-	 */
-	private static function opOr($attributes, $rule) {
-
-		foreach ($rule as $subRule) {
-			if (self::match($attributes, $subRule)) {
-				return TRUE;
-			}
-		}
-
-		/* None matches. */
-		return FALSE;
-	}
 
+class ACL
+{
+    /**
+     * The access control list, as an array.
+     *
+     * @var array
+     */
+    private $acl;
+
+    /**
+     * Initializer for this access control list.
+     *
+     * @param array|string $acl  The access control list.
+     */
+    public function __construct($acl)
+    {
+        assert(is_string($acl) || is_array($acl));
+
+        if (is_string($acl)) {
+            $acl = self::getById($acl);
+        }
+
+        foreach ($acl as $rule) {
+            if (!is_array($rule)) {
+                throw new \SimpleSAML\Error\Exception('Invalid rule in access control list: '.var_export($rule, true));
+            }
+            if (count($rule) === 0) {
+                throw new \SimpleSAML\Error\Exception('Empty rule in access control list.');
+            }
+
+            $action = array_shift($rule);
+            if ($action !== 'allow' && $action !== 'deny') {
+                throw new \SimpleSAML\Error\Exception(
+                    'Invalid action in rule in access control list: '.var_export($action, true)
+                );
+            }
+        }
+        $this->acl = $acl;
+    }
+
+    /**
+     * Retrieve an access control list with the given id.
+     *
+     * @param string $id  The id of the access control list.
+     * @return array  The access control list array.
+     */
+    private static function getById($id)
+    {
+        assert(is_string($id));
+
+        $config = \SimpleSAML\Configuration::getOptionalConfig('acl.php');
+        if (!$config->hasValue($id)) {
+            throw new \SimpleSAML\Error\Exception('No ACL with id '.var_export($id, true).' in config/acl.php.');
+        }
+
+        return $config->getArray($id);
+    }
+
+    /**
+     * Match the attributes against the access control list.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @return boolean  TRUE if the user is allowed to access the resource, FALSE if not.
+     */
+    public function allows(array $attributes)
+    {
+        foreach ($this->acl as $rule) {
+            $action = array_shift($rule);
+
+            if (!self::match($attributes, $rule)) {
+                continue;
+            }
+
+            if ($action === 'allow') {
+                return true;
+            } else {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Match the attributes against the given rule.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function match(array $attributes, array $rule)
+    {
+        $op = array_shift($rule);
+        if ($op === null) {
+            // An empty rule always matches
+            return true;
+        }
+
+        switch ($op) {
+            case 'and':
+                return self::opAnd($attributes, $rule);
+            case 'equals':
+                return self::opEquals($attributes, $rule);
+            case 'equals-preg':
+                return self::opEqualsPreg($attributes, $rule);
+            case 'has':
+                return self::opHas($attributes, $rule);
+            case 'has-preg':
+                return self::opHasPreg($attributes, $rule);
+            case 'not':
+                return !self::match($attributes, $rule);
+            case 'or':
+                return self::opOr($attributes, $rule);
+            default:
+                throw new \SimpleSAML\Error\Exception('Invalid ACL operation: '.var_export($op, true));
+        }
+    }
+
+    /**
+     * 'and' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opAnd($attributes, $rule)
+    {
+        foreach ($rule as $subRule) {
+            if (!self::match($attributes, $subRule)) {
+                return false;
+            }
+        }
+
+        // All matches
+        return true;
+    }
+
+    /**
+     * 'equals' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opEquals($attributes, $rule)
+    {
+        $attributeName = array_shift($rule);
+
+        if (!array_key_exists($attributeName, $attributes)) {
+            $attributeValues = [];
+        } else {
+            $attributeValues = $attributes[$attributeName];
+        }
+
+        foreach ($rule as $value) {
+            $found = false;
+            foreach ($attributeValues as $i => $v) {
+                if ($value !== $v) {
+                    continue;
+                }
+                unset($attributeValues[$i]);
+                $found = true;
+                break;
+            }
+            if (!$found) {
+                return false;
+            }
+        }
+        if (!empty($attributeValues)) {
+            // One of the attribute values didn't match
+            return false;
+        }
+
+        // All the values in the attribute matched one in the rule
+        return true;
+    }
+
+    /**
+     * 'equals-preg' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opEqualsPreg($attributes, $rule)
+    {
+        $attributeName = array_shift($rule);
+
+        if (!array_key_exists($attributeName, $attributes)) {
+            $attributeValues = [];
+        } else {
+            $attributeValues = $attributes[$attributeName];
+        }
+
+        foreach ($rule as $pattern) {
+            $found = false;
+            foreach ($attributeValues as $i => $v) {
+                if (!preg_match($pattern, $v)) {
+                    continue;
+                }
+                unset($attributeValues[$i]);
+                $found = true;
+                break;
+            }
+            if (!$found) {
+                return false;
+            }
+        }
+
+        if (!empty($attributeValues)) {
+            // One of the attribute values didn't match
+            return false;
+        }
+
+        // All the values in the attribute matched one in the rule
+        return true;
+    }
+
+    /**
+     * 'has' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opHas($attributes, $rule)
+    {
+        $attributeName = array_shift($rule);
+
+        if (!array_key_exists($attributeName, $attributes)) {
+            $attributeValues = [];
+        } else {
+            $attributeValues = $attributes[$attributeName];
+        }
+
+        foreach ($rule as $value) {
+            if (!in_array($value, $attributeValues, true)) {
+                return false;
+            }
+        }
+
+        // Found all values in the rule in the attribute
+        return true;
+    }
+
+    /**
+     * 'has-preg' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opHasPreg($attributes, $rule)
+    {
+        $attributeName = array_shift($rule);
+
+        if (!array_key_exists($attributeName, $attributes)) {
+            $attributeValues = [];
+        } else {
+            $attributeValues = $attributes[$attributeName];
+        }
+
+        foreach ($rule as $pattern) {
+            $matches = preg_grep($pattern, $attributeValues);
+            if (count($matches) === 0) {
+                return false;
+            }
+        }
+
+        // Found all values in the rule in the attribute
+        return true;
+    }
+
+    /**
+     * 'or' match operator.
+     *
+     * @param array $attributes  The attributes of an user.
+     * @param array $rule  The rule we should check.
+     * @return boolean  TRUE if the rule matches, FALSE if not.
+     */
+    private static function opOr($attributes, $rule)
+    {
+        foreach ($rule as $subRule) {
+            if (self::match($attributes, $subRule)) {
+                return true;
+            }
+        }
+
+        // None matches
+        return false;
+    }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeAdd.php b/modules/core/lib/Auth/Process/AttributeAdd.php
index 63aa03fb2becf34654b18b7f95b7a307c912c7b9..deb3ac310c4f1e8d6d4152080473dacaadc39814 100644
--- a/modules/core/lib/Auth/Process/AttributeAdd.php
+++ b/modules/core/lib/Auth/Process/AttributeAdd.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter to add attributes.
  *
@@ -8,78 +10,76 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_AttributeAdd extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Flag which indicates wheter this filter should append new values or replace old values.
-	 */
-	private $replace = FALSE;
-
-
-	/**
-	 * Attributes which should be added/appended.
-	 *
-	 * Assiciative array of arrays.
-	 */
-	private $attributes = array();
-
 
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
+class AttributeAdd extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Flag which indicates wheter this filter should append new values or replace old values.
+     */
+    private $replace = false;
 
-		assert(is_array($config));
+    /**
+     * Attributes which should be added/appended.
+     *
+     * Assiciative array of arrays.
+     */
+    private $attributes = [];
 
-		foreach($config as $name => $values) {
-			if(is_int($name)) {
-				if($values === '%replace') {
-					$this->replace = TRUE;
-				} else {
-					throw new Exception('Unknown flag: ' . var_export($values, TRUE));
-				}
-				continue;
-			}
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
 
-			if(!is_array($values)) {
-				$values = array($values);
-			}
-			foreach($values as $value) {
-				if(!is_string($value)) {
-					throw new Exception('Invalid value for attribute ' . $name . ': ' .
-						var_export($values, TRUE));
-				}
-			}
+        assert(is_array($config));
 
-			$this->attributes[$name] = $values;
-		}
-	}
+        foreach ($config as $name => $values) {
+            if (is_int($name)) {
+                if ($values === '%replace') {
+                    $this->replace = true;
+                } else {
+                    throw new \Exception('Unknown flag: '.var_export($values, true));
+                }
+                continue;
+            }
 
+            if (!is_array($values)) {
+                $values = [$values];
+            }
+            foreach ($values as $value) {
+                if (!is_string($value)) {
+                    throw new \Exception('Invalid value for attribute '.$name.': '.var_export($values, true));
+                }
+            }
 
-	/**
-	 * Apply filter to add or replace attributes.
-	 *
-	 * Add or replace existing attributes with the configured values.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
+            $this->attributes[$name] = $values;
+        }
+    }
 
-		$attributes =& $request['Attributes'];
+    /**
+     * Apply filter to add or replace attributes.
+     *
+     * Add or replace existing attributes with the configured values.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
 
-		foreach($this->attributes as $name => $values) {
-			if($this->replace === TRUE || !array_key_exists($name, $attributes)) {
-				$attributes[$name] = $values;
-			} else {
-				$attributes[$name] = array_merge($attributes[$name], $values);
-			}
-		}
-	}
+        $attributes = &$request['Attributes'];
 
+        foreach ($this->attributes as $name => $values) {
+            if ($this->replace === true || !array_key_exists($name, $attributes)) {
+                $attributes[$name] = $values;
+            } else {
+                $attributes[$name] = array_merge($attributes[$name], $values);
+            }
+        }
+    }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeAlter.php b/modules/core/lib/Auth/Process/AttributeAlter.php
index c53625790b57c44990ec666b6bf400cff330fbba..0d181a0d7cd45700556bd4d121cf4c90da087704 100644
--- a/modules/core/lib/Auth/Process/AttributeAlter.php
+++ b/modules/core/lib/Auth/Process/AttributeAlter.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter to modify attributes using regular expressions
  *
@@ -7,7 +10,8 @@
  * @author Jacob Christiansen, WAYF
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_ProcessingFilter
+
+class AttributeAlter extends \SimpleSAML\Auth\ProcessingFilter
 {
     /**
      * Should the pattern found be replaced?
@@ -44,7 +48,7 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
      *
      * @param array $config  Configuration information about this filter.
      * @param mixed $reserved  For future use.
-     * @throws SimpleSAML_Error_Exception In case of invalid configuration.
+     * @throws \SimpleSAML\Error\Exception In case of invalid configuration.
      */
     public function __construct($config, $reserved)
     {
@@ -61,7 +65,7 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
                 } elseif ($value === '%remove') {
                     $this->remove = true;
                 } else {
-                    throw new SimpleSAML_Error_Exception('Unknown flag : ' . var_export($value, true));
+                    throw new \SimpleSAML\Error\Exception('Unknown flag : '.var_export($value, true));
                 }
                 continue;
             } elseif ($name === 'pattern') {
@@ -86,31 +90,32 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
      * Modify existing attributes with the configured values.
      *
      * @param array &$request The current request.
-     * @throws SimpleSAML_Error_Exception In case of invalid configuration.
+     * @throws \SimpleSAML\Error\Exception In case of invalid configuration.
      */
-    public function process(&$request) {
+    public function process(&$request)
+    {
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
 
         // get attributes from request
-        $attributes =& $request['Attributes'];
+        $attributes = &$request['Attributes'];
 
         // check that all required params are set in config
         if (empty($this->pattern) || empty($this->subject)) {
-            throw new SimpleSAML_Error_Exception("Not all params set in config.");
+            throw new \SimpleSAML\Error\Exception("Not all params set in config.");
         }
 
         if (!$this->replace && !$this->remove && $this->replacement === false) {
-            throw new SimpleSAML_Error_Exception("'replacement' must be set if neither '%replace' nor ".
+            throw new \SimpleSAML\Error\Exception("'replacement' must be set if neither '%replace' nor ".
                 "'%remove' are set.");
         }
 
         if (!$this->replace && $this->replacement === null) {
-            throw new SimpleSAML_Error_Exception("'%replace' must be set if 'replacement' is null.");
+            throw new \SimpleSAML\Error\Exception("'%replace' must be set if 'replacement' is null.");
         }
 
         if ($this->replace && $this->remove) {
-            throw new SimpleSAML_Error_Exception("'%replace' and '%remove' cannot be used together.");
+            throw new \SimpleSAML\Error\Exception("'%replace' and '%remove' cannot be used together.");
         }
 
         if (empty($this->target)) {
@@ -119,7 +124,7 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
         }
 
         if ($this->subject !== $this->target && $this->remove) {
-            throw new SimpleSAML_Error_Exception("Cannot use '%remove' when 'target' is different than 'subject'.");
+            throw new \SimpleSAML\Error\Exception("Cannot use '%remove' when 'target' is different than 'subject'.");
         }
 
         if (!array_key_exists($this->subject, $attributes)) {
@@ -127,27 +132,29 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
             return;
         }
 
-        if ($this->replace) { // replace the whole value
+        if ($this->replace) {
+            // replace the whole value
             foreach ($attributes[$this->subject] as &$value) {
-                $matches = array();
+                $matches = [];
                 if (preg_match($this->pattern, $value, $matches) > 0) {
                     $new_value = $matches[0];
 
-                    if ($this->replacement !== FALSE) {
+                    if ($this->replacement !== false) {
                         $new_value = $this->replacement;
                     }
 
                     if ($this->subject === $this->target) {
                         $value = $new_value;
                     } else {
-                        $attributes[$this->target] = array($new_value);
+                        $attributes[$this->target] = [$new_value];
                     }
                 }
             }
-        } elseif ($this->remove) { // remove the whole value
-            $removedAttrs = array();
+        } elseif ($this->remove) {
+            // remove the whole value
+            $removedAttrs = [];
             foreach ($attributes[$this->subject] as $value) {
-                $matches = array();
+                $matches = [];
                 if (preg_match($this->pattern, $value, $matches) > 0) {
                     $removedAttrs[] = $value;
                 }
@@ -157,10 +164,12 @@ class sspmod_core_Auth_Process_AttributeAlter extends SimpleSAML_Auth_Processing
             if (empty($attributes[$this->target])) {
                 unset($attributes[$this->target]);
             }
-        } else { // replace only the part that matches
+        } else {
+            // replace only the part that matches
             if ($this->subject === $this->target) {
                 $attributes[$this->target] = preg_replace(
-                    $this->pattern, $this->replacement,
+                    $this->pattern,
+                    $this->replacement,
                     $attributes[$this->subject]
                 );
             } else {
diff --git a/modules/core/lib/Auth/Process/AttributeCopy.php b/modules/core/lib/Auth/Process/AttributeCopy.php
index e2412a45c8d0ff36e41bf9cfc2e51a89d12ec48c..1b54da17ae14826a5c6abe82c83b87fef681c6a3 100644
--- a/modules/core/lib/Auth/Process/AttributeCopy.php
+++ b/modules/core/lib/Auth/Process/AttributeCopy.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Attribute filter for renaming attributes.
  *
@@ -15,62 +17,61 @@
  *         ),
  *
  */
-class sspmod_core_Auth_Process_AttributeCopy extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Assosiative array with the mappings of attribute names.
-	 */
-	private $map = array();
-
-
-	/**
-	 * Initialize this filter, parse configuration
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
 
-		foreach($config as $source => $destination) {
+class AttributeCopy extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Assosiative array with the mappings of attribute names.
+     */
+    private $map = [];
 
-			if(!is_string($source)) {
-				throw new Exception('Invalid source attribute name: ' . var_export($source, TRUE));
-			}
+    /**
+     * Initialize this filter, parse configuration
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
 
-			if(!is_string($destination) && !is_array($destination)) {
-				throw new Exception('Invalid destination attribute name: ' . var_export($destination, TRUE));
-			}
+        assert(is_array($config));
 
-			$this->map[$source] = $destination;
-		}
-	}
+        foreach ($config as $source => $destination) {
+            if (!is_string($source)) {
+                throw new \Exception('Invalid source attribute name: '.var_export($source, true));
+            }
 
+            if (!is_string($destination) && !is_array($destination)) {
+                throw new \Exception('Invalid destination attribute name: '.var_export($destination, true));
+            }
 
-	/**
-	 * Apply filter to rename attributes.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
+            $this->map[$source] = $destination;
+        }
+    }
 
-		$attributes =& $request['Attributes'];
+    /**
+     * Apply filter to rename attributes.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
 
-		foreach($attributes as $name => $values) {
-			if (array_key_exists($name,$this->map)){
-				if (!is_array($this->map[$name])) {
-					$attributes[$this->map[$name]] = $values;
-				} else {
-					foreach ($this->map[$name] as $to_map) {
-						$attributes[$to_map] = $values;
-					}
-				}
-			}
-		}
+        $attributes = &$request['Attributes'];
 
-	}
+        foreach ($attributes as $name => $values) {
+            if (array_key_exists($name, $this->map)) {
+                if (!is_array($this->map[$name])) {
+                    $attributes[$this->map[$name]] = $values;
+                } else {
+                    foreach ($this->map[$name] as $to_map) {
+                        $attributes[$to_map] = $values;
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeLimit.php b/modules/core/lib/Auth/Process/AttributeLimit.php
index d74d60355c1fd103caa9945cd7e75fbb3f3093db..b90d1b0cdedad5ec6f3d34264254d30ec8128744 100644
--- a/modules/core/lib/Auth/Process/AttributeLimit.php
+++ b/modules/core/lib/Auth/Process/AttributeLimit.php
@@ -1,127 +1,169 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * A filter for limiting which attributes are passed on.
  *
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_AttributeLimit extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * List of attributes which this filter will allow through.
-	 */
-	private $allowedAttributes = array();
-
-
-	/**
-	 * Whether the 'attributes' option in the metadata takes precedence.
-	 *
-	 * @var bool
-	 */
-	private $isDefault = FALSE;
-
-
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use
-     * @throws SimpleSAML_Error_Exception If invalid configuration is found.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
 
-		assert(is_array($config));
-
-		foreach ($config as $index => $value) {
-			if ($index === 'default') {
-				$this->isDefault = (bool)$value;
-			} elseif (is_int($index)) {
-				if (!is_string($value)) {
-					throw new SimpleSAML_Error_Exception('AttributeLimit: Invalid attribute name: ' .
-                        var_export($value, TRUE));
-				}
-				$this->allowedAttributes[] = $value;
+class AttributeLimit extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * List of attributes which this filter will allow through.
+     */
+    private $allowedAttributes = [];
+
+    /**
+     * Whether the 'attributes' option in the metadata takes precedence.
+     *
+     * @var bool
+     */
+    private $isDefault = false;
+
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use
+     * @throws \SimpleSAML\Error\Exception If invalid configuration is found.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        foreach ($config as $index => $value) {
+            if ($index === 'default') {
+                $this->isDefault = (bool) $value;
+            } elseif (is_int($index)) {
+                if (!is_string($value)) {
+                    throw new \SimpleSAML\Error\Exception('AttributeLimit: Invalid attribute name: '.
+                        var_export($value, true));
+                }
+                $this->allowedAttributes[] = $value;
             } elseif (is_string($index)) {
                 if (!is_array($value)) {
-                    throw new SimpleSAML_Error_Exception('AttributeLimit: Values for ' . var_export($index, TRUE) .
-                        ' must be specified in an array.');
+                    throw new \SimpleSAML\Error\Exception('AttributeLimit: Values for '.
+                        var_export($index, true).' must be specified in an array.');
                 }
                 $this->allowedAttributes[$index] = $value;
-			} else {
-				throw new SimpleSAML_Error_Exception('AttributeLimit: Invalid option: ' . var_export($index, TRUE));
-			}
-		}
-	}
-
-
-	/**
-	 * Get list of allowed from the SP/IdP config.
-	 *
-	 * @param array &$request  The current request.
-	 * @return array|NULL  Array with attribute names, or NULL if no limit is placed.
-	 */
-	private static function getSPIdPAllowed(array &$request) {
-
-		if (array_key_exists('attributes', $request['Destination'])) {
-			// SP Config
-			return $request['Destination']['attributes'];
-		}
-		if (array_key_exists('attributes', $request['Source'])) {
-			// IdP Config
-			return $request['Source']['attributes'];
-		}
-		return NULL;
-	}
-
-
-	/**
-	 * Apply filter to remove attributes.
-	 *
-	 * Removes all attributes which aren't one of the allowed attributes.
-	 *
-	 * @param array &$request  The current request
-     * @throws SimpleSAML_Error_Exception If invalid configuration is found.
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		if ($this->isDefault) {
-			$allowedAttributes = self::getSPIdPAllowed($request);
-			if ($allowedAttributes === NULL) {
-				$allowedAttributes = $this->allowedAttributes;
-			}
-		} elseif (!empty($this->allowedAttributes)) {
-			$allowedAttributes = $this->allowedAttributes;
-		} else {
-			$allowedAttributes = self::getSPIdPAllowed($request);
-			if ($allowedAttributes === NULL) {
-				return; /* No limit on attributes. */
-			}
-		}
-
-		$attributes =& $request['Attributes'];
-
-		foreach ($attributes as $name => $values) {
-			if (!in_array($name, $allowedAttributes, TRUE)) {
+            } else {
+                throw new \SimpleSAML\Error\Exception('AttributeLimit: Invalid option: '.var_export($index, true));
+            }
+        }
+    }
+
+    /**
+     * Get list of allowed from the SP/IdP config.
+     *
+     * @param array &$request  The current request.
+     * @return array|NULL  Array with attribute names, or NULL if no limit is placed.
+     */
+    private static function getSPIdPAllowed(array &$request)
+    {
+        if (array_key_exists('attributes', $request['Destination'])) {
+            // SP Config
+            return $request['Destination']['attributes'];
+        }
+        if (array_key_exists('attributes', $request['Source'])) {
+            // IdP Config
+            return $request['Source']['attributes'];
+        }
+        return null;
+    }
+
+    /**
+     * Apply filter to remove attributes.
+     *
+     * Removes all attributes which aren't one of the allowed attributes.
+     *
+     * @param array &$request  The current request
+     * @throws \SimpleSAML\Error\Exception If invalid configuration is found.
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        if ($this->isDefault) {
+            $allowedAttributes = self::getSPIdPAllowed($request);
+            if ($allowedAttributes === null) {
+                $allowedAttributes = $this->allowedAttributes;
+            }
+        } elseif (!empty($this->allowedAttributes)) {
+            $allowedAttributes = $this->allowedAttributes;
+        } else {
+            $allowedAttributes = self::getSPIdPAllowed($request);
+            if ($allowedAttributes === null) {
+                // No limit on attributes
+                return;
+            }
+        }
+
+        $attributes = &$request['Attributes'];
+
+        foreach ($attributes as $name => $values) {
+            if (!in_array($name, $allowedAttributes, true)) {
                 // the attribute name is not in the array of allowed attributes
                 if (array_key_exists($name, $allowedAttributes)) {
                     // but it is an index of the array
                     if (!is_array($allowedAttributes[$name])) {
-                        throw new SimpleSAML_Error_Exception('AttributeLimit: Values for ' . var_export($name, TRUE) .
-                            ' must be specified in an array.');
+                        throw new \SimpleSAML\Error\Exception('AttributeLimit: Values for '.
+                            var_export($name, true).' must be specified in an array.');
                     }
-                    $attributes[$name] = array_intersect($attributes[$name], $allowedAttributes[$name]);
+                    $attributes[$name] = $this->filterAttributeValues($attributes[$name], $allowedAttributes[$name]);
                     if (!empty($attributes[$name])) {
                         continue;
                     }
                 }
                 unset($attributes[$name]);
-			}
-		}
-
-	}
-
+            }
+        }
+    }
+
+    /**
+     * Perform the filtering of attributes
+     * @param array $values The current values for a given attribute
+     * @param array $allowedConfigValues The allowed values, and possibly configuration options.
+     * @return array The filtered values
+     */
+    private function filterAttributeValues(array $values, array $allowedConfigValues)
+    {
+        if (array_key_exists('regex', $allowedConfigValues) && $allowedConfigValues['regex'] === true) {
+            $matchedValues = [];
+            foreach ($allowedConfigValues as $option => $pattern) {
+                if (!is_int($option)) {
+                    // Ignore any configuration options in $allowedConfig. e.g. regex=>true
+                    continue;
+                }
+                foreach ($values as $index => $attributeValue) {
+                    /* Suppress errors in preg_match since phpunit is set to fail on warnings, which
+                     *  prevents us from testing with invalid regex.
+                     */
+                    $regexResult = @preg_match($pattern, $attributeValue);
+                    if ($regexResult === false) {
+                        \SimpleSAML\Logger::warning("Error processing regex '$pattern' on value '$attributeValue'");
+                        break;
+                    } elseif ($regexResult === 1) {
+                        $matchedValues[] = $attributeValue;
+                        // Remove matched value incase a subsequent regex also matches it.
+                        unset($values[$index]);
+                    }
+                }
+            }
+            return $matchedValues;
+        } elseif (array_key_exists('ignoreCase', $allowedConfigValues) && $allowedConfigValues['ignoreCase'] === true) {
+            unset($allowedConfigValues['ignoreCase']);
+            return array_uintersect($values, $allowedConfigValues, "strcasecmp");
+        }
+        // The not true values for these options shouldn't leak through to array_intersect
+        unset($allowedConfigValues['ignoreCase']);
+        unset($allowedConfigValues['regex']);
+
+        return array_intersect($values, $allowedConfigValues);
+    }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeMap.php b/modules/core/lib/Auth/Process/AttributeMap.php
index 5de07cb24b229f8503adfe6c8150db31423bdbed..cedde6877a536992a6b8e6c312f88f1b487efa85 100644
--- a/modules/core/lib/Auth/Process/AttributeMap.php
+++ b/modules/core/lib/Auth/Process/AttributeMap.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
 
 /**
  * Attribute filter for renaming attributes.
@@ -7,13 +8,13 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_AttributeMap extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class AttributeMap extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * Associative array with the mappings of attribute names.
      */
-    private $map = array();
+    private $map = [];
 
     /**
      * Should attributes be duplicated or renamed.
@@ -34,7 +35,7 @@ class sspmod_core_Auth_Process_AttributeMap extends SimpleSAML_Auth_ProcessingFi
         parent::__construct($config, $reserved);
 
         assert(is_array($config));
-        $mapFiles = array();
+        $mapFiles = [];
 
         foreach ($config as $origName => $newName) {
             if (is_int($origName)) {
@@ -48,11 +49,11 @@ class sspmod_core_Auth_Process_AttributeMap extends SimpleSAML_Auth_ProcessingFi
             }
 
             if (!is_string($origName)) {
-                throw new Exception('Invalid attribute name: '.var_export($origName, true));
+                throw new \Exception('Invalid attribute name: '.var_export($origName, true));
             }
 
             if (!is_string($newName) && !is_array($newName)) {
-                throw new Exception('Invalid attribute name: '.var_export($newName, true));
+                throw new \Exception('Invalid attribute name: '.var_export($newName, true));
             }
 
             $this->map[$origName] = $newName;
@@ -75,26 +76,27 @@ class sspmod_core_Auth_Process_AttributeMap extends SimpleSAML_Auth_ProcessingFi
      */
     private function loadMapFile($fileName)
     {
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = \SimpleSAML\Configuration::getInstance();
 
         $m = explode(':', $fileName);
-        if (count($m) === 2) { // we are asked for a file in a module
-            if (!SimpleSAML\Module::isModuleEnabled($m[0])) {
-                throw new Exception("Module '$m[0]' is not enabled.");
+        if (count($m) === 2) {
+            // we are asked for a file in a module
+            if (!\SimpleSAML\Module::isModuleEnabled($m[0])) {
+                throw new \Exception("Module '$m[0]' is not enabled.");
             }
-            $filePath = SimpleSAML\Module::getModuleDir($m[0]).'/attributemap/'.$m[1].'.php';
+            $filePath = \SimpleSAML\Module::getModuleDir($m[0]).'/attributemap/'.$m[1].'.php';
         } else {
             $filePath = $config->getPathValue('attributenamemapdir', 'attributemap/').$fileName.'.php';
         }
 
         if (!file_exists($filePath)) {
-            throw new Exception('Could not find attribute map file: '.$filePath);
+            throw new \Exception('Could not find attribute map file: '.$filePath);
         }
 
         $attributemap = null;
         include($filePath);
         if (!is_array($attributemap)) {
-            throw new Exception('Attribute map file "'.$filePath.'" didn\'t define an attribute map.');
+            throw new \Exception('Attribute map file "'.$filePath.'" didn\'t define an attribute map.');
         }
 
         if ($this->duplicate) {
@@ -115,24 +117,28 @@ class sspmod_core_Auth_Process_AttributeMap extends SimpleSAML_Auth_ProcessingFi
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
 
-        $attributes =& $request['Attributes'];
+        $mapped_attributes = [];
 
-        foreach ($attributes as $name => $values) {
+        foreach ($request['Attributes'] as $name => $values) {
             if (array_key_exists($name, $this->map)) {
                 if (!is_array($this->map[$name])) {
-                    if (!$this->duplicate) {
-                        unset($attributes[$name]);
+                    if ($this->duplicate) {
+                        $mapped_attributes[$name] = $values;
                     }
-                    $attributes[$this->map[$name]] = $values;
+                    $mapped_attributes[$this->map[$name]] = $values;
                 } else {
                     foreach ($this->map[$name] as $to_map) {
-                        $attributes[$to_map] = $values;
+                        $mapped_attributes[$to_map] = $values;
                     }
-                    if (!$this->duplicate && !in_array($name, $this->map[$name], true)) {
-                        unset($attributes[$name]);
+                    if ($this->duplicate && !in_array($name, $this->map[$name], true)) {
+                        $mapped_attributes[$name] = $values;
                     }
                 }
+            } else {
+                $mapped_attributes[$name] = $values;
             }
         }
+
+        $request['Attributes'] = $mapped_attributes;
     }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeRealm.php b/modules/core/lib/Auth/Process/AttributeRealm.php
index 86c8be1b2f10e25b04873213d573f681e504a0d5..f6366e9fe66abb5cd0cd219d173dae82ba3cc7fc 100644
--- a/modules/core/lib/Auth/Process/AttributeRealm.php
+++ b/modules/core/lib/Auth/Process/AttributeRealm.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter that will take the user ID on the format 'andreas@uninett.no'
  * and create a new attribute 'realm' that includes the value after the '@' sign.
@@ -8,8 +10,9 @@
  * @package SimpleSAMLphp
  * @deprecated Use ScopeFromAttribute instead.
  */
-class sspmod_core_Auth_Process_AttributeRealm extends SimpleSAML_Auth_ProcessingFilter {
 
+class AttributeRealm extends \SimpleSAML\Auth\ProcessingFilter
+{
     private $attributename = 'realm';
 
     /**
@@ -18,13 +21,14 @@ class sspmod_core_Auth_Process_AttributeRealm extends SimpleSAML_Auth_Processing
      * @param array $config  Configuration information about this filter.
      * @param mixed $reserved  For future use.
      */
-    public function __construct($config, $reserved) {
+    public function __construct($config, $reserved)
+    {
         parent::__construct($config, $reserved);
         assert(is_array($config));
 
-        if (array_key_exists('attributename', $config))
+        if (array_key_exists('attributename', $config)) {
             $this->attributename = $config['attributename'];
-
+        }
     }
 
     /**
@@ -34,20 +38,21 @@ class sspmod_core_Auth_Process_AttributeRealm extends SimpleSAML_Auth_Processing
      *
      * @param array &$request  The current request
      */
-    public function process(&$request) {
+    public function process(&$request)
+    {
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
 
-        $attributes =& $request['Attributes'];
-
         if (!array_key_exists('UserID', $request)) {
-            throw new Exception('core:AttributeRealm: Missing UserID for this user. Please' .
-                ' check the \'userid.attribute\' option in the metadata against the' .
+            throw new \Exception('core:AttributeRealm: Missing UserID for this user. Please'.
+                ' check the \'userid.attribute\' option in the metadata against the'.
                 ' attributes provided by the authentication source.');
         }
         $userID = $request['UserID'];
         $decomposed = explode('@', $userID);
-        if (count($decomposed) !== 2) return;
-        $request['Attributes'][$this->attributename] = array($decomposed[1]);
+        if (count($decomposed) !== 2) {
+            return;
+        }
+        $request['Attributes'][$this->attributename] = [$decomposed[1]];
     }
 }
diff --git a/modules/core/lib/Auth/Process/AttributeValueMap.php b/modules/core/lib/Auth/Process/AttributeValueMap.php
index 5c69048f69d97ba59fc97c57190f1f7c44582745..9979ea66f27b8d5768c89c122ec10dddbc6be795 100644
--- a/modules/core/lib/Auth/Process/AttributeValueMap.php
+++ b/modules/core/lib/Auth/Process/AttributeValueMap.php
@@ -8,32 +8,32 @@ namespace SimpleSAML\Module\core\Auth\Process;
  * @author Martin van Es, m7
  * @package SimpleSAMLphp
  */
-class AttributeValueMap extends \SimpleSAML_Auth_ProcessingFilter
-{
 
+class AttributeValueMap extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
-    * The name of the attribute we should assign values to (ie: the target attribute).
-    */
+     * The name of the attribute we should assign values to (ie: the target attribute).
+     */
     private $targetattribute;
 
     /**
-    * The name of the attribute we should create values from.
-    */
+     * The name of the attribute we should create values from.
+     */
     private $sourceattribute;
 
     /**
-    * The required $sourceattribute values and target affiliations.
-    */
-    private $values = array();
+     * The required $sourceattribute values and target affiliations.
+     */
+    private $values = [];
     
     /**
-    * Whether $sourceattribute should be kept or not.
-    */
+     * Whether $sourceattribute should be kept or not.
+     */
     private $keep = false;
 
     /**
-    * Whether $target attribute values should be replaced by new values or not.
-    */
+     * Whether $target attribute values should be replaced by new values or not.
+     */
     private $replace = false;
     
     /**
@@ -41,8 +41,8 @@ class AttributeValueMap extends \SimpleSAML_Auth_ProcessingFilter
      *
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
-     * @throws \SimpleSAML_Error_Exception If the configuration is not valid.
-    */
+     * @throws \SimpleSAML\Error\Exception If the configuration is not valid.
+     */
     public function __construct($config, $reserved)
     {
         parent::__construct($config, $reserved);
@@ -84,13 +84,13 @@ class AttributeValueMap extends \SimpleSAML_Auth_ProcessingFilter
 
         // now validate it
         if (!is_string($this->sourceattribute)) {
-            throw new \SimpleSAML_Error_Exception("AttributeValueMap: 'sourceattribute' configuration option not set.");
+            throw new \SimpleSAML\Error\Exception("AttributeValueMap: 'sourceattribute' configuration option not set.");
         }
         if (!is_string($this->targetattribute)) {
-            throw new \SimpleSAML_Error_Exception("AttributeValueMap: 'targetattribute' configuration option not set.");
+            throw new \SimpleSAML\Error\Exception("AttributeValueMap: 'targetattribute' configuration option not set.");
         }
         if (!is_array($this->values)) {
-            throw new \SimpleSAML_Error_Exception("AttributeValueMap: 'values' configuration option is not an array.");
+            throw new \SimpleSAML\Error\Exception("AttributeValueMap: 'values' configuration option is not an array.");
         }
     }
 
@@ -106,7 +106,7 @@ class AttributeValueMap extends \SimpleSAML_Auth_ProcessingFilter
 
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
-        $attributes =& $request['Attributes'];
+        $attributes = &$request['Attributes'];
 
         if (!array_key_exists($this->sourceattribute, $attributes)) {
             // the source attribute does not exist, nothing to do here
@@ -114,12 +114,12 @@ class AttributeValueMap extends \SimpleSAML_Auth_ProcessingFilter
         }
 
         $sourceattribute = $attributes[$this->sourceattribute];
-        $targetvalues = array();
+        $targetvalues = [];
 
         if (is_array($sourceattribute)) {
             foreach ($this->values as $value => $values) {
                 if (!is_array($values)) {
-                    $values = array($values);
+                    $values = [$values];
                 }
                 if (count(array_intersect($values, $sourceattribute)) > 0) {
                     \SimpleSAML\Logger::debug("AttributeValueMap: intersect match for '$value'");
diff --git a/modules/core/lib/Auth/Process/Cardinality.php b/modules/core/lib/Auth/Process/Cardinality.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac4f1aad1edca4ca87a0ab54c71b40fe28fe9902
--- /dev/null
+++ b/modules/core/lib/Auth/Process/Cardinality.php
@@ -0,0 +1,194 @@
+<?php
+
+namespace SimpleSAML\Module\core\Auth\Process;
+
+use SimpleSAML\Utils\HttpAdapter;
+
+/**
+ * Filter to ensure correct cardinality of attributes
+ *
+ * @author Guy Halse, http://orcid.org/0000-0002-9388-8592
+ * @package SimpleSAMLphp
+ */
+
+class Cardinality extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /** @var array Associative array with the mappings of attribute names. */
+    private $cardinality = [];
+
+    /** @var array Entities that should be ignored */
+    private $ignoreEntities = [];
+
+    /** @var HTTPAdapter */
+    private $http;
+
+    /**
+     * Initialize this filter, parse configuration.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     * @param HTTPAdapter $http  HTTP utility service (handles redirects).
+     * @throws \SimpleSAML\Error\Exception
+     */
+    public function __construct($config, $reserved, HttpAdapter $http = null)
+    {
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
+
+        $this->http = $http ? : new HttpAdapter();
+
+        foreach ($config as $attribute => $rules) {
+            if ($attribute === '%ignoreEntities') {
+                $this->ignoreEntities = $config['%ignoreEntities'];
+                continue;
+            }
+
+            if (!is_string($attribute)) {
+                throw new \SimpleSAML\Error\Exception('Invalid attribute name: '.var_export($attribute, true));
+            }
+            $this->cardinality[$attribute] = ['warn' => false];
+
+            /* allow either positional or name-based parameters */
+            if (isset($rules[0])) {
+                $this->cardinality[$attribute]['min'] = $rules[0];
+            } elseif (isset($rules['min'])) {
+                $this->cardinality[$attribute]['min'] = $rules['min'];
+            }
+            if (isset($rules[1])) {
+                $this->cardinality[$attribute]['max'] = $rules[1];
+            } elseif (isset($rules['max'])) {
+                $this->cardinality[$attribute]['max'] = $rules['max'];
+            }
+            if (array_key_exists('warn', $rules)) {
+                $this->cardinality[$attribute]['warn'] = (bool) $rules['warn'];
+            }
+
+            /* sanity check the rules */
+            if (!array_key_exists('min', $this->cardinality[$attribute])) {
+                $this->cardinality[$attribute]['min'] = 0;
+            } elseif (!is_int($this->cardinality[$attribute]['min']) ||
+                $this->cardinality[$attribute]['min'] < 0
+            ) {
+                throw new \SimpleSAML\Error\Exception('Minimum cardinality must be a positive integer: '.
+                    var_export($attribute, true));
+            }
+            if (array_key_exists('max', $this->cardinality[$attribute]) &&
+                !is_int($this->cardinality[$attribute]['max'])
+            ) {
+                throw new \SimpleSAML\Error\Exception('Maximum cardinality must be a positive integer: '.
+                    var_export($attribute, true));
+            }
+            if (array_key_exists('min', $this->cardinality[$attribute]) &&
+                array_key_exists('max', $this->cardinality[$attribute]) &&
+                $this->cardinality[$attribute]['min'] > $this->cardinality[$attribute]['max']
+            ) {
+                throw new \SimpleSAML\Error\Exception('Minimum cardinality must be less than maximium: '.
+                    var_export($attribute, true));
+            }
+
+            /* generate a display expression */
+            $this->cardinality[$attribute]['_expr'] = sprintf('%d ≤ n', $this->cardinality[$attribute]['min']);
+            if (array_key_exists('max', $this->cardinality[$attribute])) {
+                $this->cardinality[$attribute]['_expr'] .= sprintf(' ≤ %d', $this->cardinality[$attribute]['max']);
+            }
+        }
+    }
+
+    /**
+     * Process this filter
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists("Attributes", $request));
+
+        $entityid = false;
+        if (array_key_exists('Source', $request) && array_key_exists('entityid', $request['Source'])) {
+            $entityid = $request['Source']['entityid'];
+        }
+        if (in_array($entityid, $this->ignoreEntities, true)) {
+            \SimpleSAML\Logger::debug('Cardinality: Ignoring assertions from '.$entityid);
+            return;
+        }
+
+        foreach ($request['Attributes'] as $k => $v) {
+            if (!array_key_exists($k, $this->cardinality)) {
+                continue;
+            }
+            if (!is_array($v)) {
+                $v = [$v];
+            }
+
+            /* minimum cardinality */
+            if (count($v) < $this->cardinality[$k]['min']) {
+                if ($this->cardinality[$k]['warn']) {
+                    \SimpleSAML\Logger::warning(
+                        sprintf(
+                            'Cardinality: attribute %s from %s does not meet minimum cardinality of %d (%d)',
+                            $k,
+                            $entityid,
+                            $this->cardinality[$k]['min'],
+                            count($v)
+                        )
+                    );
+                } else {
+                    $request['core:cardinality:errorAttributes'][$k] = [
+                        count($v),
+                        $this->cardinality[$k]['_expr']
+                    ];
+                }
+                continue;
+            }
+
+            /* maximum cardinality */
+            if (array_key_exists('max', $this->cardinality[$k]) && count($v) > $this->cardinality[$k]['max']) {
+                if ($this->cardinality[$k]['warn']) {
+                    \SimpleSAML\Logger::warning(
+                        sprintf(
+                            'Cardinality: attribute %s from %s does not meet maximum cardinality of %d (%d)',
+                            $k,
+                            $entityid,
+                            $this->cardinality[$k]['max'],
+                            count($v)
+                        )
+                    );
+                } else {
+                    $request['core:cardinality:errorAttributes'][$k] = [
+                        count($v),
+                        $this->cardinality[$k]['_expr']
+                    ];
+                }
+                continue;
+            }
+        }
+
+        /* check for missing attributes with a minimum cardinality */
+        foreach ($this->cardinality as $k => $v) {
+            if (!$this->cardinality[$k]['min'] || array_key_exists($k, $request['Attributes'])) {
+                continue;
+            }
+            if ($this->cardinality[$k]['warn']) {
+                \SimpleSAML\Logger::warning(sprintf(
+                    'Cardinality: attribute %s from %s is missing',
+                    $k,
+                    $entityid
+                ));
+            } else {
+                $request['core:cardinality:errorAttributes'][$k] = [
+                    0,
+                    $this->cardinality[$k]['_expr']
+                ];
+            }
+        }
+
+        /* abort if we found a problematic attribute */
+        if (array_key_exists('core:cardinality:errorAttributes', $request)) {
+            $id = \SimpleSAML\Auth\State::saveState($request, 'core:cardinality');
+            $url = \SimpleSAML\Module::getModuleURL('core/cardinality_error.php');
+            $this->http->redirectTrustedURL($url, ['StateId' => $id]);
+            return;
+        }
+    }
+}
diff --git a/modules/core/lib/Auth/Process/CardinalitySingle.php b/modules/core/lib/Auth/Process/CardinalitySingle.php
new file mode 100644
index 0000000000000000000000000000000000000000..ac251319beef8ffe40c2e15e3da4db498bd4798b
--- /dev/null
+++ b/modules/core/lib/Auth/Process/CardinalitySingle.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace SimpleSAML\Module\core\Auth\Process;
+
+use SimpleSAML\Utils\HttpAdapter;
+
+/**
+ * Filter to ensure correct cardinality of single-valued attributes
+ *
+ * This filter implements a special case of the core:Cardinality filter, and
+ * allows for optional corrections to be made when cardinality errors are encountered.
+ *
+ * @author Guy Halse, http://orcid.org/0000-0002-9388-8592
+ * @package SimpleSAMLphp
+ */
+
+class CardinalitySingle extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /** @var array Attributes that should be single-valued or we generate an error */
+    private $singleValued = [];
+
+    /** @var array Attributes for which the first value should be taken */
+    private $firstValue = [];
+
+    /** @var array Attributes that can be flattened to a single value */
+    private $flatten = [];
+
+    /** @var string Separator for flattened value */
+    private $flattenWith = ';';
+
+    /** @var array Entities that should be ignored */
+    private $ignoreEntities = [];
+
+    /** @var HTTPAdapter */
+    private $http;
+
+    /**
+     * Initialize this filter, parse configuration.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     * @param HTTPAdapter $http  HTTP utility service (handles redirects).
+     */
+    public function __construct($config, $reserved, HttpAdapter $http = null)
+    {
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
+
+        $this->http = $http ? : new HttpAdapter();
+
+        if (array_key_exists('singleValued', $config)) {
+            $this->singleValued = $config['singleValued'];
+        }
+        if (array_key_exists('firstValue', $config)) {
+            $this->firstValue = $config['firstValue'];
+        }
+        if (array_key_exists('flattenWith', $config)) {
+            if (is_array($config['flattenWith'])) {
+                $this->flattenWith = array_shift($config['flattenWith']);
+            } else {
+                $this->flattenWith = $config['flattenWith'];
+            }
+        }
+        if (array_key_exists('flatten', $config)) {
+            $this->flatten = $config['flatten'];
+        }
+        if (array_key_exists('ignoreEntities', $config)) {
+            $this->ignoreEntities = $config['ignoreEntities'];
+        }
+        /* for consistency with core:Cardinality */
+        if (array_key_exists('%ignoreEntities', $config)) {
+            $this->ignoreEntities = $config['%ignoreEntities'];
+        }
+    }
+
+    /**
+     * Process this filter
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists("Attributes", $request));
+
+        if (array_key_exists('Source', $request) &&
+            array_key_exists('entityid', $request['Source']) &&
+            in_array($request['Source']['entityid'], $this->ignoreEntities, true)
+        ) {
+            \SimpleSAML\Logger::debug('CardinalitySingle: Ignoring assertions from '.$request['Source']['entityid']);
+            return;
+        }
+
+        foreach ($request['Attributes'] as $k => $v) {
+            if (!is_array($v)) {
+                continue;
+            }
+            if (count($v) <= 1) {
+                continue;
+            }
+
+            if (in_array($k, $this->singleValued)) {
+                $request['core:cardinality:errorAttributes'][$k] = [count($v), '0 ≤ n ≤ 1'];
+                continue;
+            }
+            if (in_array($k, $this->firstValue)) {
+                $request['Attributes'][$k] = [array_shift($v)];
+                continue;
+            }
+            if (in_array($k, $this->flatten)) {
+                $request['Attributes'][$k] = [implode($this->flattenWith, $v)];
+                continue;
+            }
+        }
+
+        /* abort if we found a problematic attribute */
+        if (array_key_exists('core:cardinality:errorAttributes', $request)) {
+            $id = \SimpleSAML\Auth\State::saveState($request, 'core:cardinality');
+            $url = \SimpleSAML\Module::getModuleURL('core/cardinality_error.php');
+            $this->http->redirectTrustedURL($url, ['StateId' => $id]);
+            return;
+        }
+    }
+}
diff --git a/modules/core/lib/Auth/Process/ExtendIdPSession.php b/modules/core/lib/Auth/Process/ExtendIdPSession.php
index faca137a8a80ec1e84ae609d7cb9da09fa38ca6e..92102262b572ee8d0b0bfb07e35ef011c106c9a8 100644
--- a/modules/core/lib/Auth/Process/ExtendIdPSession.php
+++ b/modules/core/lib/Auth/Process/ExtendIdPSession.php
@@ -1,47 +1,52 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Extend IdP session and cookies.
-*/
-class sspmod_core_Auth_Process_ExtendIdPSession extends SimpleSAML_Auth_ProcessingFilter {
-
-	public function process(&$state) {
-		assert(is_array($state));
-
-		if (empty($state['Expire']) || empty($state['Authority'])) {
-			return;
-		}
-
-		$now = time();
-		$delta = $state['Expire'] - $now;
-
-		$globalConfig = SimpleSAML_Configuration::getInstance();
-		$sessionDuration = $globalConfig->getInteger('session.duration', 8*60*60);
-
-		// Extend only if half of session duration already passed
-		if ($delta >= ($sessionDuration * 0.5)) {
-			return;
-		}
-
-		// Update authority expire time
-		$session = SimpleSAML_Session::getSessionFromRequest();
-		$session->setAuthorityExpire($state['Authority']);
-
-		/* Update session cookies duration */
-
-		/* If remember me is active */
-		$rememberMeExpire = $session->getRememberMeExpire();
-		if (!empty($state['RememberMe']) && $rememberMeExpire !== NULL && $globalConfig->getBoolean('session.rememberme.enable', FALSE)) {
-			$session->setRememberMeExpire();
-			return;
-		}
-
-		/* Or if session lifetime is more than zero */
-		$sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
-		$cookieParams = $sessionHandler->getCookieParams();
-		if ($cookieParams['lifetime'] > 0) {
-			$session->updateSessionCookies();
-		}
-	}
-
+ */
+
+class ExtendIdPSession extends \SimpleSAML\Auth\ProcessingFilter
+{
+    public function process(&$state)
+    {
+        assert(is_array($state));
+
+        if (empty($state['Expire']) || empty($state['Authority'])) {
+            return;
+        }
+
+        $now = time();
+        $delta = $state['Expire'] - $now;
+
+        $globalConfig = \SimpleSAML\Configuration::getInstance();
+        $sessionDuration = $globalConfig->getInteger('session.duration', 28800); // 8*60*60
+
+        // Extend only if half of session duration already passed
+        if ($delta >= ($sessionDuration * 0.5)) {
+            return;
+        }
+
+        // Update authority expire time
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $session->setAuthorityExpire($state['Authority']);
+
+        // Update session cookies duration
+
+        // If remember me is active
+        $rememberMeExpire = $session->getRememberMeExpire();
+        if (!empty($state['RememberMe']) && $rememberMeExpire !== null &&
+            $globalConfig->getBoolean('session.rememberme.enable', false)
+        ) {
+            $session->setRememberMeExpire();
+            return;
+        }
+
+        // Or if session lifetime is more than zero
+        $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+        $cookieParams = $sessionHandler->getCookieParams();
+        if ($cookieParams['lifetime'] > 0) {
+            $session->updateSessionCookies();
+        }
+    }
 }
diff --git a/modules/core/lib/Auth/Process/GenerateGroups.php b/modules/core/lib/Auth/Process/GenerateGroups.php
index 17b896e5f28e17f2221f4a9791833cd383d21e3c..ab9d15aad0498e93e46fc9f4e2552455b9529912 100644
--- a/modules/core/lib/Auth/Process/GenerateGroups.php
+++ b/modules/core/lib/Auth/Process/GenerateGroups.php
@@ -1,142 +1,144 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter to generate a groups attribute based on many of the attributes of the user.
  *
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_GenerateGroups extends SimpleSAML_Auth_ProcessingFilter {
-
-
-	/**
-	 * The attributes we should generate groups from.
-	 */
-	private $generateGroupsFrom;
-
-
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
-
-		if (count($config) === 0) {
-			// Use default groups
-			$this->generateGroupsFrom = array(
-				'eduPersonAffiliation',
-				'eduPersonOrgUnitDN',
-				'eduPersonEntitlement',
-			);
-
-		} else {
-			// Validate configuration
-			foreach ($config as $attributeName) {
-				if (!is_string($attributeName)) {
-					throw new Exception('Invalid attribute name for core:GenerateGroups filter: ' .
-						var_export($attributeName, TRUE));
-				}
-			}
-
-			$this->generateGroupsFrom = $config;
-		}
-	}
-
-
-	/**
-	 * Apply filter to add groups attribute.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		$groups = array();
-		$attributes =& $request['Attributes'];
-
-		$realm = self::getRealm($attributes);
-		if ($realm !== NULL) {
-			$groups[] = 'realm-' . $realm;
-		}
-
-
-		foreach ($this->generateGroupsFrom as $name) {
-			if (!array_key_exists($name, $attributes)) {
-				SimpleSAML\Logger::debug('GenerateGroups - attribute \'' . $name . '\' not found.');
-				/* Attribute not present. */
-				continue;
-			}
-
-			foreach ($attributes[$name] as $value) {
-				$value = self::escapeIllegalChars($value);
-				$groups[] = $name . '-' . $value;
-				if ($realm !== NULL) {
-					$groups[] = $name . '-' . $realm . '-' . $value;
-				}
-			}
-		}
-
-		if (count($groups) > 0) {
-			$attributes['groups'] = $groups;
-		}
-	}
-
-
-	/**
-	 * Determine which realm the user belongs to.
-	 *
-	 * This function will attempt to determine the realm a user belongs to based on the
-	 * eduPersonPrincipalName attribute if it is present. If it isn't, or if it doesn't contain
-	 * a realm, NULL will be returned.
-	 *
-	 * @param array $attributes  The attributes of the user.
-	 * @return string|NULL  The realm of the user, or NULL if we are unable to determine the realm.
-	 */
-	private static function getRealm($attributes) {
-		assert(is_array($attributes));
-
-		if (!array_key_exists('eduPersonPrincipalName', $attributes)) {
-			return NULL;
-		}
-		$eppn = $attributes['eduPersonPrincipalName'];
-
-		if (count($eppn) < 1) {
-			return NULL;
-		}
-		$eppn = $eppn[0];
-
-		$realm = explode('@', $eppn, 2);
-		if (count($realm) < 2) {
-			return NULL;
-		}
-		$realm = $realm[1];
-
-		return self::escapeIllegalChars($realm);
-	}
-
-
-	/**
-	 * Escape special characters in a string.
-	 *
-	 * This function is similar to urlencode, but encodes many more characters.
-	 * This function takes any characters not in [a-zA-Z0-9_@=.] and encodes them with as
-	 * %<hex version>. For example, it will encode '+' as '%2b' and '%' as '%25'.
-	 *
-	 * @param string $string  The string which should be escaped.
-	 * @return string  The escaped string.
-	 */
-	private static function escapeIllegalChars($string) {
-		assert(is_string($string));
-
-		return preg_replace_callback('/([^a-zA-Z0-9_@=.])/',
-			function ($m) { return sprintf("%%%02x", ord($m[1])); },
-			$string);
-	}
 
+class GenerateGroups extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * The attributes we should generate groups from.
+     */
+    private $generateGroupsFrom;
+
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        if (count($config) === 0) {
+            // Use default groups
+            $this->generateGroupsFrom = [
+                'eduPersonAffiliation',
+                'eduPersonOrgUnitDN',
+                'eduPersonEntitlement',
+            ];
+        } else {
+            // Validate configuration
+            foreach ($config as $attributeName) {
+                if (!is_string($attributeName)) {
+                    throw new \Exception('Invalid attribute name for core:GenerateGroups filter: '.
+                        var_export($attributeName, true));
+                }
+            }
+            $this->generateGroupsFrom = $config;
+        }
+    }
+
+    /**
+     * Apply filter to add groups attribute.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        $groups = [];
+        $attributes = &$request['Attributes'];
+
+        $realm = self::getRealm($attributes);
+        if ($realm !== null) {
+            $groups[] = 'realm-'.$realm;
+        }
+
+        foreach ($this->generateGroupsFrom as $name) {
+            if (!array_key_exists($name, $attributes)) {
+                \SimpleSAML\Logger::debug('GenerateGroups - attribute \''.$name.'\' not found.');
+                // Attribute not present
+                continue;
+            }
+
+            foreach ($attributes[$name] as $value) {
+                $value = self::escapeIllegalChars($value);
+                $groups[] = $name.'-'.$value;
+                if ($realm !== null) {
+                    $groups[] = $name.'-'.$realm.'-'.$value;
+                }
+            }
+        }
+
+        if (count($groups) > 0) {
+            $attributes['groups'] = $groups;
+        }
+    }
+
+    /**
+     * Determine which realm the user belongs to.
+     *
+     * This function will attempt to determine the realm a user belongs to based on the
+     * eduPersonPrincipalName attribute if it is present. If it isn't, or if it doesn't contain
+     * a realm, NULL will be returned.
+     *
+     * @param array $attributes  The attributes of the user.
+     * @return string|NULL  The realm of the user, or NULL if we are unable to determine the realm.
+     */
+    private static function getRealm($attributes)
+    {
+        assert(is_array($attributes));
+
+        if (!array_key_exists('eduPersonPrincipalName', $attributes)) {
+            return null;
+        }
+        $eppn = $attributes['eduPersonPrincipalName'];
+
+        if (count($eppn) < 1) {
+            return null;
+        }
+        $eppn = $eppn[0];
+
+        $realm = explode('@', $eppn, 2);
+        if (count($realm) < 2) {
+            return null;
+        }
+        $realm = $realm[1];
+
+        return self::escapeIllegalChars($realm);
+    }
+
+    /**
+     * Escape special characters in a string.
+     *
+     * This function is similar to urlencode, but encodes many more characters.
+     * This function takes any characters not in [a-zA-Z0-9_@=.] and encodes them with as
+     * %<hex version>. For example, it will encode '+' as '%2b' and '%' as '%25'.
+     *
+     * @param string $string  The string which should be escaped.
+     * @return string  The escaped string.
+     */
+    private static function escapeIllegalChars($string)
+    {
+        assert(is_string($string));
+
+        return preg_replace_callback(
+            '/([^a-zA-Z0-9_@=.])/',
+            function ($m) {
+                return sprintf("%%%02x", ord($m[1]));
+            },
+            $string
+        );
+    }
 }
diff --git a/modules/core/lib/Auth/Process/LanguageAdaptor.php b/modules/core/lib/Auth/Process/LanguageAdaptor.php
index 4a1b381405255b2f441089e95f5595db24243326..771fb6357216575621aeaa067b77036e77c34e3a 100644
--- a/modules/core/lib/Auth/Process/LanguageAdaptor.php
+++ b/modules/core/lib/Auth/Process/LanguageAdaptor.php
@@ -1,66 +1,68 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter to set and get language settings from attributes.
  *
  * @author Andreas Ă…kre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_LanguageAdaptor extends SimpleSAML_Auth_ProcessingFilter {
-
-	private $langattr = 'preferredLanguage';
-
-
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-		assert(is_array($config));
-
-		if (array_key_exists('attributename', $config)) {
-			$this->langattr = $config['attributename'];
-		}
-	}
-
-
-	/**
-	 * Apply filter to add or replace attributes.
-	 *
-	 * Add or replace existing attributes with the configured values.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		$attributes =& $request['Attributes'];
-
-		$attrlang = NULL;
-		if (array_key_exists($this->langattr, $attributes))
-			$attrlang = $attributes[$this->langattr][0];
-
-		$lang = SimpleSAML\Locale\Language::getLanguageCookie();
-
-
-		if (isset($attrlang))
-			SimpleSAML\Logger::debug('LanguageAdaptor: Language in attribute was set [' . $attrlang . ']');
-		if (isset($lang))
-			SimpleSAML\Logger::debug('LanguageAdaptor: Language in session   was set [' . $lang . ']');
-
-
-		if (isset($attrlang) && !isset($lang)) {
-			// Language set in attribute but not in cookie - update cookie
-			SimpleSAML\Locale\Language::setLanguageCookie($attrlang);
-		} elseif (!isset($attrlang) && isset($lang)) {
-			// Language set in cookie, but not in attribute. Update attribute
-			$request['Attributes'][$this->langattr] = array($lang);
-		}
-
-	}
 
+class LanguageAdaptor extends \SimpleSAML\Auth\ProcessingFilter
+{
+    private $langattr = 'preferredLanguage';
+
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
+
+        if (array_key_exists('attributename', $config)) {
+            $this->langattr = $config['attributename'];
+        }
+    }
+
+    /**
+     * Apply filter to add or replace attributes.
+     *
+     * Add or replace existing attributes with the configured values.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        $attributes = &$request['Attributes'];
+
+        $attrlang = null;
+        if (array_key_exists($this->langattr, $attributes)) {
+            $attrlang = $attributes[$this->langattr][0];
+        }
+
+        $lang = \SimpleSAML\Locale\Language::getLanguageCookie();
+
+        if (isset($attrlang)) {
+            \SimpleSAML\Logger::debug('LanguageAdaptor: Language in attribute was set ['.$attrlang.']');
+        }
+        if (isset($lang)) {
+            \SimpleSAML\Logger::debug('LanguageAdaptor: Language in session   was set ['.$lang.']');
+        }
+
+        if (isset($attrlang) && !isset($lang)) {
+            // Language set in attribute but not in cookie - update cookie
+            \SimpleSAML\Locale\Language::setLanguageCookie($attrlang);
+        } elseif (!isset($attrlang) && isset($lang)) {
+            // Language set in cookie, but not in attribute. Update attribute
+            $request['Attributes'][$this->langattr] = [$lang];
+        }
+    }
 }
diff --git a/modules/core/lib/Auth/Process/PHP.php b/modules/core/lib/Auth/Process/PHP.php
index 5b7f11711bc8507b2dbc68e55d37eebafbe7ed17..cd424c76e9a01e1b4705eb217014eab2c9ec5ed1 100644
--- a/modules/core/lib/Auth/Process/PHP.php
+++ b/modules/core/lib/Auth/Process/PHP.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
 
 /**
  * Attribute filter for running arbitrary PHP code.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_PHP extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class PHP extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * The PHP code that should be run.
      *
@@ -23,7 +24,7 @@ class sspmod_core_Auth_Process_PHP extends SimpleSAML_Auth_ProcessingFilter
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception if the 'code' option is not defined.
+     * @throws \SimpleSAML\Error\Exception if the 'code' option is not defined.
      */
     public function __construct($config, $reserved)
     {
@@ -32,7 +33,7 @@ class sspmod_core_Auth_Process_PHP extends SimpleSAML_Auth_ProcessingFilter
         assert(is_array($config));
 
         if (!isset($config['code'])) {
-            throw new SimpleSAML_Error_Exception("core:PHP: missing mandatory configuration option 'code'.");
+            throw new \SimpleSAML\Error\Exception("core:PHP: missing mandatory configuration option 'code'.");
         }
         $this->code = (string) $config['code'];
     }
@@ -48,7 +49,12 @@ class sspmod_core_Auth_Process_PHP extends SimpleSAML_Auth_ProcessingFilter
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
 
-        $function = function(&$attributes) { eval($this->code); };
-        $function($request['Attributes']);
+        $function = function (
+            /** @scrutinizer ignore-unused */ &$attributes,
+            /** @scrutinizer ignore-unused */ &$state
+        ) {
+            eval($this->code);
+        };
+        $function($request['Attributes'], $request);
     }
 }
diff --git a/modules/core/lib/Auth/Process/ScopeAttribute.php b/modules/core/lib/Auth/Process/ScopeAttribute.php
index a44ff14de75b7a519af8887da99d309321affb3d..1db7d3c18a1bf3dd3f1f4cc1a3d1cc1bd090d7d7 100644
--- a/modules/core/lib/Auth/Process/ScopeAttribute.php
+++ b/modules/core/lib/Auth/Process/ScopeAttribute.php
@@ -1,107 +1,106 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Add a scoped variant of an attribute.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_ScopeAttribute extends SimpleSAML_Auth_ProcessingFilter
+
+class ScopeAttribute extends \SimpleSAML\Auth\ProcessingFilter
 {
-	/**
-	 * The attribute we extract the scope from.
-	 *
-	 * @var string
-	 */
-	private $scopeAttribute;
-
-
-	/**
-	 * The attribute we want to add scope to.
-	 *
-	 * @var string
-	 */
-	private $sourceAttribute;
-
-
-	/**
-	 * The attribute we want to add the scoped attributes to.
-	 *
-	 * @var string
-	 */
-	private $targetAttribute;
-
-	/**
-	 * Only modify targetAttribute if it doesn't already exist.
-	 *
-	 * @var bool
-	 */
-	private $onlyIfEmpty = false;
-
-
-	/**
-	 * Initialize this filter, parse configuration
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved)
+    /**
+     * The attribute we extract the scope from.
+     *
+     * @var string
+     */
+    private $scopeAttribute;
+
+    /**
+     * The attribute we want to add scope to.
+     *
+     * @var string
+     */
+    private $sourceAttribute;
+
+    /**
+     * The attribute we want to add the scoped attributes to.
+     *
+     * @var string
+     */
+    private $targetAttribute;
+
+    /**
+     * Only modify targetAttribute if it doesn't already exist.
+     *
+     * @var bool
+     */
+    private $onlyIfEmpty = false;
+
+    /**
+     * Initialize this filter, parse configuration
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
     {
-		parent::__construct($config, $reserved);
-		assert(is_array($config));
-
-		$config = SimpleSAML_Configuration::loadFromArray($config, 'ScopeAttribute');
-
-		$this->scopeAttribute = $config->getString('scopeAttribute');
-		$this->sourceAttribute = $config->getString('sourceAttribute');
-		$this->targetAttribute = $config->getString('targetAttribute');
-		$this->onlyIfEmpty = $config->getBoolean('onlyIfEmpty', false);
-	}
-
-
-	/**
-	 * Apply this filter to the request.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request)
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
+
+        $config = \SimpleSAML\Configuration::loadFromArray($config, 'ScopeAttribute');
+
+        $this->scopeAttribute = $config->getString('scopeAttribute');
+        $this->sourceAttribute = $config->getString('sourceAttribute');
+        $this->targetAttribute = $config->getString('targetAttribute');
+        $this->onlyIfEmpty = $config->getBoolean('onlyIfEmpty', false);
+    }
+
+    /**
+     * Apply this filter to the request.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
     {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
 
-		$attributes =& $request['Attributes'];
+        $attributes = &$request['Attributes'];
 
-		if (!isset($attributes[$this->scopeAttribute])) {
-			return;
-		}
+        if (!isset($attributes[$this->scopeAttribute])) {
+            return;
+        }
 
-		if (!isset($attributes[$this->sourceAttribute])) {
-			return;
-		}
+        if (!isset($attributes[$this->sourceAttribute])) {
+            return;
+        }
 
-		if (!isset($attributes[$this->targetAttribute])) {
-			$attributes[$this->targetAttribute] = array();
-		}
+        if (!isset($attributes[$this->targetAttribute])) {
+            $attributes[$this->targetAttribute] = [];
+        }
 
-		if ($this->onlyIfEmpty && count($attributes[$this->targetAttribute]) > 0) {
-			return;
-		}
+        if ($this->onlyIfEmpty && count($attributes[$this->targetAttribute]) > 0) {
+            return;
+        }
 
-		foreach ($attributes[$this->scopeAttribute] as $scope) {
-			if (strpos($scope, '@') !== false) {
-				$scope = explode('@', $scope, 2);
-				$scope = $scope[1];
-			}
+        foreach ($attributes[$this->scopeAttribute] as $scope) {
+            if (strpos($scope, '@') !== false) {
+                $scope = explode('@', $scope, 2);
+                $scope = $scope[1];
+            }
 
-			foreach ($attributes[$this->sourceAttribute] as $value) {
-				$value = $value . '@' . $scope;
+            foreach ($attributes[$this->sourceAttribute] as $value) {
+                $value = $value.'@'.$scope;
 
-				if (in_array($value, $attributes[$this->targetAttribute], true)) {
-					// Already present
-					continue;
-				}
+                if (in_array($value, $attributes[$this->targetAttribute], true)) {
+                    // Already present
+                    continue;
+                }
 
-				$attributes[$this->targetAttribute][] = $value;
-			}
-		}
-	}
+                $attributes[$this->targetAttribute][] = $value;
+            }
+        }
+    }
 }
diff --git a/modules/core/lib/Auth/Process/ScopeFromAttribute.php b/modules/core/lib/Auth/Process/ScopeFromAttribute.php
index 818a24f7657bfcfb77e5bba86ce54790f0056db8..b043de9fd86a0c58ba16e8d332b730c26ded02f6 100644
--- a/modules/core/lib/Auth/Process/ScopeFromAttribute.php
+++ b/modules/core/lib/Auth/Process/ScopeFromAttribute.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Retrieve a scope from a source attribute and add it as a virtual target
  * attribute.
@@ -16,74 +18,77 @@
  * to add a virtual 'scope' attribute from the eduPersonPrincipalName
  * attribute.
  */
-class sspmod_core_Auth_Process_ScopeFromAttribute extends SimpleSAML_Auth_ProcessingFilter {
-	/**
-	 * The attribute where the scope is taken from
-	 *
-	 * @var string
-	 */
-	private $sourceAttribute;
-	/**
-	 * The name of the attribute which includes the scope
-	 *
-	 * @var string
-	 */
-	private $targetAttribute;
 
-	/**
-	 * Initialize this filter, parse configuration
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-		assert(is_array($config));
+class ScopeFromAttribute extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * The attribute where the scope is taken from
+     *
+     * @var string
+     */
+    private $sourceAttribute;
+
+    /**
+     * The name of the attribute which includes the scope
+     *
+     * @var string
+     */
+    private $targetAttribute;
 
-		$config = SimpleSAML_Configuration::loadFromArray($config, 'ScopeFromAttribute');
-		$this->targetAttribute = $config->getString('targetAttribute');
-		$this->sourceAttribute = $config->getString('sourceAttribute');
-	} // end constructor
+    /**
+     * Initialize this filter, parse configuration
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
 
+        $config = \SimpleSAML\Configuration::loadFromArray($config, 'ScopeFromAttribute');
+        $this->targetAttribute = $config->getString('targetAttribute');
+        $this->sourceAttribute = $config->getString('sourceAttribute');
+    } // end constructor
 
-	/**
-	 * Apply this filter.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
+    /**
+     * Apply this filter.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
 
-		$attributes =& $request['Attributes'];
+        $attributes = &$request['Attributes'];
 
-		if (!isset($attributes[$this->sourceAttribute])) {
-			return;
-		}
+        if (!isset($attributes[$this->sourceAttribute])) {
+            return;
+        }
 
-		// will not overwrite existing attribute
-		if (isset($attributes[$this->targetAttribute])) {
-			return;
-		}
+        // will not overwrite existing attribute
+        if (isset($attributes[$this->targetAttribute])) {
+            return;
+        }
 
-		$sourceAttrVal = $attributes[$this->sourceAttribute][0];
+        $sourceAttrVal = $attributes[$this->sourceAttribute][0];
 
-		/* the last position of an @ is usually the beginning of the scope
-		 * string */
-		$scopeIndex = strrpos($sourceAttrVal, '@');
+        /* the last position of an @ is usually the beginning of the
+         * scope string
+         */
+        $scopeIndex = strrpos($sourceAttrVal, '@');
 
-		if ($scopeIndex !== FALSE) {
-			$attributes[$this->targetAttribute] = array();
-			$scope = substr($sourceAttrVal, $scopeIndex+1);
-			$attributes[$this->targetAttribute][] = $scope;
-			SimpleSAML\Logger::debug('ScopeFromAttribute: Inserted new attribute ' .
-			                         $this->targetAttribute . ', with scope ' .
-			                         $scope);
-		} else {
-			SimpleSAML\Logger::warning('ScopeFromAttribute: The configured source attribute ' .
-			                           $this->sourceAttribute .
-			                           ' does not have a scope. Did not add attribute ' .
-			                           $this->targetAttribute . '.');
-		}
-	} /* end process */
+        if ($scopeIndex !== false) {
+            $attributes[$this->targetAttribute] = [];
+            $scope = substr($sourceAttrVal, $scopeIndex + 1);
+            $attributes[$this->targetAttribute][] = $scope;
+            \SimpleSAML\Logger::debug('ScopeFromAttribute: Inserted new attribute '.
+                $this->targetAttribute.', with scope '.$scope);
+        } else {
+            \SimpleSAML\Logger::warning('ScopeFromAttribute: The configured source attribute '.
+                $this->sourceAttribute.' does not have a scope. Did not add attribute '.
+                    $this->targetAttribute.'.');
+        }
+    } // end process
 }
diff --git a/modules/core/lib/Auth/Process/StatisticsWithAttribute.php b/modules/core/lib/Auth/Process/StatisticsWithAttribute.php
index 800558cbd51b32f28bc307304c81d5326cecc23c..86db3063c575396706a4373d8ba5f8db9bc3b3d6 100644
--- a/modules/core/lib/Auth/Process/StatisticsWithAttribute.php
+++ b/modules/core/lib/Auth/Process/StatisticsWithAttribute.php
@@ -1,18 +1,21 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Log a line in the STAT log with one attribute.
  *
  * @author Andreas Ă…kre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_StatisticsWithAttribute extends SimpleSAML_Auth_ProcessingFilter
+
+class StatisticsWithAttribute extends \SimpleSAML\Auth\ProcessingFilter
 {
     /**
      * The attribute to log
      * @var string|null
      */
-	private $attribute = null;
+    private $attribute = null;
 
     /**
      * @var string
@@ -40,14 +43,14 @@ class sspmod_core_Auth_Process_StatisticsWithAttribute extends SimpleSAML_Auth_P
         if (array_key_exists('attributename', $config)) {
             $this->attribute = $config['attributename'];
             if (!is_string($this->attribute)) {
-                throw new Exception('Invalid attribute name given to core:StatisticsWithAttribute filter.');
+                throw new \Exception('Invalid attribute name given to core:StatisticsWithAttribute filter.');
             }
         }
 
         if (array_key_exists('type', $config)) {
             $this->typeTag = $config['type'];
             if (!is_string($this->typeTag)) {
-                throw new Exception('Invalid typeTag given to core:StatisticsWithAttribute filter.');
+                throw new \Exception('Invalid typeTag given to core:StatisticsWithAttribute filter.');
             }
         }
 
@@ -87,11 +90,11 @@ class sspmod_core_Auth_Process_StatisticsWithAttribute extends SimpleSAML_Auth_P
 
         if (!array_key_exists('PreviousSSOTimestamp', $state)) {
             // The user hasn't authenticated with this SP earlier in this session
-            SimpleSAML\Logger::stats($isPassive.$this->typeTag.'-first '.$dest.' '.$source.' '. $logAttribute);
+            \SimpleSAML\Logger::stats($isPassive.$this->typeTag.'-first '.$dest.' '.$source.' '.$logAttribute);
         }
 
-        SimpleSAML\Logger::stats($isPassive.$this->typeTag.' '.$dest.' '.$source.' '.$logAttribute);
-	}
+        \SimpleSAML\Logger::stats($isPassive.$this->typeTag.' '.$dest.' '.$source.' '.$logAttribute);
+    }
 
     /**
      * @param string &$direction  Either 'Source' or 'Destination'.
diff --git a/modules/core/lib/Auth/Process/TargetedID.php b/modules/core/lib/Auth/Process/TargetedID.php
index 3b70f02aa4ad20a7468862fa6c3ff89be8ec236a..5ea29bec74a42d27d769e0c8c412f99b240761c8 100644
--- a/modules/core/lib/Auth/Process/TargetedID.php
+++ b/modules/core/lib/Auth/Process/TargetedID.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Filter to generate the eduPersonTargetedID attribute.
  *
@@ -28,145 +30,143 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_TargetedID extends SimpleSAML_Auth_ProcessingFilter {
-
-
-	/**
-	 * The attribute we should generate the targeted id from, or NULL if we should use the
-	 * UserID.
-	 */
-	private $attribute = NULL;
-
-
-	/**
-	 * Whether the attribute should be generated as a NameID value, or as a simple string.
-	 *
-	 * @var boolean
-	 */
-	private $generateNameId = FALSE;
-
-
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
-
-		if (array_key_exists('attributename', $config)) {
-			$this->attribute = $config['attributename'];
-			if (!is_string($this->attribute)) {
-				throw new Exception('Invalid attribute name given to core:TargetedID filter.');
-			}
-		}
-
-		if (array_key_exists('nameId', $config)) {
-			$this->generateNameId = $config['nameId'];
-			if (!is_bool($this->generateNameId)) {
-				throw new Exception('Invalid value of \'nameId\'-option to core:TargetedID filter.');
-			}
-		}
-	}
-
-
-	/**
-	 * Apply filter to add the targeted ID.
-	 *
-	 * @param array &$state  The current state.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-		assert(array_key_exists('Attributes', $state));
-
-		if ($this->attribute === NULL) {
-			if (!array_key_exists('UserID', $state)) {
-				throw new Exception('core:TargetedID: Missing UserID for this user. Please' .
-					' check the \'userid.attribute\' option in the metadata against the' .
-					' attributes provided by the authentication source.');
-			}
-
-			$userID = $state['UserID'];
-		} else {
-			if (!array_key_exists($this->attribute, $state['Attributes'])) {
-				throw new Exception('core:TargetedID: Missing attribute \'' . $this->attribute .
-					'\', which is needed to generate the targeted ID.');
-			}
-
-			$userID = $state['Attributes'][$this->attribute][0];
-		}
-
-
-		$secretSalt = SimpleSAML\Utils\Config::getSecretSalt();
-
-		if (array_key_exists('Source', $state)) {
-			$srcID = self::getEntityId($state['Source']);
-		} else {
-			$srcID = '';
-		}
-
-		if (array_key_exists('Destination', $state)) {
-			$dstID = self::getEntityId($state['Destination']);
-		} else {
-			$dstID = '';
-		}
-
-		$uidData = 'uidhashbase' . $secretSalt;
-		$uidData .= strlen($srcID) . ':' . $srcID;
-		$uidData .= strlen($dstID) . ':' . $dstID;
-		$uidData .= strlen($userID) . ':' . $userID;
-		$uidData .= $secretSalt;
-
-		$uid = hash('sha1', $uidData);
-
-		if ($this->generateNameId) {
-			// Convert the targeted ID to a SAML 2.0 name identifier element
-			$nameId = new \SAML2\XML\saml\NameID();
-			$nameId->value = $uid;
-			$nameId->Format = \SAML2\Constants::NAMEID_PERSISTENT;
-
-			if (isset($state['Source']['entityid'])) {
-				$nameId->NameQualifier = $state['Source']['entityid'];
-			}
-			if (isset($state['Destination']['entityid'])) {
-				$nameId->SPNameQualifier = $state['Destination']['entityid'];
-			}
-		} else {
-			$nameId = $uid;
-		}
-
-		$state['Attributes']['eduPersonTargetedID'] = array($nameId);
-	}
-
-
-	/**
-	 * Generate ID from entity metadata.
-	 *
-	 * This function takes in the metadata of an entity, and attempts to generate
-	 * an unique identifier based on that.
-	 *
-	 * @param array $metadata  The metadata of the entity.
-	 * @return string  The unique identifier for the entity.
-	 */
-	private static function getEntityId($metadata) {
-		assert(is_array($metadata));
-
-		$id = '';
-
-		if (array_key_exists('metadata-set', $metadata)) {
-			$set = $metadata['metadata-set'];
-			$id .= 'set' . strlen($set) . ':' . $set;
-		}
-
-		if (array_key_exists('entityid', $metadata)) {
-			$entityid = $metadata['entityid'];
-			$id .= 'set' . strlen($entityid) . ':' . $entityid;
-		}
-
-		return $id;
-	}
 
+class TargetedID extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * The attribute we should generate the targeted id from, or NULL if we should use the
+     * UserID.
+     */
+    private $attribute = null;
+
+    /**
+     * Whether the attribute should be generated as a NameID value, or as a simple string.
+     *
+     * @var boolean
+     */
+    private $generateNameId = false;
+
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        if (array_key_exists('attributename', $config)) {
+            $this->attribute = $config['attributename'];
+            if (!is_string($this->attribute)) {
+                throw new \Exception('Invalid attribute name given to core:TargetedID filter.');
+            }
+        }
+
+        if (array_key_exists('nameId', $config)) {
+            $this->generateNameId = $config['nameId'];
+            if (!is_bool($this->generateNameId)) {
+                throw new \Exception('Invalid value of \'nameId\'-option to core:TargetedID filter.');
+            }
+        }
+    }
+
+    /**
+     * Apply filter to add the targeted ID.
+     *
+     * @param array &$state  The current state.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+        assert(array_key_exists('Attributes', $state));
+
+        if ($this->attribute === null) {
+            if (!array_key_exists('UserID', $state)) {
+                throw new \Exception('core:TargetedID: Missing UserID for this user. Please'.
+                    ' check the \'userid.attribute\' option in the metadata against the'.
+                    ' attributes provided by the authentication source.');
+            }
+
+            $userID = $state['UserID'];
+        } else {
+            if (!array_key_exists($this->attribute, $state['Attributes'])) {
+                throw new \Exception('core:TargetedID: Missing attribute \''.$this->attribute.
+                    '\', which is needed to generate the targeted ID.');
+            }
+
+            $userID = $state['Attributes'][$this->attribute][0];
+        }
+
+
+        $secretSalt = \SimpleSAML\Utils\Config::getSecretSalt();
+
+        if (array_key_exists('Source', $state)) {
+            $srcID = self::getEntityId($state['Source']);
+        } else {
+            $srcID = '';
+        }
+
+        if (array_key_exists('Destination', $state)) {
+            $dstID = self::getEntityId($state['Destination']);
+        } else {
+            $dstID = '';
+        }
+
+        $uidData = 'uidhashbase'.$secretSalt;
+        $uidData .= strlen($srcID).':'.$srcID;
+        $uidData .= strlen($dstID).':'.$dstID;
+        $uidData .= strlen($userID).':'.$userID;
+        $uidData .= $secretSalt;
+
+        $uid = hash('sha1', $uidData);
+
+        if ($this->generateNameId) {
+            // Convert the targeted ID to a SAML 2.0 name identifier element
+            $nameId = new \SAML2\XML\saml\NameID();
+            $nameId->value = $uid;
+            $nameId->Format = \SAML2\Constants::NAMEID_PERSISTENT;
+
+            if (isset($state['Source']['entityid'])) {
+                $nameId->NameQualifier = $state['Source']['entityid'];
+            }
+            if (isset($state['Destination']['entityid'])) {
+                $nameId->SPNameQualifier = $state['Destination']['entityid'];
+            }
+        } else {
+            $nameId = $uid;
+        }
+
+        $state['Attributes']['eduPersonTargetedID'] = [$nameId];
+    }
+
+    /**
+     * Generate ID from entity metadata.
+     *
+     * This function takes in the metadata of an entity, and attempts to generate
+     * an unique identifier based on that.
+     *
+     * @param array $metadata  The metadata of the entity.
+     * @return string  The unique identifier for the entity.
+     */
+    private static function getEntityId($metadata)
+    {
+        assert(is_array($metadata));
+
+        $id = '';
+
+        if (array_key_exists('metadata-set', $metadata)) {
+            $set = $metadata['metadata-set'];
+            $id .= 'set'.strlen($set).':'.$set;
+        }
+
+        if (array_key_exists('entityid', $metadata)) {
+            $entityid = $metadata['entityid'];
+            $id .= 'set'.strlen($entityid).':'.$entityid;
+        }
+
+        return $id;
+    }
 }
diff --git a/modules/core/lib/Auth/Process/WarnShortSSOInterval.php b/modules/core/lib/Auth/Process/WarnShortSSOInterval.php
index d8ae6fa0a6e9bda49d7d493aaa00997216296b72..1d488b9db935886a2a2e2359ffddaf10ef3e4e56 100644
--- a/modules/core/lib/Auth/Process/WarnShortSSOInterval.php
+++ b/modules/core/lib/Auth/Process/WarnShortSSOInterval.php
@@ -1,52 +1,53 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Process;
+
 /**
  * Give a warning to the user if we receive multiple requests in a short time.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Process_WarnShortSSOInterval extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Process a authentication response.
-	 *
-	 * This function checks how long it is since the last time the user was authenticated.
-	 * If it is to short a while since, we will show a warning to the user.
-	 *
-	 * @param array $state  The state of the response.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-
-		if (!array_key_exists('PreviousSSOTimestamp', $state)) {
-			/*
-			 * No timestamp from the previous SSO to this SP. This is the first
-			 * time during this session.
-			 */
-			return;
-		}
-
-		$timeDelta = time() - $state['PreviousSSOTimestamp'];
-		if ($timeDelta >= 10) {
-			// At least 10 seconds since last attempt
-			return;
-		}
-
-		if (array_key_exists('Destination', $state)
-			&& array_key_exists('entityid', $state['Destination'])) {
-			$entityId = $state['Destination']['entityid'];
-		} else {
-			$entityId = 'UNKNOWN';
-		}
-
-		SimpleSAML\Logger::warning('WarnShortSSOInterval: Only ' . $timeDelta .
-			' seconds since last SSO for this user from the SP ' .
-			var_export($entityId, TRUE));
-
-		// Save state and redirect
-		$id = SimpleSAML_Auth_State::saveState($state, 'core:short_sso_interval');
-		$url = SimpleSAML\Module::getModuleURL('core/short_sso_interval.php');
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-	}
 
+class WarnShortSSOInterval extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Process a authentication response.
+     *
+     * This function checks how long it is since the last time the user was authenticated.
+     * If it is to short a while since, we will show a warning to the user.
+     *
+     * @param array $state  The state of the response.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+
+        if (!array_key_exists('PreviousSSOTimestamp', $state)) {
+            /*
+             * No timestamp from the previous SSO to this SP. This is the first
+             * time during this session.
+             */
+            return;
+        }
+
+        $timeDelta = time() - $state['PreviousSSOTimestamp'];
+        if ($timeDelta >= 10) {
+            // At least 10 seconds since last attempt
+            return;
+        }
+
+        if (array_key_exists('Destination', $state) && array_key_exists('entityid', $state['Destination'])) {
+            $entityId = $state['Destination']['entityid'];
+        } else {
+            $entityId = 'UNKNOWN';
+        }
+
+        \SimpleSAML\Logger::warning('WarnShortSSOInterval: Only '.$timeDelta.
+            ' seconds since last SSO for this user from the SP '.var_export($entityId, true));
+
+        // Save state and redirect
+        $id = \SimpleSAML\Auth\State::saveState($state, 'core:short_sso_interval');
+        $url = \SimpleSAML\Module::getModuleURL('core/short_sso_interval.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+    }
 }
diff --git a/modules/core/lib/Auth/Source/AdminPassword.php b/modules/core/lib/Auth/Source/AdminPassword.php
index 3ba1a821086d5e290b0149445c323562973429df..45ce4c2696bb2514f9b579fcdf29f8c4dbcc1431 100644
--- a/modules/core/lib/Auth/Source/AdminPassword.php
+++ b/modules/core/lib/Auth/Source/AdminPassword.php
@@ -1,64 +1,65 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth\Source;
+
 /**
  * Authentication source which verifies the password against
  * the 'auth.adminpassword' configuration option.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Auth_Source_AdminPassword extends sspmod_core_Auth_UserPassBase {
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		$this->setForcedUsername("admin");
-	}
 
+class AdminPassword extends \SimpleSAML\Module\core\Auth\UserPassBase
+{
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
 
-	/**
-	 * Attempt to log in using the given username and password.
-	 *
-	 * On a successful login, this function should return the users attributes. On failure,
-	 * it should throw an exception. If the error was caused by the user entering the wrong
-	 * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
-	 *
-	 * Note that both the username and the password are UTF-8 encoded.
-	 *
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 * @return array  Associative array with the users attributes.
-	 */
-	protected function login($username, $password) {
-		assert(is_string($username));
-		assert(is_string($password));
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
 
-		$config = SimpleSAML_Configuration::getInstance();
-		$adminPassword = $config->getString('auth.adminpassword', '123');
-		if ($adminPassword === '123') {
-			// We require that the user changes the password
-			throw new SimpleSAML_Error_Error('NOTSET');
-		}
+        $this->setForcedUsername("admin");
+    }
 
-		if ($username !== "admin") {
-			throw new SimpleSAML_Error_Error('WRONGUSERPASS');
-		}
+    /**
+     * Attempt to log in using the given username and password.
+     *
+     * On a successful login, this function should return the users attributes. On failure,
+     * it should throw an exception. If the error was caused by the user entering the wrong
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
+     *
+     * Note that both the username and the password are UTF-8 encoded.
+     *
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     * @return array  Associative array with the users attributes.
+     */
+    protected function login($username, $password)
+    {
+        assert(is_string($username));
+        assert(is_string($password));
 
-		if (!SimpleSAML\Utils\Crypto::pwValid($adminPassword, $password)) {
-			throw new SimpleSAML_Error_Error('WRONGUSERPASS');
-		}
+        $config = \SimpleSAML\Configuration::getInstance();
+        $adminPassword = $config->getString('auth.adminpassword', '123');
+        if ($adminPassword === '123') {
+            // We require that the user changes the password
+            throw new \SimpleSAML\Error\Error('NOTSET');
+        }
 
-		return array('user' => array('admin'));
-	}
+        if ($username !== "admin") {
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
+        }
 
+        if (!\SimpleSAML\Utils\Crypto::pwValid($adminPassword, $password)) {
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
+        }
+        return ['user' => ['admin']];
+    }
 }
diff --git a/modules/core/lib/Auth/UserPassBase.php b/modules/core/lib/Auth/UserPassBase.php
index bc05f61967cf976ac80f323a148759dfd215a5be..5f0ee4ffa33040da24c254c4f1ffe34fa691d031 100644
--- a/modules/core/lib/Auth/UserPassBase.php
+++ b/modules/core/lib/Auth/UserPassBase.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth;
+
 /**
  * Helper class for username/password authentication.
  *
@@ -9,50 +11,48 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
-
-
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGEID = 'sspmod_core_Auth_UserPassBase.state';
-
-
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'sspmod_core_Auth_UserPassBase.AuthId';
-
-
-	/**
-	 * Username we should force.
-	 *
-	 * A forced username cannot be changed by the user.
-	 * If this is NULL, we won't force any username.
-	 */
-	private $forcedUsername;
-
-	/**
-	 * Links to pages from login page.
-	 * From configuration
-	 */
-	protected $loginLinks;
-
-	/**
-	 * Storage for authsource config option remember.username.enabled
-	 * loginuserpass.php and loginuserpassorg.php pages/templates use this option to
-	 * present users with a checkbox to save their username for the next login request.
-	 * @var bool
-	 */
-	protected $rememberUsernameEnabled = FALSE;
-
-	/**
-	 * Storage for authsource config option remember.username.checked
-	 * loginuserpass.php and loginuserpassorg.php pages/templates use this option
-	 * to default the remember username checkbox to checked or not.
-	 * @var bool
-	 */
-	protected $rememberUsernameChecked = FALSE;
+
+abstract class UserPassBase extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The string used to identify our states.
+     */
+    const STAGEID = '\SimpleSAML\Module\core\Auth\UserPassBase.state';
+
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = '\SimpleSAML\Module\core\Auth\UserPassBase.AuthId';
+
+    /**
+     * Username we should force.
+     *
+     * A forced username cannot be changed by the user.
+     * If this is NULL, we won't force any username.
+     */
+    private $forcedUsername;
+
+    /**
+     * Links to pages from login page.
+     * From configuration
+     */
+    protected $loginLinks;
+
+    /**
+     * Storage for authsource config option remember.username.enabled
+     * loginuserpass.php and loginuserpassorg.php pages/templates use this option to
+     * present users with a checkbox to save their username for the next login request.
+     * @var bool
+     */
+    protected $rememberUsernameEnabled = false;
+
+    /**
+     * Storage for authsource config option remember.username.checked
+     * loginuserpass.php and loginuserpassorg.php pages/templates use this option
+     * to default the remember username checkbox to checked or not.
+     * @var bool
+     */
+    protected $rememberUsernameChecked = false;
 
     /**
      * Storage for general config option session.rememberme.enable.
@@ -62,7 +62,7 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
      * browser again).
      * @var bool
      */
-    protected $rememberMeEnabled = FALSE;
+    protected $rememberMeEnabled = false;
 
     /**
      * Storage for general config option session.rememberme.checked.
@@ -70,83 +70,88 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
      * the "remember me" checkbox to checked or not.
      * @var bool
      */
-    protected $rememberMeChecked = FALSE;
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * All subclasses who implement their own constructor must call this constructor before
-	 * using $config for anything.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array &$config  Configuration for this authentication source.
-	 */
-	public function __construct($info, &$config) {
-		assert(is_array($info));
-		assert(is_array($config));
-		
-		if (isset($config['core:loginpage_links'])) {
-			$this->loginLinks = $config['core:loginpage_links'];
-		}
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		// Get the remember username config options
-		if (isset($config['remember.username.enabled'])) {
-			$this->rememberUsernameEnabled = (bool) $config['remember.username.enabled'];
-			unset($config['remember.username.enabled']);
-		}
-		if (isset($config['remember.username.checked'])) {
-			$this->rememberUsernameChecked = (bool) $config['remember.username.checked'];
-			unset($config['remember.username.checked']);
-		}
+    protected $rememberMeChecked = false;
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * All subclasses who implement their own constructor must call this constructor before
+     * using $config for anything.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array &$config  Configuration for this authentication source.
+     */
+    public function __construct($info, &$config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        if (isset($config['core:loginpage_links'])) {
+            $this->loginLinks = $config['core:loginpage_links'];
+        }
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        // Get the remember username config options
+        if (isset($config['remember.username.enabled'])) {
+            $this->rememberUsernameEnabled = (bool) $config['remember.username.enabled'];
+            unset($config['remember.username.enabled']);
+        }
+        if (isset($config['remember.username.checked'])) {
+            $this->rememberUsernameChecked = (bool) $config['remember.username.checked'];
+            unset($config['remember.username.checked']);
+        }
 
         // get the "remember me" config options
-        $sspcnf = SimpleSAML_Configuration::getInstance();
-        $this->rememberMeEnabled = $sspcnf->getBoolean('session.rememberme.enable', FALSE);
-        $this->rememberMeChecked = $sspcnf->getBoolean('session.rememberme.checked', FALSE);
-	}
-
-
-	/**
-	 * Set forced username.
-	 *
-	 * @param string|NULL $forcedUsername  The forced username.
-	 */
-	public function setForcedUsername($forcedUsername) {
-		assert(is_string($forcedUsername) || $forcedUsername === null);
-		$this->forcedUsername = $forcedUsername;
-	}
-
-	/**
-	 * Return login links from configuration
-	 */
-	public function getLoginLinks() {
-		return $this->loginLinks;
-	}
-
-	/**
-	 * Getter for the authsource config option remember.username.enabled
-	 * @return bool
-	 */
-	public function getRememberUsernameEnabled() {
-		return $this->rememberUsernameEnabled;
-	}
-
-	/**
-	 * Getter for the authsource config option remember.username.checked
-	 * @return bool
-	 */
-	public function getRememberUsernameChecked() {
-		return $this->rememberUsernameChecked;
-	}
+        $sspcnf = \SimpleSAML\Configuration::getInstance();
+        $this->rememberMeEnabled = $sspcnf->getBoolean('session.rememberme.enable', false);
+        $this->rememberMeChecked = $sspcnf->getBoolean('session.rememberme.checked', false);
+    }
+
+    /**
+     * Set forced username.
+     *
+     * @param string|NULL $forcedUsername  The forced username.
+     */
+    public function setForcedUsername($forcedUsername)
+    {
+        assert(is_string($forcedUsername) || $forcedUsername === null);
+        $this->forcedUsername = $forcedUsername;
+    }
+
+    /**
+     * Return login links from configuration
+     */
+    public function getLoginLinks()
+    {
+        return $this->loginLinks;
+    }
+
+    /**
+     * Getter for the authsource config option remember.username.enabled
+     * @return bool
+     */
+    public function getRememberUsernameEnabled()
+    {
+        return $this->rememberUsernameEnabled;
+    }
+
+    /**
+     * Getter for the authsource config option remember.username.checked
+     * @return bool
+     */
+    public function getRememberUsernameChecked()
+    {
+        return $this->rememberUsernameChecked;
+    }
 
     /**
      * Check if the "remember me" feature is enabled.
      * @return bool TRUE if enabled, FALSE otherwise.
      */
-    public function isRememberMeEnabled() {
+    public function isRememberMeEnabled()
+    {
         return $this->rememberMeEnabled;
     }
 
@@ -154,133 +159,133 @@ abstract class sspmod_core_Auth_UserPassBase extends SimpleSAML_Auth_Source {
      * Check if the "remember me" checkbox should be checked.
      * @return bool TRUE if enabled, FALSE otherwise.
      */
-    public function isRememberMeChecked() {
+    public function isRememberMeChecked()
+    {
         return $this->rememberMeChecked;
     }
 
-	/**
-	 * Initialize login.
-	 *
-	 * This function saves the information about the login, and redirects to a
-	 * login page.
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		/*
-		 * Save the identifier of this authentication source, so that we can
-		 * retrieve it later. This allows us to call the login()-function on
-		 * the current object.
-		 */
-		$state[self::AUTHID] = $this->authId;
-
-		// What username we should force, if any
-		if ($this->forcedUsername !== NULL) {
-			/*
-			 * This is accessed by the login form, to determine if the user
-			 * is allowed to change the username.
-			 */
-			$state['forcedUsername'] = $this->forcedUsername;
-	    }
-
-	  // ECP requests supply authentication credentials with the AUthnRequest
-	  // so we validate them now rather than redirecting
-	  if (isset($state['core:auth:username']) && isset($state['core:auth:password'])) {
-	      $username = $state['core:auth:username'];
-	      $password = $state['core:auth:password'];
-
-	      if (isset($state['forcedUsername'])) {
-	          $username = $state['forcedUsername'];
-	      }
-
-	      $attributes = $this->login($username, $password);
-	      assert('is_array($attributes)');
-	      $state['Attributes'] = $attributes;
-
-	      return;
-	  }
-
-		/* Save the $state-array, so that we can restore it after a redirect. */
-		$id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
-
-		/*
-		 * Redirect to the login form. We include the identifier of the saved
-		 * state array as a parameter to the login form.
-		 */
-		$url = SimpleSAML\Module::getModuleURL('core/loginuserpass.php');
-		$params = array('AuthState' => $id);
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
-
-		/* The previous function never returns, so this code is never executed. */
-		assert(false);
-	}
-
-
-	/**
-	 * Attempt to log in using the given username and password.
-	 *
-	 * On a successful login, this function should return the users attributes. On failure,
-	 * it should throw an exception/error. If the error was caused by the user entering the wrong
-	 * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
-	 *
-	 * Note that both the username and the password are UTF-8 encoded.
-	 *
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 * @return array  Associative array with the user's attributes.
-	 */
-	abstract protected function login($username, $password);
-
-
-	/**
-	 * Handle login request.
-	 *
-	 * This function is used by the login form (core/www/loginuserpass.php) when the user
-	 * enters a username and password. On success, it will not return. On wrong
-	 * username/password failure, and other errors, it will throw an exception.
-	 *
-	 * @param string $authStateId  The identifier of the authentication state.
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 */
-	public static function handleLogin($authStateId, $username, $password) {
-		assert(is_string($authStateId));
-		assert(is_string($username));
-		assert(is_string($password));
-
-		/* Here we retrieve the state array we saved in the authenticate-function. */
-		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
-
-		/* Retrieve the authentication source we are executing. */
-		assert(array_key_exists(self::AUTHID, $state));
-		$source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
-		if ($source === NULL) {
-			throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
-		}
-
-		/*
-		 * $source now contains the authentication source on which authenticate()
-		 * was called. We should call login() on the same authentication source.
-		 */
-
-		/* Attempt to log in. */
-		try {
-			$attributes = $source->login($username, $password);
-		} catch (Exception $e) {
-			SimpleSAML\Logger::stats('Unsuccessful login attempt from '.$_SERVER['REMOTE_ADDR'].'.');
-			throw $e;
-		}
-
-		SimpleSAML\Logger::stats('User \''.$username.'\' successfully authenticated from '.$_SERVER['REMOTE_ADDR']);
-
-		/* Save the attributes we received from the login-function in the $state-array. */
-		assert(is_array($attributes));
-		$state['Attributes'] = $attributes;
-
-		/* Return control to SimpleSAMLphp after successful authentication. */
-		SimpleSAML_Auth_Source::completeAuth($state);
-	}
+    /**
+     * Initialize login.
+     *
+     * This function saves the information about the login, and redirects to a
+     * login page.
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+
+        /*
+         * Save the identifier of this authentication source, so that we can
+         * retrieve it later. This allows us to call the login()-function on
+         * the current object.
+         */
+        $state[self::AUTHID] = $this->authId;
+
+        // What username we should force, if any
+        if ($this->forcedUsername !== null) {
+            /*
+             * This is accessed by the login form, to determine if the user
+             * is allowed to change the username.
+             */
+            $state['forcedUsername'] = $this->forcedUsername;
+        }
+
+        // ECP requests supply authentication credentials with the AUthnRequest
+        // so we validate them now rather than redirecting
+        if (isset($state['core:auth:username']) && isset($state['core:auth:password'])) {
+            $username = $state['core:auth:username'];
+            $password = $state['core:auth:password'];
+
+            if (isset($state['forcedUsername'])) {
+                $username = $state['forcedUsername'];
+            }
+
+            $attributes = $this->login($username, $password);
+            assert(is_array($attributes));
+            $state['Attributes'] = $attributes;
+
+            return;
+        }
+
+        // Save the $state-array, so that we can restore it after a redirect
+        $id = \SimpleSAML\Auth\State::saveState($state, self::STAGEID);
+
+        /*
+         * Redirect to the login form. We include the identifier of the saved
+         * state array as a parameter to the login form.
+         */
+        $url = \SimpleSAML\Module::getModuleURL('core/loginuserpass.php');
+        $params = ['AuthState' => $id];
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
+
+        // The previous function never returns, so this code is never executed.
+        assert(false);
+    }
+
+    /**
+     * Attempt to log in using the given username and password.
+     *
+     * On a successful login, this function should return the users attributes. On failure,
+     * it should throw an exception/error. If the error was caused by the user entering the wrong
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
+     *
+     * Note that both the username and the password are UTF-8 encoded.
+     *
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     * @return array  Associative array with the user's attributes.
+     */
+    abstract protected function login($username, $password);
 
+    /**
+     * Handle login request.
+     *
+     * This function is used by the login form (core/www/loginuserpass.php) when the user
+     * enters a username and password. On success, it will not return. On wrong
+     * username/password failure, and other errors, it will throw an exception.
+     *
+     * @param string $authStateId  The identifier of the authentication state.
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     */
+    public static function handleLogin($authStateId, $username, $password)
+    {
+        assert(is_string($authStateId));
+        assert(is_string($username));
+        assert(is_string($password));
+
+        // Here we retrieve the state array we saved in the authenticate-function.
+        $state = \SimpleSAML\Auth\State::loadState($authStateId, self::STAGEID);
+
+        // Retrieve the authentication source we are executing.
+        assert(array_key_exists(self::AUTHID, $state));
+        $source = \SimpleSAML\Auth\Source::getById($state[self::AUTHID]);
+        if ($source === null) {
+            throw new \Exception('Could not find authentication source with id '.$state[self::AUTHID]);
+        }
+
+        /*
+         * $source now contains the authentication source on which authenticate()
+         * was called. We should call login() on the same authentication source.
+         */
+
+        // Attempt to log in
+        try {
+            $attributes = $source->login($username, $password);
+        } catch (\Exception $e) {
+            \SimpleSAML\Logger::stats('Unsuccessful login attempt from '.$_SERVER['REMOTE_ADDR'].'.');
+            throw $e;
+        }
+
+        \SimpleSAML\Logger::stats('User \''.$username.'\' successfully authenticated from '.$_SERVER['REMOTE_ADDR']);
+
+        // Save the attributes we received from the login-function in the $state-array
+        assert(is_array($attributes));
+        $state['Attributes'] = $attributes;
+
+        // Return control to SimpleSAMLphp after successful authentication.
+        \SimpleSAML\Auth\Source::completeAuth($state);
+    }
 }
diff --git a/modules/core/lib/Auth/UserPassOrgBase.php b/modules/core/lib/Auth/UserPassOrgBase.php
index ccdc1cda5980ee6f8e72ed611764346fbdd92779..33168524c85c692c1f19fac1b3f08b684e3c3878 100644
--- a/modules/core/lib/Auth/UserPassOrgBase.php
+++ b/modules/core/lib/Auth/UserPassOrgBase.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\core\Auth;
+
 /**
  * Helper class for username/password/organization authentication.
  *
@@ -11,266 +13,316 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-abstract class sspmod_core_Auth_UserPassOrgBase extends SimpleSAML_Auth_Source {
-
-
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGEID = 'sspmod_core_Auth_UserPassOrgBase.state';
-
-
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'sspmod_core_Auth_UserPassOrgBase.AuthId';
-
-
-	/**
-	 * The key of the OrgId field in the state, identifies which org was selected.
-	 */
-	const ORGID = 'sspmod_core_Auth_UserPassOrgBase.SelectedOrg';
-
-
-	/**
-	 * What way do we handle the organization as part of the username.
-	 * Three values:
-	 *  'none': Force the user to select the correct organization from the dropdown box.
-	 *  'allow': Allow the user to enter the organization as part of the username.
-	 *  'force': Remove the dropdown box.
-	 */
-	private $usernameOrgMethod;
-
-	/**
-	 * Storage for authsource config option remember.username.enabled
-	 * loginuserpass.php and loginuserpassorg.php pages/templates use this option to
-	 * present users with a checkbox to save their username for the next login request.
-	 * @var bool
-	 */
-	protected $rememberUsernameEnabled = FALSE;
-
-	/**
-	 * Storage for authsource config option remember.username.checked
-	 * loginuserpass.php and loginuserpassorg.php pages/templates use this option
-	 * to default the remember username checkbox to checked or not.
-	 * @var bool
-	 */
-	protected $rememberUsernameChecked = FALSE;
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * All subclasses who implement their own constructor must call this constructor before
-	 * using $config for anything.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array &$config  Configuration for this authentication source.
-	 */
-	public function __construct($info, &$config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		// Get the remember username config options
-		if (isset($config['remember.username.enabled'])) {
-			$this->rememberUsernameEnabled = (bool) $config['remember.username.enabled'];
-			unset($config['remember.username.enabled']);
-		}
-		if (isset($config['remember.username.checked'])) {
-			$this->rememberUsernameChecked = (bool) $config['remember.username.checked'];
-			unset($config['remember.username.checked']);
-		}
-
-		$this->usernameOrgMethod = 'none';
-	}
-
-
-	/**
-	 * Configure the way organizations as part of the username is handled.
-	 *
-	 * There are three possible values:
-	 * - 'none': Force the user to select the correct organization from the dropdown box.
-	 * - 'allow': Allow the user to enter the organization as part of the username.
-	 * - 'force': Remove the dropdown box.
-	 *
-	 * If unconfigured, the default is 'none'.
-	 *
-	 * @param string $usernameOrgMethod  The method which should be used.
-	 */
-	protected function setUsernameOrgMethod($usernameOrgMethod) {
-		assert(in_array($usernameOrgMethod, array('none', 'allow', 'force'), true));
-
-		$this->usernameOrgMethod = $usernameOrgMethod;
-	}
-
-
-	/**
-	 * Retrieve the way organizations as part of the username should be handled.
-	 *
-	 * There are three possible values:
-	 * - 'none': Force the user to select the correct organization from the dropdown box.
-	 * - 'allow': Allow the user to enter the organization as part of the username.
-	 * - 'force': Remove the dropdown box.
-	 *
-	 * @return string  The method which should be used.
-	 */
-	public function getUsernameOrgMethod() {
-		return $this->usernameOrgMethod;
-	}
-
-	/**
-	 * Getter for the authsource config option remember.username.enabled
-	 * @return bool
-	 */
-	public function getRememberUsernameEnabled() {
-		return $this->rememberUsernameEnabled;
-	}
-
-	/**
-	 * Getter for the authsource config option remember.username.checked
-	 * @return bool
-	 */
-	public function getRememberUsernameChecked() {
-		return $this->rememberUsernameChecked;
-	}
-
-
-	/**
-	 * Initialize login.
-	 *
-	 * This function saves the information about the login, and redirects to a
-	 * login page.
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		// We are going to need the authId in order to retrieve this authentication source later
-		$state[self::AUTHID] = $this->authId;
-
-		$id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
-
-		$url = SimpleSAML\Module::getModuleURL('core/loginuserpassorg.php');
-		$params = array('AuthState' => $id);
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
-	}
-
-
-	/**
-	 * Attempt to log in using the given username, password and organization.
-	 *
-	 * On a successful login, this function should return the users attributes. On failure,
-	 * it should throw an exception/error. If the error was caused by the user entering the wrong
-	 * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
-	 *
-	 * Note that both the username and the password are UTF-8 encoded.
-	 *
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 * @param string $organization  The id of the organization the user chose.
-	 * @return array  Associative array with the user's attributes.
-	 */
-	abstract protected function login($username, $password, $organization);
-
-
-	/**
-	 * Retrieve list of organizations.
-	 *
-	 * The list of organizations is an associative array. The key of the array is the
-	 * id of the organization, and the value is the description. The value can be another
-	 * array, in which case that array is expected to contain language-code to
-	 * description mappings.
-	 *
-	 * @return array  Associative array with the organizations.
-	 */
-	abstract protected function getOrganizations();
-
-
-	/**
-	 * Handle login request.
-	 *
-	 * This function is used by the login form (core/www/loginuserpassorg.php) when the user
-	 * enters a username and password. On success, it will not return. On wrong
-	 * username/password failure, and other errors, it will throw an exception.
-	 *
-	 * @param string $authStateId  The identifier of the authentication state.
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 * @param string $organization  The id of the organization the user chose.
-	 */
-	public static function handleLogin($authStateId, $username, $password, $organization) {
-		assert(is_string($authStateId));
-		assert(is_string($username));
-		assert(is_string($password));
-		assert(is_string($organization));
-
-		/* Retrieve the authentication state. */
-		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
-
-		/* Find authentication source. */
-		assert(array_key_exists(self::AUTHID, $state));
-		$source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
-		if ($source === NULL) {
-			throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
-		}
-
-		$orgMethod = $source->getUsernameOrgMethod();
-		if ($orgMethod !== 'none') {
-			$tmp = explode('@', $username, 2);
-			if (count($tmp) === 2) {
-				$username = $tmp[0];
-				$organization = $tmp[1];
-			} else {
-				if ($orgMethod === 'force') {
-					/* The organization should be a part of the username, but isn't. */
-					throw new SimpleSAML_Error_Error('WRONGUSERPASS');
-				}
-			}
-		}
-
-		/* Attempt to log in. */
-		$attributes = $source->login($username, $password, $organization);
-
-		// Add the selected Org to the state
-		$state[self::ORGID] = $organization;
-		$state['PersistentAuthData'][] = self::ORGID;
-
-		$state['Attributes'] = $attributes;
-		SimpleSAML_Auth_Source::completeAuth($state);
-	}
-
-
-	/**
-	 * Get available organizations.
-	 *
-	 * This function is used by the login form to get the available organizations.
-	 *
-	 * @param string $authStateId  The identifier of the authentication state.
-	 * @return array|NULL  Array of organizations. NULL if the user must enter the
-	 *         organization as part of the username.
-	 */
-	public static function listOrganizations($authStateId) {
-		assert(is_string($authStateId));
-
-		/* Retrieve the authentication state. */
-		$state = SimpleSAML_Auth_State::loadState($authStateId, self::STAGEID);
-
-		/* Find authentication source. */
-		assert(array_key_exists(self::AUTHID, $state));
-		$source = SimpleSAML_Auth_Source::getById($state[self::AUTHID]);
-		if ($source === NULL) {
-			throw new Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
-		}
-
-		$orgMethod = $source->getUsernameOrgMethod();
-		if ($orgMethod === 'force') {
-			return NULL;
-		}
-
-		return $source->getOrganizations();
-	}
+
+abstract class UserPassOrgBase extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The string used to identify our states.
+     */
+    const STAGEID = '\SimpleSAML\Module\core\Auth\UserPassOrgBase.state';
+
+
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = '\SimpleSAML\Module\core\Auth\UserPassOrgBase.AuthId';
+
+
+    /**
+     * The key of the OrgId field in the state, identifies which org was selected.
+     */
+    const ORGID = '\SimpleSAML\Module\core\Auth\UserPassOrgBase.SelectedOrg';
+
+
+    /**
+     * What way do we handle the organization as part of the username.
+     * Three values:
+     *  'none': Force the user to select the correct organization from the dropdown box.
+     *  'allow': Allow the user to enter the organization as part of the username.
+     *  'force': Remove the dropdown box.
+     */
+    private $usernameOrgMethod;
+
+    /**
+     * Storage for authsource config option remember.username.enabled
+     * loginuserpass.php and loginuserpassorg.php pages/templates use this option to
+     * present users with a checkbox to save their username for the next login request.
+     * @var bool
+     */
+    protected $rememberUsernameEnabled = false;
+
+    /**
+     * Storage for authsource config option remember.username.checked
+     * loginuserpass.php and loginuserpassorg.php pages/templates use this option
+     * to default the remember username checkbox to checked or not.
+     * @var bool
+     */
+    protected $rememberUsernameChecked = false;
+
+    /**
+     * Storage for authsource config option remember.organization.enabled
+     * loginuserpassorg.php page/template use this option to present users
+     * with a checkbox to save their organization choice for the next login request.
+     * @var bool
+     */
+    protected $rememberOrganizationEnabled = false;
+
+    /**
+     * Storage for authsource config option remember.organization.checked
+     * loginuserpassorg.php page/template use this option to
+     * default the remember organization checkbox to checked or not.
+     * @var bool
+     */
+    protected $rememberOrganizationChecked = false;
+
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * All subclasses who implement their own constructor must call this constructor before
+     * using $config for anything.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array &$config  Configuration for this authentication source.
+     */
+    public function __construct($info, &$config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        // Get the remember username config options
+        if (isset($config['remember.username.enabled'])) {
+            $this->rememberUsernameEnabled = (bool) $config['remember.username.enabled'];
+            unset($config['remember.username.enabled']);
+        }
+        if (isset($config['remember.username.checked'])) {
+            $this->rememberUsernameChecked = (bool) $config['remember.username.checked'];
+            unset($config['remember.username.checked']);
+        }
+        // Get the remember organization config options
+        if (isset($config['remember.organization.enabled'])) {
+            $this->rememberOrganizationEnabled = (bool) $config['remember.organization.enabled'];
+            unset($config['remember.organization.enabled']);
+        }
+        if (isset($config['remember.organization.checked'])) {
+            $this->rememberOrganizationChecked = (bool) $config['remember.organization.checked'];
+            unset($config['remember.organization.checked']);
+        }
+
+        $this->usernameOrgMethod = 'none';
+    }
+
+
+    /**
+     * Configure the way organizations as part of the username is handled.
+     *
+     * There are three possible values:
+     * - 'none': Force the user to select the correct organization from the dropdown box.
+     * - 'allow': Allow the user to enter the organization as part of the username.
+     * - 'force': Remove the dropdown box.
+     *
+     * If unconfigured, the default is 'none'.
+     *
+     * @param string $usernameOrgMethod  The method which should be used.
+     */
+    protected function setUsernameOrgMethod($usernameOrgMethod)
+    {
+        assert(in_array($usernameOrgMethod, ['none', 'allow', 'force'], true));
+
+        $this->usernameOrgMethod = $usernameOrgMethod;
+    }
+
+
+    /**
+     * Retrieve the way organizations as part of the username should be handled.
+     *
+     * There are three possible values:
+     * - 'none': Force the user to select the correct organization from the dropdown box.
+     * - 'allow': Allow the user to enter the organization as part of the username.
+     * - 'force': Remove the dropdown box.
+     *
+     * @return string  The method which should be used.
+     */
+    public function getUsernameOrgMethod()
+    {
+        return $this->usernameOrgMethod;
+    }
+
+    /**
+     * Getter for the authsource config option remember.username.enabled
+     * @return bool
+     */
+    public function getRememberUsernameEnabled()
+    {
+        return $this->rememberUsernameEnabled;
+    }
+
+    /**
+     * Getter for the authsource config option remember.username.checked
+     * @return bool
+     */
+    public function getRememberUsernameChecked()
+    {
+        return $this->rememberUsernameChecked;
+    }
+
+    /**
+     * Getter for the authsource config option remember.organization.enabled
+     * @return bool
+     */
+    public function getRememberOrganizationEnabled()
+    {
+        return $this->rememberOrganizationEnabled;
+    }
+
+    /**
+     * Getter for the authsource config option remember.organization.checked
+     * @return bool
+     */
+    public function getRememberOrganizationChecked()
+    {
+        return $this->rememberOrganizationChecked;
+    }
+
+    /**
+     * Initialize login.
+     *
+     * This function saves the information about the login, and redirects to a
+     * login page.
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+
+        // We are going to need the authId in order to retrieve this authentication source later
+        $state[self::AUTHID] = $this->authId;
+
+        $id = \SimpleSAML\Auth\State::saveState($state, self::STAGEID);
+
+        $url = \SimpleSAML\Module::getModuleURL('core/loginuserpassorg.php');
+        $params = ['AuthState' => $id];
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
+    }
+
+
+    /**
+     * Attempt to log in using the given username, password and organization.
+     *
+     * On a successful login, this function should return the users attributes. On failure,
+     * it should throw an exception/error. If the error was caused by the user entering the wrong
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
+     *
+     * Note that both the username and the password are UTF-8 encoded.
+     *
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     * @param string $organization  The id of the organization the user chose.
+     * @return array  Associative array with the user's attributes.
+     */
+    abstract protected function login($username, $password, $organization);
+
+
+    /**
+     * Retrieve list of organizations.
+     *
+     * The list of organizations is an associative array. The key of the array is the
+     * id of the organization, and the value is the description. The value can be another
+     * array, in which case that array is expected to contain language-code to
+     * description mappings.
+     *
+     * @return array  Associative array with the organizations.
+     */
+    abstract protected function getOrganizations();
+
+
+    /**
+     * Handle login request.
+     *
+     * This function is used by the login form (core/www/loginuserpassorg.php) when the user
+     * enters a username and password. On success, it will not return. On wrong
+     * username/password failure, and other errors, it will throw an exception.
+     *
+     * @param string $authStateId  The identifier of the authentication state.
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     * @param string $organization  The id of the organization the user chose.
+     */
+    public static function handleLogin($authStateId, $username, $password, $organization)
+    {
+        assert(is_string($authStateId));
+        assert(is_string($username));
+        assert(is_string($password));
+        assert(is_string($organization));
+
+        /* Retrieve the authentication state. */
+        $state = \SimpleSAML\Auth\State::loadState($authStateId, self::STAGEID);
+
+        /* Find authentication source. */
+        assert(array_key_exists(self::AUTHID, $state));
+        $source = \SimpleSAML\Auth\Source::getById($state[self::AUTHID]);
+        if ($source === null) {
+            throw new \Exception('Could not find authentication source with id '.$state[self::AUTHID]);
+        }
+
+        $orgMethod = $source->getUsernameOrgMethod();
+        if ($orgMethod !== 'none') {
+            $tmp = explode('@', $username, 2);
+            if (count($tmp) === 2) {
+                $username = $tmp[0];
+                $organization = $tmp[1];
+            } else {
+                if ($orgMethod === 'force') {
+                    /* The organization should be a part of the username, but isn't. */
+                    throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
+                }
+            }
+        }
+
+        /* Attempt to log in. */
+        $attributes = $source->login($username, $password, $organization);
+
+        // Add the selected Org to the state
+        $state[self::ORGID] = $organization;
+        $state['PersistentAuthData'][] = self::ORGID;
+
+        $state['Attributes'] = $attributes;
+        \SimpleSAML\Auth\Source::completeAuth($state);
+    }
+
+
+    /**
+     * Get available organizations.
+     *
+     * This function is used by the login form to get the available organizations.
+     *
+     * @param string $authStateId  The identifier of the authentication state.
+     * @return array|NULL  Array of organizations. NULL if the user must enter the
+     *         organization as part of the username.
+     */
+    public static function listOrganizations($authStateId)
+    {
+        assert(is_string($authStateId));
+
+        /* Retrieve the authentication state. */
+        $state = \SimpleSAML\Auth\State::loadState($authStateId, self::STAGEID);
+
+        /* Find authentication source. */
+        assert(array_key_exists(self::AUTHID, $state));
+        $source = \SimpleSAML\Auth\Source::getById($state[self::AUTHID]);
+        if ($source === null) {
+            throw new \Exception('Could not find authentication source with id '.$state[self::AUTHID]);
+        }
+
+        $orgMethod = $source->getUsernameOrgMethod();
+        if ($orgMethod === 'force') {
+            return null;
+        }
+
+        return $source->getOrganizations();
+    }
 }
diff --git a/modules/core/lib/Stats/Output/File.php b/modules/core/lib/Stats/Output/File.php
index 0642bcda23ae138c532c2b000f2546967003de94..cac817c83b784f5e7fca13d3a6dca81d0497ab18 100644
--- a/modules/core/lib/Stats/Output/File.php
+++ b/modules/core/lib/Stats/Output/File.php
@@ -1,97 +1,96 @@
 <?php
 
+namespace SimpleSAML\Module\core\Stats\Output;
+
 /**
  * Statistics logger that writes to a set of log files
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Stats_Output_File extends SimpleSAML_Stats_Output {
-
-	/**
-	 * The log directory.
-	 * @var string
-	 */
-	private $logDir;
-
-
-	/**
-	 * The file handle for the current file.
-	 * @var resource
-	 */
-	private $file = NULL;
-
-	/**
-	 * The current file date.
-	 * @var string
-	 */
-	private $fileDate = NULL;
-
-
-	/**
-	 * Initialize the output.
-	 *
-	 * @param SimpleSAML_Configuration $config  The configuration for this output.
-	 */
-	public function __construct(SimpleSAML_Configuration $config) {
-
-		$this->logDir = $config->getPathValue('directory');
-		if ($this->logDir === NULL) {
-			throw new Exception('Missing "directory" option for core:File');
-		}
-		if (!is_dir($this->logDir)) {
-			throw new Exception('Could not find log directory: ' . var_export($this->logDir, TRUE));
-		}
-
-	}
-
-
-	/**
-	 * Open a log file.
-	 *
-	 * @param string $date  The date for the log file.
-	 */
-	private function openLog($date) {
-		assert(is_string($date));
-
-		if ($this->file !== NULL && $this->file !== FALSE) {
-			fclose($this->file);
-			$this->file = NULL;
-		}
-
-		$fileName = $this->logDir . '/' . $date . '.log';
-		$this->file = @fopen($fileName, 'a');
-		if ($this->file === FALSE) {
-			throw new SimpleSAML_Error_Exception('Error opening log file: ' . var_export($fileName, TRUE));
-		}
-
-		// Disable output buffering
-		stream_set_write_buffer($this->file, 0);
-
-		$this->fileDate = $date;
-	}
-
-
-	/**
-	 * Write a stats event.
-	 *
-	 * @param array $data  The event.
-	 */
-	public function emit(array $data) {
-		assert(isset($data['time']));
-
-		$time = $data['time'];
-		$milliseconds = (int)(($time - (int)$time) * 1000);
-
-		$timestamp = gmdate('Y-m-d\TH:i:s', $time) . sprintf('.%03dZ', $milliseconds);
-
-		$outDate = substr($timestamp, 0, 10); // The date-part of the timstamp
-
-		if ($outDate !== $this->fileDate) {
-			$this->openLog($outDate);
-		}
-
-		$line = $timestamp . ' ' . json_encode($data) . "\n";
-		fwrite($this->file, $line);
-	}
 
+class File extends \SimpleSAML\Stats\Output
+{
+    /**
+     * The log directory.
+     * @var string
+     */
+    private $logDir;
+
+    /**
+     * The file handle for the current file.
+     * @var resource|null|false
+     */
+    private $file = null;
+
+    /**
+     * The current file date.
+     * @var string
+     */
+    private $fileDate = null;
+
+    /**
+     * Initialize the output.
+     *
+     * @param \SimpleSAML\Configuration $config  The configuration for this output.
+     */
+    public function __construct(\SimpleSAML\Configuration $config)
+    {
+        $this->logDir = $config->getPathValue('directory');
+        if ($this->logDir === null) {
+            throw new \Exception('Missing "directory" option for core:File');
+        }
+        if (!is_dir($this->logDir)) {
+            throw new \Exception('Could not find log directory: '.var_export($this->logDir, true));
+        }
+    }
+
+    /**
+     * Open a log file.
+     *
+     * @param string $date  The date for the log file.
+     */
+    private function openLog($date)
+    {
+        assert(is_string($date));
+
+        if ($this->file !== null && $this->file !== false) {
+            fclose($this->file);
+            $this->file = null;
+        }
+
+        $fileName = $this->logDir.'/'.$date.'.log';
+        $this->file = @fopen($fileName, 'a');
+        if ($this->file === false) {
+            throw new \SimpleSAML\Error\Exception('Error opening log file: '.var_export($fileName, true));
+        }
+
+        // Disable output buffering
+        stream_set_write_buffer($this->file, 0);
+
+        $this->fileDate = $date;
+    }
+
+    /**
+     * Write a stats event.
+     *
+     * @param array $data  The event.
+     */
+    public function emit(array $data)
+    {
+        assert(isset($data['time']));
+
+        $time = $data['time'];
+        $milliseconds = (int) (($time - (int) $time) * 1000);
+
+        $timestamp = gmdate('Y-m-d\TH:i:s', $time).sprintf('.%03dZ', $milliseconds);
+
+        $outDate = substr($timestamp, 0, 10); // The date-part of the timstamp
+
+        if ($outDate !== $this->fileDate) {
+            $this->openLog($outDate);
+        }
+
+        $line = $timestamp.' '.json_encode($data)."\n";
+        fwrite($this->file, $line);
+    }
 }
diff --git a/modules/core/lib/Stats/Output/Log.php b/modules/core/lib/Stats/Output/Log.php
index 70e914e4bb4316cb4d2b83a1a4370e6b68175f29..e3eff86663cac6955df4ff620944547578e4d415 100644
--- a/modules/core/lib/Stats/Output/Log.php
+++ b/modules/core/lib/Stats/Output/Log.php
@@ -1,42 +1,43 @@
 <?php
 
+namespace SimpleSAML\Module\core\Stats\Output;
+
 /**
  * Statistics logger that writes to the default logging handler.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_core_Stats_Output_Log extends SimpleSAML_Stats_Output {
-
-	/**
-	 * The logging function we should call.
-	 * @var callback
-	 */
-	private $logger;
-
-
-	/**
-	 * Initialize the output.
-	 *
-	 * @param SimpleSAML_Configuration $config  The configuration for this output.
-	 */
-	public function __construct(SimpleSAML_Configuration $config) {
-
-		$logLevel = $config->getString('level', 'notice');
-		$this->logger = array('SimpleSAML\Logger', $logLevel);
-		if (!is_callable($this->logger)) {
-			throw new Exception('Invalid log level: ' . var_export($logLevel, TRUE));
-		}
-	}
-
-
-	/**
-	 * Write a stats event.
-	 *
-	 * @param string $data  The event (as a JSON string).
-	 */
-	public function emit(array $data) {
-		$str_data = json_encode($data);
-		call_user_func($this->logger, 'EVENT ' . $str_data);
-	}
 
+class Log extends \SimpleSAML\Stats\Output
+{
+    /**
+     * The logging function we should call.
+     * @var callback
+     */
+    private $logger;
+
+    /**
+     * Initialize the output.
+     *
+     * @param \SimpleSAML\Configuration $config  The configuration for this output.
+     */
+    public function __construct(\SimpleSAML\Configuration $config)
+    {
+        $logLevel = $config->getString('level', 'notice');
+        $this->logger = ['\SimpleSAML\Logger', $logLevel];
+        if (!is_callable($this->logger)) {
+            throw new \Exception('Invalid log level: '.var_export($logLevel, true));
+        }
+    }
+
+    /**
+     * Write a stats event.
+     *
+     * @param string $data  The event (as a JSON string).
+     */
+    public function emit(array $data)
+    {
+        $str_data = json_encode($data);
+        call_user_func($this->logger, 'EVENT '.$str_data);
+    }
 }
diff --git a/modules/core/lib/Storage/SQLPermanentStorage.php b/modules/core/lib/Storage/SQLPermanentStorage.php
index 54bb5642bf1b59201b850164f1ac343489d4b64a..4360d5e84ad015e37438810cdc61712a85aef9ee 100644
--- a/modules/core/lib/Storage/SQLPermanentStorage.php
+++ b/modules/core/lib/Storage/SQLPermanentStorage.php
@@ -1,206 +1,219 @@
 <?php
 
+namespace SimpleSAML\Module\core\Storage;
+
 /**
  * SQLPermanentStorage
- * 
+ *
  * Generic SQL Store to store key value pairs. To be used in several other modules that needs
  * to store data permanently.
  *
  * @author Andreas Ă…kre Solberg <andreas@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_core_Storage_SQLPermanentStorage {
-	
-	private $db;
-	
-	function __construct($name, $config = NULL) {
-		if (is_null($config))
-			$config = SimpleSAML_Configuration::getInstance();
-		
-		$datadir = $config->getPathValue('datadir', 'data/');
-		
-		if (!is_dir($datadir))
-			throw new Exception('Data directory [' . $datadir. '] does not exist');
-		if (!is_writable($datadir))
-			throw new Exception('Data directory [' . $datadir. '] is not writable');
-		
-		$sqllitedir = $datadir . 'sqllite/';
-		if (!is_dir($sqllitedir)) {
-			mkdir($sqllitedir);
-		}
-		
-		$dbfile = $sqllitedir . $name . '.sqllite';
-		
-		if ($this->db = new SQLiteDatabase($dbfile)) {
-			$q = @$this->db->query('SELECT key1 FROM data LIMIT 1');
-			if ($q === false) {
-				$this->db->queryExec('
-		CREATE TABLE data (
-			key1 text, 
-			key2 text,
-			type text,
-			value text,
-			created timestamp,
-			updated timestamp,
-			expire timestamp,
-			PRIMARY KEY (key1,key2,type)
-		);
-		');
-			} 
-		} else {
-		    throw new Exception('Error creating SQL lite database [' . $dbfile . '].');
-		}
-	}
-
-	public function set($type, $key1, $key2, $value, $duration = NULL) {
-		if ($this->exists($type, $key1, $key2)) {
-			$this->update($type, $key1, $key2, $value, $duration);
-		} else {
-			$this->insert($type, $key1, $key2, $value, $duration);
-		}
-	}
-
-	private function insert($type, $key1, $key2, $value, $duration = NULL) {
-		
-		$setDuration = '';
-		if (is_null($duration)) {
-			$setDuration = 'NULL';
-		} else {
-			$setDuration = "'" . sqlite_escape_string(time() + $duration) . "'";
-		}
-		
-		$query = "INSERT INTO data (key1,key2,type,created,updated,expire,value) VALUES (" . 
-			"'" . sqlite_escape_string($key1) . "'," . 
-			"'" . sqlite_escape_string($key2) . "'," . 
-			"'" . sqlite_escape_string($type) . "'," . 
-			"'" . sqlite_escape_string(time()) . "'," . 
-			"'" . sqlite_escape_string(time()) . "'," . 
-			$setDuration . "," .
-			"'" . sqlite_escape_string(serialize($value)) . "')";
-		$results = $this->db->queryExec($query);
-		return $results;
-	}
-	
-	private function update($type, $key1, $key2, $value, $duration = NULL) {
-		
-		$setDuration = '';
-		if (is_null($duration)) {
-			$setDuration = ", expire = NULL ";
-		} else {
-			$setDuration = ", expire = '" . sqlite_escape_string(time() + $duration) . "' ";
-		}
-		
-		$query = "UPDATE data SET " . 
-			"updated = '" . sqlite_escape_string(time()) . "'," . 
-			"value = '" . sqlite_escape_string(serialize($value)) . "'" .
-			$setDuration .
-			"WHERE " . 
-			"key1 = '" . sqlite_escape_string($key1) . "' AND " . 
-			"key2 = '" . sqlite_escape_string($key2) . "' AND " . 
-			"type = '" . sqlite_escape_string($type) . "'";
-		$results = $this->db->queryExec($query);
-		return $results;
-	}
-
-	public function get($type = NULL, $key1 = NULL, $key2 = NULL) {
-		
-		$condition = self::getCondition($type, $key1, $key2);
-		$query = "SELECT * FROM data WHERE " . $condition;
-		$results = $this->db->arrayQuery($query, SQLITE_ASSOC);
-
-		if (count($results) !== 1) return NULL;
-		
-		$res = $results[0];
-		$res['value'] = unserialize($res['value']);
-		return $res;
-	}
-	
-	/*
-	 * Return the value directly (not in a container)
-	 */
-	public function getValue($type = NULL, $key1 = NULL, $key2 = NULL) {
-		$res = $this->get($type, $key1, $key2);
-		if ($res === NULL) return NULL;
-		return $res['value'];
-	}
-	
-	public function exists($type, $key1, $key2) {
-		$query = "SELECT * FROM data WHERE " . 
-			"key1 = '" . sqlite_escape_string($key1) . "' AND " . 
-			"key2 = '" . sqlite_escape_string($key2) . "' AND " . 
-			"type = '" . sqlite_escape_string($type) . "' LIMIT 1";
-		$results = $this->db->arrayQuery($query, SQLITE_ASSOC);
-		return (count($results) == 1);
-	}
-		
-	public function getList($type = NULL, $key1 = NULL, $key2 = NULL) {
-		
-		$condition = self::getCondition($type, $key1, $key2);
-		$query = "SELECT * FROM data WHERE " . $condition;
-		$results = $this->db->arrayQuery($query, SQLITE_ASSOC);
-		if (count($results) == 0) return NULL;
-		
-		foreach($results AS $key => $value) {
-			$results[$key]['value'] = unserialize($results[$key]['value']);
-		}
-		return $results;
-	}
-	
-	public function getKeys($type = NULL, $key1 = NULL, $key2 = NULL, $whichKey = 'type') {
-
-		if (!in_array($whichKey, array('key1', 'key2', 'type'), true))
-			throw new Exception('Invalid key type');
-			
-		$condition = self::getCondition($type, $key1, $key2);
-		
-		$query = "SELECT DISTINCT " . $whichKey . " FROM data WHERE " . $condition;
-		$results = $this->db->arrayQuery($query, SQLITE_ASSOC);
-
-		if (count($results) == 0) return NULL;
-		
-		$resarray = array();
-		foreach($results AS $key => $value) {
-			$resarray[] = $value[$whichKey];
-		}
-		
-		return $resarray;
-	}
-	
-	
-	public function remove($type, $key1, $key2) {
-		$query = "DELETE FROM data WHERE " . 
-			"key1 = '" . sqlite_escape_string($key1) . "' AND " . 
-			"key2 = '" . sqlite_escape_string($key2) . "' AND " . 
-			"type = '" . sqlite_escape_string($type) . "'";
-		$results = $this->db->arrayQuery($query, SQLITE_ASSOC);
-		return (count($results) == 1);
-	}
-	
-	public function removeExpired() {
-		$query = "DELETE FROM data WHERE expire NOT NULL AND expire < " . time();
-		$this->db->arrayQuery($query, SQLITE_ASSOC);
-		$changes = $this->db->changes();
-		return $changes;
-	}
-	
-	
-	/**
-	 * Create a SQL condition statement based on parameters
-	 */
-	private static function getCondition($type = NULL, $key1 = NULL, $key2 = NULL) {
-		$conditions = array();
-		
-		if (!is_null($type)) $conditions[] = "type = '" . sqlite_escape_string($type) . "'";
-		if (!is_null($key1)) $conditions[] = "key1 = '" . sqlite_escape_string($key1) . "'";
-		if (!is_null($key2)) $conditions[] = "key2 = '" . sqlite_escape_string($key2) . "'";
-		
-		if (count($conditions) === 0) return '1';
-		
-		$condition = join(' AND ', $conditions);
-		
-		return $condition;
-	}
-	
-	
-}
 
+class SQLPermanentStorage
+{
+    private $db;
+
+    public function __construct($name, $config = null)
+    {
+        if (is_null($config)) {
+            $config = \SimpleSAML\Configuration::getInstance();
+        }
+
+        $datadir = $config->getPathValue('datadir', 'data/');
+
+        if (!is_dir($datadir)) {
+            throw new \Exception('Data directory ['.$datadir.'] does not exist');
+        } elseif (!is_writable($datadir)) {
+            throw new \Exception('Data directory ['.$datadir.'] is not writable');
+        }
+
+        $sqllitedir = $datadir.'sqllite/';
+        if (!is_dir($sqllitedir)) {
+            mkdir($sqllitedir);
+        }
+
+        $dbfile = 'sqlite:'.$sqllitedir.$name.'.sqlite';
+        if ($this->db = new \PDO($dbfile)) {
+            $q = @$this->db->query('SELECT key1 FROM data LIMIT 1');
+            if ($q === false) {
+                $this->db->exec('
+		    CREATE TABLE data (
+                        key1 text, 
+                        key2 text,
+                        type text,
+                        value text,
+                        created timestamp,
+                        updated timestamp,
+                        expire timestamp,
+                        PRIMARY KEY (key1,key2,type)
+                    );
+                ');
+            }
+        } else {
+            throw new \Exception('Error creating SQL lite database ['.$dbfile.'].');
+        }
+    }
+
+    public function set($type, $key1, $key2, $value, $duration = null)
+    {
+        if ($this->exists($type, $key1, $key2)) {
+            $this->update($type, $key1, $key2, $value, $duration);
+        } else {
+            $this->insert($type, $key1, $key2, $value, $duration);
+        }
+    }
+
+    private function insert($type, $key1, $key2, $value, $duration = null)
+    {
+        $expire = is_null($duration) ? null : (time() + $duration);
+
+        $query = "INSERT INTO data (key1, key2, type, created, updated, expire, value)".
+            " VALUES(:key1, :key2, :type, :created, :updated, :expire, :value)";
+        $prepared = $this->db->prepare($query);
+        $data = [':key1' => $key1, ':key2' => $key2,
+            ':type' => $type, ':created' => time(),
+            ':updated' => time(), ':expire' => $expire,
+            ':value' => serialize($value)];
+        $prepared->execute($data);
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        return $results;
+    }
+
+    private function update($type, $key1, $key2, $value, $duration = null)
+    {
+        $expire = is_null($duration) ? null : (time() + $duration);
+
+        $query = "UPDATE data SET updated = :updated, value = :value, ".
+            "expire = :expire WHERE key1 = :key1 AND key2 = :key2 AND type = :type";
+        $prepared = $this->db->prepare($query);
+        $data = [':key1' => $key1, ':key2' => $key2,
+            ':type' => $type, ':updated' => time(),
+            ':expire' => $expire, ':value' => serialize($value)];
+        $prepared->execute($data);
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        return $results;
+    }
+
+    public function get($type = null, $key1 = null, $key2 = null)
+    {
+        $conditions = $this->getCondition($type, $key1, $key2);
+        $query = 'SELECT * FROM data WHERE '.$conditions;
+
+        $prepared = $this->db->prepare($query);
+        $prepared->execute();
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        if (count($results) !== 1) {
+            return null;
+        }
+
+        $res = $results[0];
+        $res['value'] = unserialize($res['value']);
+        return $res;
+    }
+
+    /*
+     * Return the value directly (not in a container)
+     */
+    public function getValue($type = null, $key1 = null, $key2 = null)
+    {
+        $res = $this->get($type, $key1, $key2);
+        if ($res === null) {
+            return null;
+        }
+        return $res['value'];
+    }
+
+    public function exists($type, $key1, $key2)
+    {
+        $query = 'SELECT * FROM data WHERE type = :type AND key1 = :key1 AND key2 = :key2 LIMIT 1';
+        $prepared = $this->db->prepare($query);
+        $data = [':type' => $type, ':key1' => $key1, ':key2' => $key2];
+        $prepared->execute($data);
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        return (count($results) == 1);
+    }
+
+    public function getList($type = null, $key1 = null, $key2 = null)
+    {
+        $conditions = $this->getCondition($type, $key1, $key2);
+        $query = 'SELECT * FROM data WHERE '.$conditions;
+        $prepared = $this->db->prepare($query);
+        $prepared->execute();
+
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        if (count($results) == 0) {
+            return null;
+        }
+
+        foreach ($results as $key => $value) {
+            $results[$key]['value'] = unserialize($results[$key]['value']);
+        }
+        return $results;
+    }
+
+    public function getKeys($type = null, $key1 = null, $key2 = null, $whichKey = 'type')
+    {
+        if (!in_array($whichKey, ['key1', 'key2', 'type'], true)) {
+            throw new \Exception('Invalid key type');
+        }
+
+        $conditions = $this->getCondition($type, $key1, $key2);
+        $query = 'SELECT DISTINCT :whichKey FROM data WHERE '.$conditions;
+        $prepared = $this->db->prepare($query);
+        $data = ['whichKey' => $whichKey];
+        $prepared->execute($data);
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+
+        if (count($results) == 0) {
+            return null;
+        }
+
+        $resarray = [];
+        foreach ($results as $key => $value) {
+            $resarray[] = $value[$whichKey];
+        }
+        return $resarray;
+    }
+
+    public function remove($type, $key1, $key2)
+    {
+        $query = 'DELETE FROM data WHERE type = :type AND key1 = :key1 AND key2 = :key2';
+        $prepared = $this->db->prepare($query);
+        $data = [':type' => $type, ':key1' => $key1, ':key2' => $key2];
+        $prepared->execute($data);
+        $results = $prepared->fetchAll(\PDO::FETCH_ASSOC);
+        return (count($results) == 1);
+    }
+
+    public function removeExpired()
+    {
+        $query = "DELETE FROM data WHERE expire IS NOT NULL AND expire < :expire";
+        $prepared = $this->db->prepare($query);
+        $data = [':expire' => time()];
+        $prepared->execute($data);
+        return $prepared->rowCount();
+    }
+
+    /**
+     * Create a SQL condition statement based on parameters
+     */
+    private function getCondition($type = null, $key1 = null, $key2 = null)
+    {
+        $conditions = [];
+        if (!is_null($type)) {
+            $conditions[] = "type = ".$this->db->quote($type);
+        }
+        if (!is_null($key1)) {
+            $conditions[] = "key1 = ".$this->db->quote($key1);
+        }
+        if (!is_null($key2)) {
+            $conditions[] = "key2 = ".$this->db->quote($key2);
+        }
+
+        $conditions[] = "(expire IS NULL OR expire >= ".time().")";
+        return join(' AND ', $conditions);
+    }
+}
diff --git a/modules/core/locales/ar/LC_MESSAGES/core.po b/modules/core/locales/ar/LC_MESSAGES/core.po
index 35c36fccd75b73807530865718ffc9db311c47ce..84c0fc10ca1ca5631ce6175e2751a6bf68f3f968 100644
--- a/modules/core/locales/ar/LC_MESSAGES/core.po
+++ b/modules/core/locales/ar/LC_MESSAGES/core.po
@@ -179,8 +179,8 @@ msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>انت لا تستخدم HTTPS</strong> - محادثة مشفرة مع المستخدم. HTTP جيد"
 " للاختبارات لكن في بيئة النظام المبدئي ينبغي استخدام HTTPS. [ <a "
-"href=\"http://rnd.feide.no/contents/simplesamlphp-maintenance-and-"
-"configuration\">read more about SimpleSAMLphp maintenance</a>]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">read more about SimpleSAMLphp maintenance</a>]"
 
 msgid "{core:frontpage:federation}"
 msgstr "الدخول الموحد"
@@ -376,8 +376,8 @@ msgid ""
 msgstr ""
 "<strong>انت لا تستخدم HTTPS</strong> - محادثة مشفرة مع المستخدم. HTTP جيد"
 " للاختبارات لكن في بيئة النظام المبدئي ينبغي استخدام HTTPS. [ <a "
-"href=\"http://rnd.feide.no/contents/simplesamlphp-maintenance-and-"
-"configuration\">read more about SimpleSAMLphp maintenance</a>]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">read more about SimpleSAMLphp maintenance</a>]"
 
 msgid "Metadata"
 msgstr "البيانات الوصفية/الميتاداتا "
diff --git a/modules/core/locales/cs/LC_MESSAGES/core.po b/modules/core/locales/cs/LC_MESSAGES/core.po
index 5293daa9a89a9e34e3006e15654f769a89f56b1a..0c5a0b5c613eeca008b188e005dd65acbe14d84d 100644
--- a/modules/core/locales/cs/LC_MESSAGES/core.po
+++ b/modules/core/locales/cs/LC_MESSAGES/core.po
@@ -184,8 +184,8 @@ msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>Nepoužíváte HTTPS</strong> - šivrovanou komunikaci s uživatelem. "
 "HTTP je vhodné jen k testovacím účelům, pro produkční účely použijte "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">ÄŚtete vĂ­ce o ĂşdrĹľbÄ› SimpleSAMLphp</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">ÄŚtete vĂ­ce o ĂşdrĹľbÄ› SimpleSAMLphp</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federace"
@@ -386,8 +386,8 @@ msgid ""
 msgstr ""
 "<strong>Nepoužíváte HTTPS</strong> - šivrovanou komunikaci s uživatelem. "
 "HTTP je vhodné jen k testovacím účelům, pro produkční účely použijte "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">ÄŚtete vĂ­ce o ĂşdrĹľbÄ› SimpleSAMLphp</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">ÄŚtete vĂ­ce o ĂşdrĹľbÄ› SimpleSAMLphp</a> ]"
 
 msgid "Metadata"
 msgstr "Metadata"
diff --git a/modules/core/locales/da/LC_MESSAGES/core.po b/modules/core/locales/da/LC_MESSAGES/core.po
index 6ae96bedf513a9cab2613878602f2367971ed107..ed0dbe54c6bce2d86f1b9ce9b4b3234e70875041 100644
--- a/modules/core/locales/da/LC_MESSAGES/core.po
+++ b/modules/core/locales/da/LC_MESSAGES/core.po
@@ -188,8 +188,8 @@ msgstr ""
 "brugeren. SimpleSAMLphp vil fungere uden problemer med HTTP alene, men "
 "hvis du anvender systemet i produktionssystemer, anbefales det stærkt at "
 "benytte sikker kommunikation i form af HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">læs mere i dokumentet: SimpleSAMLphp maintenance</a> ] "
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">læs mere i dokumentet: SimpleSAMLphp maintenance</a> ] "
 
 msgid "{core:frontpage:federation}"
 msgstr "Føderation"
@@ -388,8 +388,8 @@ msgstr ""
 "brugeren. SimpleSAMLphp vil fungere uden problemer med HTTP alene, men "
 "hvis du anvender systemet i produktionssystemer, anbefales det stærkt at "
 "benytte sikker kommunikation i form af HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">læs mere i dokumentet: SimpleSAMLphp maintenance</a> ] "
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">læs mere i dokumentet: SimpleSAMLphp maintenance</a> ] "
 
 msgid "Metadata"
 msgstr "Metadata"
diff --git a/modules/core/locales/de/LC_MESSAGES/core.po b/modules/core/locales/de/LC_MESSAGES/core.po
index 5aff6c3654100ae20734a5e0706d5b94c4bafffc..c6648ced42ba13a2c629d44045331a7dcd68f94d 100644
--- a/modules/core/locales/de/LC_MESSAGES/core.po
+++ b/modules/core/locales/de/LC_MESSAGES/core.po
@@ -184,8 +184,8 @@ msgstr ""
 "<strong>Sie benutzen keine HTTPS</strong> - verschlĂĽsselte Kommunikation "
 "mit dem Nutzer. SimpleSAMLphp funktioniert zum Testen auch mit HTTP "
 "problemlos, aber in einer Produktionsumgebung sollten Sie HTTPS benutzen."
-" [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Lesen sie mehr ĂĽber die Verwaltung von SimpleSAMLphp</a> "
+" [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Lesen sie mehr ĂĽber die Verwaltung von SimpleSAMLphp</a> "
 "]"
 
 msgid "{core:frontpage:federation}"
@@ -393,8 +393,8 @@ msgstr ""
 "<strong>Sie benutzen keine HTTPS</strong> - verschlĂĽsselte Kommunikation "
 "mit dem Nutzer. SimpleSAMLphp funktioniert zum Testen auch mit HTTP "
 "problemlos, aber in einer Produktionsumgebung sollten Sie HTTPS benutzen."
-" [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Lesen sie mehr ĂĽber die Verwaltung von SimpleSAMLphp</a> "
+" [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Lesen sie mehr ĂĽber die Verwaltung von SimpleSAMLphp</a> "
 "]"
 
 msgid "Metadata"
diff --git a/modules/core/locales/el/LC_MESSAGES/core.po b/modules/core/locales/el/LC_MESSAGES/core.po
index f99d522c286dd0a4745cfdf745c020ff909c72c4..a2f7c1563303b807287a7828262619075a2bc061 100644
--- a/modules/core/locales/el/LC_MESSAGES/core.po
+++ b/modules/core/locales/el/LC_MESSAGES/core.po
@@ -206,8 +206,8 @@ msgstr ""
 "Δεν χρησιμοποιείτε <strong>HTTPS</strong> για κρυπτογραφημένη επικοινωνία"
 " με τον χρήστη. Το HTTP επαρκεί για δοκιμαστικούς σκοπούς, ωστόσο σε "
 "περιβάλλον παραγωγής θα πρέπει να χρησιμοποιήσετε HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Διαβάστε περισσότερα...</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Διαβάστε περισσότερα...</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Ομοσπονδία"
@@ -427,8 +427,8 @@ msgstr ""
 "Δεν χρησιμοποιείτε <strong>HTTPS</strong> για κρυπτογραφημένη επικοινωνία"
 " με τον χρήστη. Το HTTP επαρκεί για δοκιμαστικούς σκοπούς, ωστόσο σε "
 "περιβάλλον παραγωγής θα πρέπει να χρησιμοποιήσετε HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Διαβάστε περισσότερα...</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Διαβάστε περισσότερα...</a> ]"
 
 msgid "Metadata"
 msgstr "Μεταδεδομένα"
diff --git a/modules/core/locales/en/LC_MESSAGES/core.po b/modules/core/locales/en/LC_MESSAGES/core.po
index bf9ee93f84563aa26e9c3d3fc638d1737b66bdb9..470d08a3df25530f15743a4499ff3e4a06679917 100644
--- a/modules/core/locales/en/LC_MESSAGES/core.po
+++ b/modules/core/locales/en/LC_MESSAGES/core.po
@@ -54,6 +54,30 @@ msgstr "OpenID Provider site - Alpha version (test code)"
 msgid "{core:frontpage:link_doc_install}"
 msgstr "Installing SimpleSAMLphp"
 
+msgid "{core:frontpage:link_consentAdmin}"
+msgstr "Consent Administration"
+
+msgid "{core:frontpage:link_memcacheMonitor}"
+msgstr "MemCache Statistics"
+
+msgid "{core:frontpage:link_oauth}"
+msgstr "OAuth Consumer Registry"
+
+msgid "{core:frontpage:link_cron}"
+msgstr "Cron module information page"
+
+msgid "{core:frontpage:link_statistics}"
+msgstr "Show statistics"
+
+msgid "{core:frontpage:link_statistics_metadata}"
+msgstr "Show statistics metadata"
+
+msgid "{core:frontpage:link_metarefresh}"
+msgstr "Metarefresh: fetch metadata"
+
+msgid "{core:frontpage:link_sanitycheck}"
+msgstr "Sanity check of your SimpleSAMLphp setup"
+
 msgid "{core:frontpage:link_diagnostics}"
 msgstr "Diagnostics on hostname, port and protocol"
 
@@ -142,6 +166,9 @@ msgstr "You are logged in as administrator"
 msgid "{core:frontpage:auth}"
 msgstr "Authentication"
 
+msgid "{core:frontpage:logout}"
+msgstr "Logout"
+
 msgid "{core:no_metadata:suggestion_user_link}"
 msgstr ""
 "If you are an user who received this error after following a link on a "
@@ -336,6 +363,9 @@ msgstr "Configure Shibboleth 1.3 SP to work with SimpleSAMLphp IdP"
 msgid "Using the back and forward buttons in the web browser."
 msgstr "Using the back and forward buttons in the web browser."
 
+msgid "PHP cURL extension missing. Cannot check for SimpleSAMLphp updates."
+msgstr "PHP cURL extension missing. Cannot check for SimpleSAMLphp updates."
+
 msgid ""
 "You are running an outdated version of SimpleSAMLphp. Please update to <a"
 " href=\"%LATEST_URL%\">the latest version</a> as soon as possible."
diff --git a/modules/core/locales/eu/LC_MESSAGES/core.po b/modules/core/locales/eu/LC_MESSAGES/core.po
index 18d8bd793d6788186ca459916a727509e49ea24d..d979950a1de6dcc8101453a0318bd930b3df4647 100644
--- a/modules/core/locales/eu/LC_MESSAGES/core.po
+++ b/modules/core/locales/eu/LC_MESSAGES/core.po
@@ -185,8 +185,8 @@ msgstr ""
 "<strong>Ez zara erabiltzen ari HTTPSak</strong> - erabiltzailearekin "
 "zifratutako komunikazioak. HTTP zuzen ibiltzen da ebaluaketa ingurunetan,"
 " baina ustiapenean erabili behar baduzu, HTTPS erabili beharko zenuke. [ "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei "
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei "
 "buruz </a> ]"
 
 msgid "{core:frontpage:federation}"
@@ -392,8 +392,8 @@ msgstr ""
 "<strong>Ez zara erabiltzen ari HTTPSak</strong> - erabiltzailearekin "
 "zifratutako komunikazioak. HTTP zuzen ibiltzen da ebaluaketa ingurunetan,"
 " baina ustiapenean erabili behar baduzu, HTTPS erabili beharko zenuke. [ "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei "
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Irakur ezazu gehiago SimpleSAMLphp-ren mantentze-lanei "
 "buruz </a> ]"
 
 msgid "Metadata"
diff --git a/modules/core/locales/fr/LC_MESSAGES/core.po b/modules/core/locales/fr/LC_MESSAGES/core.po
index c00c93ab2e3c0c3cee7c85dd89a166c8f4e9b15c..188d437f3ea0d032f0504322c347cc1951bd8aad 100644
--- a/modules/core/locales/fr/LC_MESSAGES/core.po
+++ b/modules/core/locales/fr/LC_MESSAGES/core.po
@@ -187,8 +187,8 @@ msgstr ""
 "avec l'utilisateur.  Utiliser SimpleSAMLphp marchera parfaitement avec "
 "HTTP pour des tests, mais si vous voulez l'utiliser dans un environnement"
 " de production, vous devriez utiliser HTTPS. [  <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">En lire plus sur la maintenance de SimpleSAMLphp</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">En lire plus sur la maintenance de SimpleSAMLphp</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Fédération"
@@ -399,8 +399,8 @@ msgstr ""
 "avec l'utilisateur.  Utiliser SimpleSAMLphp marchera parfaitement avec "
 "HTTP pour des tests, mais si vous voulez l'utiliser dans un environnement"
 " de production, vous devriez utiliser HTTPS. [  <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">En lire plus sur la maintenance de SimpleSAMLphp</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">En lire plus sur la maintenance de SimpleSAMLphp</a> ]"
 
 msgid "Metadata"
 msgstr "Métadonnées"
diff --git a/modules/core/locales/he/LC_MESSAGES/core.po b/modules/core/locales/he/LC_MESSAGES/core.po
index 167d0457e4476bcf91c599bec6d81ef2d58d0726..ea53dbbe1b247484ad4de84cfca8124722cb834d 100644
--- a/modules/core/locales/he/LC_MESSAGES/core.po
+++ b/modules/core/locales/he/LC_MESSAGES/core.po
@@ -174,8 +174,8 @@ msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>אתה לא משתמש ב- HTTPS </strong> - התקשרות מוצפנת עם המשתמש. HTTP "
 "עובד בסדר למטרות בדיקה, אולם למערכות אמיתיות, כדי להשתמש ה HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\"> קרא עוד על תחזוק SimpleSAMLphp </a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\"> קרא עוד על תחזוק SimpleSAMLphp </a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "איחוד"
@@ -369,8 +369,8 @@ msgid ""
 msgstr ""
 "<strong>אתה לא משתמש ב- HTTPS </strong> - התקשרות מוצפנת עם המשתמש. HTTP "
 "עובד בסדר למטרות בדיקה, אולם למערכות אמיתיות, כדי להשתמש ה HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\"> קרא עוד על תחזוק SimpleSAMLphp </a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\"> קרא עוד על תחזוק SimpleSAMLphp </a> ]"
 
 msgid "Metadata"
 msgstr "מטא-נתונים"
diff --git a/modules/core/locales/hr/LC_MESSAGES/core.po b/modules/core/locales/hr/LC_MESSAGES/core.po
index 41bf6b81c1c1c194a7074592f9beb917c9d0696c..4e0311f3db3fe617ff3177d05b342761e15a33ea 100644
--- a/modules/core/locales/hr/LC_MESSAGES/core.po
+++ b/modules/core/locales/hr/LC_MESSAGES/core.po
@@ -192,8 +192,8 @@ msgstr ""
 "<strong>Ne koristite HTTPS</strong> - kriptiranu komunikaciju s "
 "korisnikom. HTTP se moĹľe koristiti za potrebe testiranja, ali u "
 "produkcijskom okruĹľenju trebali biste koristiti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Pročitajte više o SimpleSAMLphp postavkama</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Pročitajte više o SimpleSAMLphp postavkama</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federacija"
@@ -411,8 +411,8 @@ msgstr ""
 "<strong>Ne koristite HTTPS</strong> - kriptiranu komunikaciju s "
 "korisnikom. HTTP se moĹľe koristiti za potrebe testiranja, ali u "
 "produkcijskom okruĹľenju trebali biste koristiti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Pročitajte više o SimpleSAMLphp postavkama</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Pročitajte više o SimpleSAMLphp postavkama</a> ]"
 
 msgid "Metadata"
 msgstr "Metapodaci"
diff --git a/modules/core/locales/hu/LC_MESSAGES/core.po b/modules/core/locales/hu/LC_MESSAGES/core.po
index 078427f461a1ed49bae5df3a54f2f3d95e842726..2304e086d459c8a2ede5de935fb6b58b6d7d5348 100644
--- a/modules/core/locales/hu/LC_MESSAGES/core.po
+++ b/modules/core/locales/hu/LC_MESSAGES/core.po
@@ -189,8 +189,8 @@ msgstr ""
 "<strong>Nem HTTPS protokollt használ</strong> - nem titkosított a "
 "kommunikáció! HTTP jó megoldás lehet teszt rendszerek esetében, de az "
 "éles rendszerben lehetőség szerint használjon HTTPS-t! [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Többet olvashat a SimpleSAMLphp beállításáról</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Többet olvashat a SimpleSAMLphp beállításáról</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Föderáció"
@@ -393,8 +393,8 @@ msgstr ""
 "<strong>Nem HTTPS protokollt használ</strong> - nem titkosított a "
 "kommunikáció! HTTP jó megoldás lehet teszt rendszerek esetében, de az "
 "éles rendszerben lehetőség szerint használjon HTTPS-t! [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Többet olvashat a SimpleSAMLphp beállításáról</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Többet olvashat a SimpleSAMLphp beállításáról</a> ]"
 
 msgid "Metadata"
 msgstr "Metaadat"
diff --git a/modules/core/locales/id/LC_MESSAGES/core.po b/modules/core/locales/id/LC_MESSAGES/core.po
index 757ecc8d8fc7aabc036ba0d0ea369a97a7829371..75646d0a570c75863ca422da57c77de83b69ca91 100644
--- a/modules/core/locales/id/LC_MESSAGES/core.po
+++ b/modules/core/locales/id/LC_MESSAGES/core.po
@@ -185,8 +185,8 @@ msgstr ""
 "<strong>Anda tidak menggunakan HTTPS</strong> - komunikasi yang "
 "dienkripsi dengan user. HTTP bekerja baik-baik saja untuk tujuan "
 "pengetesan , tapi dalam lingkungan produksi, Anda sebaiknya menggunakan "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Baca lebih lanjut tentang proses pemeliraan "
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Baca lebih lanjut tentang proses pemeliraan "
 "SimpleSAMLphp.</a> ]"
 
 msgid "{core:frontpage:federation}"
@@ -395,8 +395,8 @@ msgstr ""
 "<strong>Anda tidak menggunakan HTTPS</strong> - komunikasi yang "
 "dienkripsi dengan user. HTTP bekerja baik-baik saja untuk tujuan "
 "pengetesan , tapi dalam lingkungan produksi, Anda sebaiknya menggunakan "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Baca lebih lanjut tentang proses pemeliraan "
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Baca lebih lanjut tentang proses pemeliraan "
 "SimpleSAMLphp.</a> ]"
 
 msgid "Metadata"
diff --git a/modules/core/locales/it/LC_MESSAGES/core.po b/modules/core/locales/it/LC_MESSAGES/core.po
index 1333903f9a79ced5f29fb668897cbf47e4e4c72d..555f86a8e2b379ffd15042f3ec814dbf4470b3c4 100644
--- a/modules/core/locales/it/LC_MESSAGES/core.po
+++ b/modules/core/locales/it/LC_MESSAGES/core.po
@@ -190,8 +190,8 @@ msgstr ""
 "<strong>Non stai usando HTTPS</strong> - comunicazione cifrata con "
 "l'utente. HTTP pu&ograve; funzionare per i test, ma in un ambiente di "
 "produzione si dovrebbe usare HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Maggiori informazioni sulla manutenzione di "
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Maggiori informazioni sulla manutenzione di "
 "SimpleSAMLphp</a> ]"
 
 msgid "{core:frontpage:federation}"
@@ -404,8 +404,8 @@ msgstr ""
 "<strong>Non stai usando HTTPS</strong> - comunicazione cifrata con "
 "l'utente. HTTP pu&ograve; funzionare per i test, ma in un ambiente di "
 "produzione si dovrebbe usare HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Maggiori informazioni sulla manutenzione di "
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Maggiori informazioni sulla manutenzione di "
 "SimpleSAMLphp</a> ]"
 
 msgid "Metadata"
diff --git a/modules/core/locales/ja/LC_MESSAGES/core.po b/modules/core/locales/ja/LC_MESSAGES/core.po
index 2e296fb0d9dfde9dc10cd88b4a5a3218b9a437fc..457a8cc931d9e778b50ecd4253383d8e288bcc32 100644
--- a/modules/core/locales/ja/LC_MESSAGES/core.po
+++ b/modules/core/locales/ja/LC_MESSAGES/core.po
@@ -166,8 +166,8 @@ msgstr ""
 msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>あなたはHTTPS(暗号化通信)を行っていません。</strong>HTTPはテスト環境であれば正常に動作します、しかし製品環境ではHTTPSを使用するべきです。["
-" <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">詳しくは SimpleSAMLphp メンテナンス情報を読んでください。</a> ]"
+" <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">詳しくは SimpleSAMLphp メンテナンス情報を読んでください。</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "連携"
@@ -352,8 +352,8 @@ msgid ""
 "maintenance\">Read more about SimpleSAMLphp maintenance</a> ]"
 msgstr ""
 "<strong>あなたはHTTPS(暗号化通信)を行っていません。</strong>HTTPはテスト環境であれば正常に動作します、しかし製品環境ではHTTPSを使用するべきです。["
-" <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">詳しくは SimpleSAMLphp メンテナンス情報を読んでください。</a> ]"
+" <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">詳しくは SimpleSAMLphp メンテナンス情報を読んでください。</a> ]"
 
 msgid "Metadata"
 msgstr "メタデータ"
diff --git a/modules/core/locales/lb/LC_MESSAGES/core.po b/modules/core/locales/lb/LC_MESSAGES/core.po
index 5c30d24a4523063590a1c7f6f4ded16b58aa18a8..da87760a77048056f117e49d6349b6ed09f1d2ab 100644
--- a/modules/core/locales/lb/LC_MESSAGES/core.po
+++ b/modules/core/locales/lb/LC_MESSAGES/core.po
@@ -94,8 +94,8 @@ msgstr ""
 "<strong>Der benotzt ken HTTPS</strong> - verschlësselt Kommunikatioun mat"
 " dem Benotzer. SimpleSAMLphp funktionéiert einwandfräi mat HTTP fir "
 "Testzwéecker mais an engem produktiven Emfeld sollt et besser mat HTTPS "
-"lafen. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Liest méi iwert Maintenance vun SimpleSAMLphp</a> ]"
+"lafen. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Liest méi iwert Maintenance vun SimpleSAMLphp</a> ]"
 
 msgid "{core:frontpage:required_radius}"
 msgstr "NĂ©ideg fir RADIUS"
@@ -187,8 +187,8 @@ msgstr ""
 "<strong>Der benotzt ken HTTPS</strong> - verschlësselt Kommunikatioun mat"
 " dem Benotzer. SimpleSAMLphp funktionéiert einwandfräi mat HTTP fir "
 "Testzwéecker mais an engem produktiven Emfeld sollt et besser mat HTTPS "
-"lafen. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Liest méi iwert Maintenance vun SimpleSAMLphp</a> ]"
+"lafen. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Liest méi iwert Maintenance vun SimpleSAMLphp</a> ]"
 
 msgid "Metadata"
 msgstr "Meta Données"
diff --git a/modules/core/locales/lt/LC_MESSAGES/core.po b/modules/core/locales/lt/LC_MESSAGES/core.po
index f9d0421e331fecb61d6df0abf20932c1cb63b403..aa83f7aaa0d6907754c2a90702d01d0b31bdf6fd 100644
--- a/modules/core/locales/lt/LC_MESSAGES/core.po
+++ b/modules/core/locales/lt/LC_MESSAGES/core.po
@@ -187,8 +187,8 @@ msgstr ""
 "<strong>Jūs nenaudojate HTTPS</strong> - šifruotos komunikacijos su "
 "vartotoju. HTTP puikiai tinka testavimo reikmÄ—ms, taÄŤiau realioje "
 "aplinkoje turÄ—tumÄ—te naudoti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Skaityti daugiau apie SimpleSAMLphp priežiūrą</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Skaityti daugiau apie SimpleSAMLphp priežiūrą</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federacija"
@@ -397,8 +397,8 @@ msgstr ""
 "<strong>Jūs nenaudojate HTTPS</strong> - šifruotos komunikacijos su "
 "vartotoju. HTTP puikiai tinka testavimo reikmÄ—ms, taÄŤiau realioje "
 "aplinkoje turÄ—tumÄ—te naudoti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Skaityti daugiau apie SimpleSAMLphp priežiūrą</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Skaityti daugiau apie SimpleSAMLphp priežiūrą</a> ]"
 
 msgid "Metadata"
 msgstr "Metaduomenys"
diff --git a/modules/core/locales/lv/LC_MESSAGES/core.po b/modules/core/locales/lv/LC_MESSAGES/core.po
index 9a6df6db5338237d926c15c82eb56283f0b76812..61743892b824f10f948cc63b0f852577b5ceec8d 100644
--- a/modules/core/locales/lv/LC_MESSAGES/core.po
+++ b/modules/core/locales/lv/LC_MESSAGES/core.po
@@ -177,8 +177,8 @@ msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>Jūs neizmantojat HTTPS</strong> - šifrētu komunikāciju ar "
 "lietotāju. HTTP ir labs testa nolūkiem, bet ražošanā jāizmanto HTTPS. [ "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Lasiet vairāk par SimpleSAMLphp uzturēšanu</a> ]"
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Lasiet vairāk par SimpleSAMLphp uzturēšanu</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federācija"
@@ -375,8 +375,8 @@ msgid ""
 msgstr ""
 "<strong>Jūs neizmantojat HTTPS</strong> - šifrētu komunikāciju ar "
 "lietotāju. HTTP ir labs testa nolūkiem, bet ražošanā jāizmanto HTTPS. [ "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Lasiet vairāk par SimpleSAMLphp uzturēšanu</a> ]"
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Lasiet vairāk par SimpleSAMLphp uzturēšanu</a> ]"
 
 msgid "Metadata"
 msgstr "Metadati"
diff --git a/modules/core/locales/nb/LC_MESSAGES/core.po b/modules/core/locales/nb/LC_MESSAGES/core.po
index 60b841b6f4e0233fc5d3dafc009d283dc28604e3..c10d9d2e5ca974ac419976cad669912ef0699d32 100644
--- a/modules/core/locales/nb/LC_MESSAGES/core.po
+++ b/modules/core/locales/nb/LC_MESSAGES/core.po
@@ -185,8 +185,8 @@ msgstr ""
 "<strong>Du bruker ikke HTTPS</strong> - kryptert kommunikasjon med "
 "brukeren. HTTP fungerer utmerket til testformĂĄl, men  i et "
 "produksjonsmiljø anbefales sterkt å skru på sikker kommunikasjon med "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Les mer i dokumentet: SimpleSAMLphp maintenance</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Les mer i dokumentet: SimpleSAMLphp maintenance</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Føderasjon"
@@ -389,8 +389,8 @@ msgstr ""
 "<strong>Du bruker ikke HTTPS</strong> - kryptert kommunikasjon med "
 "brukeren. HTTP fungerer utmerket til testformĂĄl, men  i et "
 "produksjonsmiljø anbefales sterkt å skru på sikker kommunikasjon med "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Les mer i dokumentet: SimpleSAMLphp maintenance</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Les mer i dokumentet: SimpleSAMLphp maintenance</a> ]"
 
 msgid "Metadata"
 msgstr "Metadata"
diff --git a/modules/core/locales/nl/LC_MESSAGES/core.po b/modules/core/locales/nl/LC_MESSAGES/core.po
index edeee369edef093ca15dcd484b9a3b67ca2d0c81..d6404e871148310612fc4a7185ecf0a4ccd2b3b2 100644
--- a/modules/core/locales/nl/LC_MESSAGES/core.po
+++ b/modules/core/locales/nl/LC_MESSAGES/core.po
@@ -36,6 +36,9 @@ msgstr "Suggesties om dit probleem op te lossen:"
 msgid "{core:frontpage:login_as_admin}"
 msgstr "Login als beheerder"
 
+msgid "{core:frontpage:logout}"
+msgstr "Uitloggen"
+
 msgid "{core:short_sso_interval:warning}"
 msgstr ""
 "We hebben waargenomen dat u slechts een paar seconden geleden al "
@@ -137,6 +140,9 @@ msgstr ""
 "snel mogelijk te upgraden naar <a href=\"%LATEST_URL%\">de meest recente "
 "versie</a>."
 
+msgid "{core:frontpage:warnings_curlmissing}"
+msgstr "PHP cURL-extensie ontbreekt. Kan niet controleren op updates voor SimpleSAMLphp."
+
 msgid "{core:frontpage:loggedin_as_admin}"
 msgstr "Je bent ingelogd als beheerder"
 
diff --git a/modules/core/locales/nn/LC_MESSAGES/core.po b/modules/core/locales/nn/LC_MESSAGES/core.po
index cdbfc5684ac973fcd2fd98ea0fae48f73690841e..368dd7e76b37c2525b2126bf239176d2c92514eb 100644
--- a/modules/core/locales/nn/LC_MESSAGES/core.po
+++ b/modules/core/locales/nn/LC_MESSAGES/core.po
@@ -182,8 +182,8 @@ msgstr ""
 "brukaren. Du kan bruka SimpleSAMLphp uten HTTPS til testformĂĄl, men "
 "dersom du skal bruka SimpleSAMLphp i eit produksjonsmiljø, vil vi sterkt "
 "tilrĂĄ ĂĄ skru pĂĄ sikker kommunikasjon med HTTPS. [ Les meir i dokumentet: "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">SimpleSAMLphp maintenance</a> ]"
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">SimpleSAMLphp maintenance</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Føderasjon"
@@ -386,8 +386,8 @@ msgstr ""
 "brukaren. Du kan bruka SimpleSAMLphp uten HTTPS til testformĂĄl, men "
 "dersom du skal bruka SimpleSAMLphp i eit produksjonsmiljø, vil vi sterkt "
 "tilrĂĄ ĂĄ skru pĂĄ sikker kommunikasjon med HTTPS. [ Les meir i dokumentet: "
-"<a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">SimpleSAMLphp maintenance</a> ]"
+"<a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">SimpleSAMLphp maintenance</a> ]"
 
 msgid "Metadata"
 msgstr "Metadata"
diff --git a/modules/core/locales/pt/LC_MESSAGES/core.po b/modules/core/locales/pt/LC_MESSAGES/core.po
index c9aec1c5f23718477a8cc1864494b09c83242645..599cf95aac19d32fc5870fa66d3729c700f5b716 100644
--- a/modules/core/locales/pt/LC_MESSAGES/core.po
+++ b/modules/core/locales/pt/LC_MESSAGES/core.po
@@ -138,8 +138,8 @@ msgstr ""
 "<strong>Não está a ser usado HTTPS</strong> - comunicação cifrada com o "
 "utilizador. Para ambientes de teste, ligações HTTP são suficientes, mas "
 "num ambiente de produção deve ser usado HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Ler mais sobre manutenção do SimpleSAMLphp</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Ler mais sobre manutenção do SimpleSAMLphp</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federação"
@@ -296,8 +296,8 @@ msgstr ""
 "<strong>Não está a ser usado HTTPS</strong> - comunicação cifrada com o "
 "utilizador. Para ambientes de teste, ligações HTTP são suficientes, mas "
 "num ambiente de produção deve ser usado HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Ler mais sobre manutenção do SimpleSAMLphp</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Ler mais sobre manutenção do SimpleSAMLphp</a> ]"
 
 msgid "Metadata"
 msgstr "Metadados"
diff --git a/modules/core/locales/sl/LC_MESSAGES/core.po b/modules/core/locales/sl/LC_MESSAGES/core.po
index eaf0bcf67c795d4f22cee633404c83bffa3774a5..802a6f38c92d9cbce6effef674e8c7e3ce553e7d 100644
--- a/modules/core/locales/sl/LC_MESSAGES/core.po
+++ b/modules/core/locales/sl/LC_MESSAGES/core.po
@@ -177,8 +177,8 @@ msgstr ""
 "<strong>Ne uporabljate HTTPS</strong>-šifrirane komunikacije. "
 "SimpleSAMLphp deluje brez teĹľav na HTTP, vendar le za testne namene, za "
 "uporabo SimpleSAMLphp v produkcijskem okolju uporabite HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Preberite veÄŤ o SimpleSAMLphp vzdrĹľevanju</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Preberite veÄŤ o SimpleSAMLphp vzdrĹľevanju</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federacija"
@@ -380,8 +380,8 @@ msgstr ""
 "<strong>Ne uporabljate HTTPS</strong>-šifrirane komunikacije. "
 "SimpleSAMLphp deluje brez teĹľav na HTTP, vendar le za testne namene, za "
 "uporabo SimpleSAMLphp v produkcijskem okolju uporabite HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Preberite veÄŤ o SimpleSAMLphp vzdrĹľevanju</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Preberite veÄŤ o SimpleSAMLphp vzdrĹľevanju</a> ]"
 
 msgid "Metadata"
 msgstr "Metapodatki"
diff --git a/modules/core/locales/sr/LC_MESSAGES/core.po b/modules/core/locales/sr/LC_MESSAGES/core.po
index f500a2c6f41960e2433f4893752837be934e7e21..9f7a9ea2083b377d1b3b038fa6fed1956cf1194f 100644
--- a/modules/core/locales/sr/LC_MESSAGES/core.po
+++ b/modules/core/locales/sr/LC_MESSAGES/core.po
@@ -194,8 +194,8 @@ msgstr ""
 "<strong>Ne koristite HTTPS</strong> - kriptovanu komunikaciju s "
 "korisnikom. HTTP se moĹľe koristiti za potrebe testiranja, ali u "
 "produkcionom okruĹľenju trebali biste koristiti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Pročitajte više o SimpleSAMLphp podešavanjima</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Pročitajte više o SimpleSAMLphp podešavanjima</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federacija"
@@ -407,8 +407,8 @@ msgstr ""
 "<strong>Ne koristite HTTPS</strong> - kriptovanu komunikaciju s "
 "korisnikom. HTTP se moĹľe koristiti za potrebe testiranja, ali u "
 "produkcionom okruĹľenju trebali biste koristiti HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">Pročitajte više o SimpleSAMLphp podešavanjima</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Pročitajte više o SimpleSAMLphp podešavanjima</a> ]"
 
 msgid "Metadata"
 msgstr "Medapodaci"
diff --git a/modules/core/locales/sv/LC_MESSAGES/core.po b/modules/core/locales/sv/LC_MESSAGES/core.po
index f3d8a2c06fd45875d07da6193c0107fd98721f13..6adaceec51b3eb397f156ce0456c5a8eec24f448 100644
--- a/modules/core/locales/sv/LC_MESSAGES/core.po
+++ b/modules/core/locales/sv/LC_MESSAGES/core.po
@@ -181,8 +181,8 @@ msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>Du använder inte HTTPS</strong> - krypterad kommunikation med "
 "användaren. HTTP fungerar bra under test men i produktion ska du använda "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Läs mer i dokumentet SimpleSAMLphp maintenance</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Läs mer i dokumentet SimpleSAMLphp maintenance</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "Federation"
@@ -384,8 +384,8 @@ msgid ""
 msgstr ""
 "<strong>Du använder inte HTTPS</strong> - krypterad kommunikation med "
 "användaren. HTTP fungerar bra under test men i produktion ska du använda "
-"HTTPS. [ <a href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-"
-"and-configuration\">Läs mer i dokumentet SimpleSAMLphp maintenance</a> ]"
+"HTTPS. [ <a href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">Läs mer i dokumentet SimpleSAMLphp maintenance</a> ]"
 
 msgid "Metadata"
 msgstr "Metadata"
diff --git a/modules/core/locales/zh/LC_MESSAGES/core.po b/modules/core/locales/zh/LC_MESSAGES/core.po
index 4cd6c87ff307346ad212fb179ed62e349302993b..f883464c23da8b5a70db3b4816a382738e025155 100644
--- a/modules/core/locales/zh/LC_MESSAGES/core.po
+++ b/modules/core/locales/zh/LC_MESSAGES/core.po
@@ -162,8 +162,8 @@ msgstr "请求参数的长度被PHP Suhosin扩展限制了,请增大suhosin.ge
 msgid "{core:frontpage:warnings_https}"
 msgstr ""
 "<strong>你没有使用HTTPS</strong> - 和用户加密的通信。HTTP在测试目的下很好,但生产环境请使用HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">获取更多SimpleSAMLphp维护的信息</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">获取更多SimpleSAMLphp维护的信息</a> ]"
 
 msgid "{core:frontpage:federation}"
 msgstr "联盟"
@@ -347,8 +347,8 @@ msgid ""
 "maintenance\">Read more about SimpleSAMLphp maintenance</a> ]"
 msgstr ""
 "<strong>你没有使用HTTPS</strong> - 和用户加密的通信。HTTP在测试目的下很好,但生产环境请使用HTTPS. [ <a "
-"href=\"http://rnd.feide.no/content/simplesamlphp-maintenance-and-"
-"configuration\">获取更多SimpleSAMLphp维护的信息</a> ]"
+"href=\"https://simplesamlphp.org/docs/stable/simplesamlphp-maintenance"
+"\">获取更多SimpleSAMLphp维护的信息</a> ]"
 
 msgid "Metadata"
 msgstr "元信息"
diff --git a/modules/core/templates/_frontpage_menu.twig b/modules/core/templates/_frontpage_menu.twig
new file mode 100644
index 0000000000000000000000000000000000000000..3af633752872c47b9dfb17295676caccffe633dc
--- /dev/null
+++ b/modules/core/templates/_frontpage_menu.twig
@@ -0,0 +1,31 @@
+<div class="pure-g frontpage-menu">
+    <div class="pure-u-2-3">
+        <div class="pure-menu pure-menu-horizontal">
+            <ul class="pure-menu-list">
+                <li class="pure-menu-item{% if frontpage_section == "welcome" %} pure-menu-selected{% endif %}">
+                    <a href="frontpage_welcome.php" class="pure-menu-link">Welcome</a>
+                </li>
+                <li class="pure-menu-item{% if frontpage_section == "config" %} pure-menu-selected{% endif %}">
+                    <a href="frontpage_config.php" class="pure-menu-link">Configuration</a>
+                </li>
+                <li class="pure-menu-item{% if frontpage_section == "auth" %} pure-menu-selected{% endif %}">
+                    <a href="frontpage_auth.php" class="pure-menu-link">Authentication</a>
+                </li>
+                <li class="pure-menu-item{% if frontpage_section == "federation" %} pure-menu-selected{% endif %}">
+                    <a href="frontpage_federation.php" class="pure-menu-link">Federation</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+    <div class="pure-u-1-3">
+    {% if isadmin %}
+        <p class="float-r youareadmin">{{ '{core:frontpage:loggedin_as_admin}'|trans }}
+        <a href="{{ logouturl }}"><i class="fa fa-sign-out" title="{{ '{core:frontpage:logout}'|trans }}"></i></a>
+        </p>
+    {% else %}
+        <p class="float-r youareadmin">
+            <a href="{{ loginurl }}">{{ '{core:frontpage:login_as_admin}'|trans }}</a>
+        </p>
+    {% endif %}
+    </div>
+</div>
diff --git a/modules/core/templates/authsource_list.tpl.php b/modules/core/templates/authsource_list.tpl.php
index db0a7cede05e88b30b82fdfbae85b4f616adfe82..20522518defa804e70e6e850a8f4ef9447c4b9d2 100644
--- a/modules/core/templates/authsource_list.tpl.php
+++ b/modules/core/templates/authsource_list.tpl.php
@@ -4,14 +4,13 @@
  *
  */
 $this->data['header'] = 'Test authentication sources';
-
 $this->includeAtTemplateBase('includes/header.php');
 ?>
 <h1><?php echo $this->data['header']; ?></h1>
 <ul>
 <?php
 foreach ($this->data['sources'] as $id) {
-	echo '<li><a href="?as=' . htmlspecialchars(urlencode($id)) . '">' . htmlspecialchars($id) . '</a></li>';
+    echo '<li><a href="?as='.htmlspecialchars(urlencode($id)).'">'.htmlspecialchars($id).'</a></li>';
 }
 ?>
 </ul>
diff --git a/modules/core/templates/authsource_list.twig b/modules/core/templates/authsource_list.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c966180b7fb54b8ef8b304f65034ba1f7dfd1457
--- /dev/null
+++ b/modules/core/templates/authsource_list.twig
@@ -0,0 +1,11 @@
+{% set pagetitle = 'Test Authentication Sources'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>{{ header }}</h1>
+    <ul>
+    {% for key, name in sources %}
+        <li><a href="?as={{ name|escape('url') }}">{{ name|escape('html') }}</a></li>
+    {% endfor %}
+    </ul>
+{% endblock %}
diff --git a/modules/core/templates/base.twig b/modules/core/templates/base.twig
index 47a732abda4e6ae049b5111bf0bd442861dc78f3..96fcc07baeb873b82c4f94a4e6a17a002a40b500 100644
--- a/modules/core/templates/base.twig
+++ b/modules/core/templates/base.twig
@@ -2,23 +2,24 @@
 {% block contentwrapper %}
 {% if tabname %}
 <div id="portalmenu" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
-<ul class="tabset_tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
-{% for name, link in links %}
-{% if name == pageid %}
-<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active">
-<a href="#">{{ link.text|trans }}</a>
-</li>
-{% else %}
-<li class="ui-state-default ui-corner-top">
-<a href="{{ link.href }}">{{ link.text|trans }}</a>
-</li>
-{% endif %}
-{% endfor %}
-</ul>
-<div id="portalcontent" class="ui-tabs-panel ui-widget-content ui-corner-bottom">
+    <ul class="tabset_tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
+    {% for name, link in links %}
+    {% if name == pageid %}
+        <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active">
+            <a href="#">{{ link.text|trans }}</a>
+        </li>
+    {% else %}
+        <li class="ui-state-default ui-corner-top">
+            <a href="{{ link.href }}">{{ link.text|trans }}</a>
+        </li>
+    {% endif %}
+    {% endfor %}
+    </ul>
+    <div id="portalcontent" class="ui-tabs-panel ui-widget-content ui-corner-bottom">
 {% endif %}
 {{ block('content') }}
 {% if tabname %}
-</div></div>
+    </div>
+</div>
 {% endif %}
 {% endblock %}
diff --git a/modules/core/templates/cardinality_error.tpl.php b/modules/core/templates/cardinality_error.tpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..6dd78aa1b6168858a14063c815525b32fd2cba22
--- /dev/null
+++ b/modules/core/templates/cardinality_error.tpl.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Template which is shown when when an attribute violates a cardinality rule
+ *
+ * Parameters:
+ * - 'target': Target URL.
+ * - 'params': Parameters which should be included in the request.
+ *
+ * @package SimpleSAMLphp
+ */
+
+
+$this->data['cardinality_header'] = $this->t('{core:cardinality:cardinality_header}');
+$this->data['cardinality_text'] = $this->t('{core:cardinality:cardinality_text}');
+$this->data['problematic_attributes'] = $this->t('{core:cardinality:problematic_attributes}');
+
+$this->includeAtTemplateBase('includes/header.php');
+?>
+<h1><?php echo $this->data['cardinality_header']; ?></h1>
+<p><?php echo $this->data['cardinality_text']; ?></p>
+<h3><?php echo $this->data['problematic_attributes']; ?></h3>
+<dl class="cardinalityErrorAttributes">
+<?php
+foreach ($this->data['cardinalityErrorAttributes'] as $attr => $v) {
+    echo '<dt>'.$attr.'</td><dd>';
+    echo $this->t(
+        '{core:cardinality:got_want}',
+        ['%GOT%' => $v[0], '%WANT%' => htmlspecialchars($v[1])]
+    );
+    echo '</dd></tr>';
+}
+echo '</dl>';
+if (isset($this->data['LogoutURL'])) {
+    echo '<p><a href="'.htmlspecialchars($this->data['LogoutURL']).'>">'.$this->t('{status:logout}').'</a></p>';
+}
+$this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/frontpage_auth.tpl.php b/modules/core/templates/frontpage_auth.tpl.php
index f0594948f1e2f19d7f067de38c526c2908108e0a..afb55b30d72452381c8e02b3f17f346d5ac046dc 100644
--- a/modules/core/templates/frontpage_auth.tpl.php
+++ b/modules/core/templates/frontpage_auth.tpl.php
@@ -1,34 +1,30 @@
-<?php 
+<?php
 
 $this->data['header'] = $this->t('{core:frontpage:page_title}');
-$this->includeAtTemplateBase('includes/header.php'); 
+$this->includeAtTemplateBase('includes/header.php');
 
 ?>
 
 <?php
 if ($this->data['isadmin']) {
-	echo '<p class="float-r youareadmin">' . $this->t('{core:frontpage:loggedin_as_admin}') . '</p>';
+    echo '<p class="float-r youareadmin">'.$this->t('{core:frontpage:loggedin_as_admin}').'</p>';
 } else {
-	echo '<p class="float-r youareadmin"><a href="' . $this->data['loginurl'] . '">' . $this->t('{core:frontpage:login_as_admin}') . '</a></p>';
+    echo '<p class="float-r youareadmin"><a href="'.$this->data['loginurl'].'">'.
+        $this->t('{core:frontpage:login_as_admin}').'</a></p>';
 }
 ?>
 
-
-	
-<!--	<h2><?php echo $this->t('{core:frontpage:useful_links_header}'); ?></h2> -->
+<!-- <h2><?php echo $this->t('{core:frontpage:useful_links_header}'); ?></h2> -->
 <ul>
 <?php
-	foreach ($this->data['links_auth'] AS $link) {
-		echo '<li><a href="' . htmlspecialchars($link['href']) . '">' . $this->t($link['text']) . '</a>';
-		if (isset($link['deprecated']) && $link['deprecated']) {
-			echo ' <b>' . $this->t('{core:frontpage:deprecated}') . '</b>';
-		}
-		echo '</li>';
-	}
+foreach ($this->data['links_auth'] as $link) {
+    echo '<li><a href="'.htmlspecialchars($link['href']).'">'.$this->t($link['text']).'</a>';
+    if (isset($link['deprecated']) && $link['deprecated']) {
+        echo ' <b>'.$this->t('{core:frontpage:deprecated}').'</b>';
+    }
+    echo '</li>';
+}
 ?>
 </ul>
 
-	
-
-		
 <?php $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/frontpage_auth.twig b/modules/core/templates/frontpage_auth.twig
new file mode 100644
index 0000000000000000000000000000000000000000..cfe3c4f9d1f385e00bb3ecb2da497c0cf9e61013
--- /dev/null
+++ b/modules/core/templates/frontpage_auth.twig
@@ -0,0 +1,18 @@
+{% set pagetitle = '{core:frontpage:page_title}'|trans %}
+{% set frontpage_section = 'auth' %}
+{% extends "base.twig" %}
+
+{% block content %}
+    {% include "@core/_frontpage_menu.twig" %}
+
+    <ul>
+    {% for key, link in links_auth %}
+        <li>
+            <a href="{{ link.href }}">{{ link.text|trans|escape('html') }}</a>
+            {% if link.deprecated is defined and link.deprecated is not empty %}
+            <strong>{{ '{core:frontpage:deprecated}'|trans }}</strong>
+            {% endif %}
+        </li>
+    {% endfor %}
+    </ul>
+{% endblock %}
diff --git a/modules/core/templates/frontpage_config.tpl.php b/modules/core/templates/frontpage_config.tpl.php
index 4bf19eff9390aa5086561ed410b0f33ca5f7035b..10f7463cf305b6ceff462533f85f4c5140db68db 100644
--- a/modules/core/templates/frontpage_config.tpl.php
+++ b/modules/core/templates/frontpage_config.tpl.php
@@ -5,97 +5,74 @@ $this->includeAtTemplateBase('includes/header.php');
 
 ?>
 
-
 <!-- 
 <div id="tabdiv">
 <ul>
-	<li><a href="#welcome"><?php echo $this->t('{core:frontpage:welcome}'); ?></a></li>
-	<li><a href="#configuration"><?php echo $this->t('{core:frontpage:configuration}'); ?></a></li>
-	<li><a href="#metadata"><?php echo $this->t('{core:frontpage:metadata}'); ?></a></li>
+    <li><a href="#welcome"><?php echo $this->t('{core:frontpage:welcome}'); ?></a></li>
+    <li><a href="#configuration"><?php echo $this->t('{core:frontpage:configuration}'); ?></a></li>
+    <li><a href="#metadata"><?php echo $this->t('{core:frontpage:metadata}'); ?></a></li>
 </ul> -->
 <?php
 if ($this->data['isadmin']) {
-	echo '<p class="float-r youareadmin">' . $this->t('{core:frontpage:loggedin_as_admin}') . '</p>';
+    echo '<p class="float-r youareadmin">'.$this->t('{core:frontpage:loggedin_as_admin}').'</p>';
 } else {
-	echo '<p class="float-r youareadmin"><a href="' . $this->data['loginurl'] . '">' . $this->t('{core:frontpage:login_as_admin}') . '</a></p>';
+    echo '<p class="float-r youareadmin"><a href="'.$this->data['loginurl'].'">'.
+        $this->t('{core:frontpage:login_as_admin}').'</a></p>';
 }
 ?>
 
-
-
-
 <div style="margin-top: 1em;">
-	<code style="background: white; background: #f5f5f5; border: 1px dotted #bbb; padding: 1em;  color: #555" ><?php 
-		echo $this->data['directory'] . ' (' . $this->data['version'] . ')'; 
-	?></code>
+    <code style="background: white; background: #f5f5f5; border: 1px dotted #bbb; padding: 1em;  color: #555" ><?php
+    echo $this->data['directory'].' ('.$this->data['version'].')';
+    ?></code>
 </div>
 
-
-
 <div style="clear: both" class="enablebox mini">
-	<table>
-	
-	<?php
-	$icon_enabled  = '<img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="enabled" />';
-	$icon_disabled = '<img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="disabled" />';
-	?>
-	
-		<tr class="<?php echo $this->data['enablematrix']['saml20-idp'] ? 'enabled' : 'disabled'; ?>"><td>SAML 2.0 IdP</td>
-			<td><?php echo $this->data['enablematrix']['saml20-idp'] ? $icon_enabled : $icon_disabled; ?></td></tr>
-			
-		<tr class="<?php echo $this->data['enablematrix']['shib13-idp'] ? 'enabled' : 'disabled'; ?>"><td>Shib 1.3 IdP</td>
-			<td><?php echo $this->data['enablematrix']['shib13-idp'] ? $icon_enabled : $icon_disabled; ?></td></tr>
-		
-	</table>
-</div>
+    <table>
 
+    <?php
+    $icon_enabled  = '<img src="/'.$this->data['baseurlpath'].'resources/icons/silk/accept.png" alt="enabled" />';
+    $icon_disabled = '<img src="/'.$this->data['baseurlpath'].'resources/icons/silk/delete.png" alt="disabled" />';
+    echo '<tr class="'.($this->data['enablematrix']['saml20idp'] ? 'enabled' : 'disabled').'"><td>SAML 2.0 IdP</td>';
+    echo '<td>'.($this->data['enablematrix']['saml20idp'] ? $icon_enabled : $icon_disabled).'</td></tr>';
 
+    echo '<tr class="'.($this->data['enablematrix']['shib13idp'] ? 'enabled' : 'disabled').'"><td>Shib 1.3 IdP</td>';
+    echo '<td>'.($this->data['enablematrix']['shib13idp'] ? $icon_enabled : $icon_disabled).'</td></tr>';
+    ?>
+
+    </table>
+</div>
 
 <h2><?php echo $this->t('{core:frontpage:configuration}'); ?></h2>
 <ul>
 <?php
-	foreach ($this->data['links_config'] AS $link) {
-		echo '<li><a href="' . htmlspecialchars($link['href']) . '">' . $this->t($link['text']) . '</a></li>';
-	}
+foreach ($this->data['links_config'] as $link) {
+    echo '<li><a href="'.htmlspecialchars($link['href']).'">'.$this->t($link['text']).'</a></li>';
+}
 ?>
 </ul>
 
-
 <?php
-	if (array_key_exists('warnings', $this->data) && is_array($this->data['warnings']) && !empty($this->data['warnings'])) {
-
-		echo '<h2>' . $this->t('{core:frontpage:warnings}') . '</h2>';
+if (array_key_exists('warnings', $this->data) && is_array($this->data['warnings']) && !empty($this->data['warnings'])) {
+    echo '<h2>'.$this->t('{core:frontpage:warnings}').'</h2>';
+    foreach ($this->data['warnings'] as $warning) {
+        echo '<div class="caution">'.$warning.'</div>';
+    }
+}
 
-		foreach($this->data['warnings'] AS $warning) {
-			if (is_array($warning)) {
-				echo '<div class="caution">' . $this->t($warning[0], $warning[1]) . '</div>';
-			} else {
-				echo '<div class="caution">'.$this->t($warning).'</div>';
-			}
-		}
-	}
-?>
-<?php 
 if ($this->data['isadmin']) {
-
-	echo '<h2>'. $this->t('{core:frontpage:checkphp}') . '</h2>';
-	echo '<div class="enablebox"><table>';
-	
-	
-	$icon_enabled  = '<img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="enabled" />';
-	$icon_disabled = '<img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="disabled" />';
-	
-	
-	foreach ($this->data['funcmatrix'] AS $func) {
-		echo '<tr class="' . ($func['enabled'] ? 'enabled' : 'disabled') . '"><td>' . ($func['enabled'] ? $icon_enabled : $icon_disabled) . '</td>';
-		echo '<td>' . $this->t($this->data['requiredmap'][$func['required']]) . '</td><td>' . $func['descr'] . '</td></tr>';
-	}
-	echo('</table></div>');
+    echo '<h2>'.$this->t('{core:frontpage:checkphp}').'</h2>';
+    echo '<div class="enablebox"><table>';
+
+    $icon_enabled = '<img src="/'.$this->data['baseurlpath'].'resources/icons/silk/accept.png" alt="enabled" />';
+    $icon_disabled = '<img src="/'.$this->data['baseurlpath'].'resources/icons/silk/delete.png" alt="disabled" />';
+
+    foreach ($this->data['funcmatrix'] as $func) {
+        echo '<tr class="'.($func['enabled'] ? 'enabled' : 'disabled').'"><td>'.
+            ($func['enabled'] ? $icon_enabled : $icon_disabled).'</td>';
+        echo '<td>'.$this->t($this->data['requiredmap'][$func['required']]).'</td><td>'.$func['descr'].'</td></tr>';
+    }
+    echo '</table></div>';
 }
 
-?>
-	
-	
-
-		
-<?php $this->includeAtTemplateBase('includes/footer.php');
+$this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/frontpage_config.twig b/modules/core/templates/frontpage_config.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c0fb87b95d4002e18b6337e46aafaddd1ccc7126
--- /dev/null
+++ b/modules/core/templates/frontpage_config.twig
@@ -0,0 +1,56 @@
+{% set pagetitle = '{core:frontpage:page_title}'|trans %}
+{% set frontpage_section = 'config' %}
+{% extends "base.twig" %}
+
+{% block content %}
+    {% include "@core/_frontpage_menu.twig" %}
+
+    <div>
+        <code class="simplesaml_version">{{ directory }} ({{ version }})</code>
+    </div>
+
+    {% set icon_enabled = '<i class="fa fa-check"></i>' %}
+    {% set icon_disabled = '<i class="fa fa-ban"></i>' %}
+
+    <div class="enablebox mini">
+        <table>
+	    <tr class="{%- if enablematrix.saml20idp %}enabled{% else %}disabled{% endif -%}">
+                <td>SAML 2.0 IdP</td>
+                <td>{%- if enablematrix.saml20idp %}{{ icon_enabled|raw }}{% else %}{{ icon_disabled|raw }}{% endif -%}</td>
+            </tr>
+	    <tr class="{%- if enablematrix.shib13idp %}enabled{% else %}disabled{% endif -%}">
+                <td>Shib 1.3 IdP</td>
+                <td>{%- if enablematrix.shib13idp %}{{ icon_enabled|raw }}{% else %}{{ icon_disabled|raw }}{% endif -%}</td>
+            </tr>
+        </table>
+    </div>
+
+    <h2>{{ '{core:frontpage:configuration}'|trans }}</h2>
+    <ul>
+        {% for key, link in links_config %}
+        <li><a href="{{ link.href|escape('html') }}">{{ link.text|trans|escape('html') }}</a></li>
+        {% endfor %}
+    </ul>
+
+    {% if warnings is defined and warnings is not empty %}
+    <h2>{{ '{core:frontpage:warnings}'|trans|escape('html') }}</h2>
+    {% for key, warning in warnings %}
+    <div class="caution">{{ warning|raw }}</div>
+    {% endfor %}
+    {% endif %}
+
+    {% if isadmin %}
+    <h2>{{ '{core:frontpage:checkphp}'|trans }}</h2>
+    <div class="enablebox">
+        <table>
+        {% for key, func in funcmatrix %}
+	    <tr class="{%- if func.enabled %}enabled{% else %}disabled{% endif -%}">
+                <td>{%- if func.enabled %}{{ icon_enabled|raw }}{% else %}{{ icon_disabled|raw }}{% endif -%}</td>
+                <td>{{ requiredmap[func.required]|trans }}</td>
+                <td>{{ func.descr }}</td>
+            </tr>
+        {% endfor %}
+        </table>
+    </div>
+    {% endif %}
+{% endblock %}
diff --git a/modules/core/templates/frontpage_federation.tpl.php b/modules/core/templates/frontpage_federation.tpl.php
index f6e1596c560a6e76e12f3e109bedcdaf0e51265d..6bdce021115624cd0b38451de208c217e64dc1a3 100644
--- a/modules/core/templates/frontpage_federation.tpl.php
+++ b/modules/core/templates/frontpage_federation.tpl.php
@@ -43,7 +43,6 @@ if (is_array($this->data['metaentries']['hosted']) && count($this->data['metaent
 if (is_array($this->data['metaentries']['remote']) && count($this->data['metaentries']['remote']) > 0) {
     $now = time();
     foreach ($this->data['metaentries']['remote'] as $setkey => $set) {
-
         echo '<fieldset class="fancyfieldset"><legend>'.$this->t($this->data['mtype'][$setkey]).' (Trusted)</legend>';
         echo '<ul>';
         foreach ($set as $entry) {
@@ -52,7 +51,7 @@ if (is_array($this->data['metaentries']['remote']) && count($this->data['metaent
                 htmlspecialchars(
                     SimpleSAML\Module::getModuleURL(
                         'core/show_metadata.php',
-                        array('entityid' => $entry['entityid'], 'set' => $setkey)
+                        ['entityid' => $entry['entityid'], 'set' => $setkey]
                     )
                 ).'">');
             if (!empty($entry['name'])) {
@@ -81,26 +80,26 @@ if (is_array($this->data['metaentries']['remote']) && count($this->data['metaent
         echo '</fieldset>';
     }
 }
+
+echo '<h2>'.$this->t('{core:frontpage:tools}').'</h2>';
+echo '<ul>';
+foreach ($this->data['links_federation'] as $link) {
+    echo '<li><a href="'.htmlspecialchars($link['href']).'">'.$this->t($link['text']).'</a></li>';
+}
+echo '</ul>';
+if ($this->data['isadmin']) {
 ?>
-    <h2><?php echo $this->t('{core:frontpage:tools}'); ?></h2>
-    <ul><?php
-        foreach ($this->data['links_federation'] as $link) {
-            echo '<li><a href="'.htmlspecialchars($link['href']).'">'.$this->t($link['text']).'</a></li>';
-        }
-?>
-    </ul>
-<?php
-        if ($this->data['isadmin']) { ?>
     <fieldset class="fancyfieldset">
         <legend>Lookup metadata</legend>
         <form action="<?php echo SimpleSAML\Module::getModuleURL('core/show_metadata.php'); ?>" method="get">
             <p style="margin: 1em 2em ">Look up metadata for entity:
-                <select name="set"><?php
-            if (is_array($this->data['metaentries']['remote']) && count($this->data['metaentries']['remote']) > 0) {
-                foreach ($this->data['metaentries']['remote'] as $setkey => $set) {
-                    echo '<option value="'.htmlspecialchars($setkey).'">'.$this->t($this->data['mtype'][$setkey]).'</option>';
-                }
-            }
+                <select name="set">
+<?php
+    if (is_array($this->data['metaentries']['remote']) && count($this->data['metaentries']['remote']) > 0) {
+        foreach ($this->data['metaentries']['remote'] as $setkey => $set) {
+            echo '<option value="'.htmlspecialchars($setkey).'">'.$this->t($this->data['mtype'][$setkey]).'</option>';
+        }
+    }
 ?>
                 </select>
                 <input type="text" name="entityid" />
@@ -109,5 +108,5 @@ if (is_array($this->data['metaentries']['remote']) && count($this->data['metaent
         </form>
     </fieldset>
 <?php
-        }
+}
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/frontpage_federation.twig b/modules/core/templates/frontpage_federation.twig
new file mode 100644
index 0000000000000000000000000000000000000000..35acde2d64bf5db106cee6300d41100a4a0a8483
--- /dev/null
+++ b/modules/core/templates/frontpage_federation.twig
@@ -0,0 +1,84 @@
+{% set pagetitle = '{core:frontpage:page_title}'|trans %}
+{% set frontpage_section = 'federation' %}
+{% extends "base.twig" %}
+
+{% block content %}
+    {% include "@core/_frontpage_menu.twig" %}
+
+    {% if metaentries.hosted is iterable and metaentries.hosted is not empty %}
+    <dl>
+    {% for key, set in metaentries.hosted %}
+        {% set metadataset = attribute(set, 'metadata-set') %}
+        <dt>{{ mtype[metadataset]|trans }}</dt>
+        <dd>
+        <p>Entity ID: <code>{{ set.entityid }}</code>
+            {% if set.deprecated is defined and set.deprecated %}
+            <br /><span class="entity-deprecated">Deprecated</span>
+            {% endif %}
+            {% if set.entityid != attribute(set, 'metadata-index') %}
+            <br />Index: {{ attribute(set, 'metadata-index') }}
+            {% endif %}
+            {% if set.name_translated is defined %}
+            <br /><span class="entity-name">{{ set.name_translated }}</span>
+            {% endif %}
+            {% if set.descr_translated is defined %}
+            <br /><span class="entity-name">{{ set.descr_translated }}</span>
+            {% endif %}
+            <br />[ <a href="{{ attribute(set, 'metadata-url') }}">{{'{core:frontpage:show_metadata}'|trans }}</a> ]
+        </p>
+        </dd>
+    {% endfor %}
+    </dl>
+    {% endif %}
+
+    {% if metaentries.remote is iterable and metaentries.remote is not empty %}
+    {% for key, set in metaentries.remote %}
+    <fieldset class="fancyfieldset">
+        <legend>{{ mtype[key]|trans }} (Trusted)</legend>
+        <ul>
+        {% for entityid, entity in set %}
+            <li><a href="{{ (metadata_url ~ '?entityid=' ~ entity.entityid ~ '&set=' ~ key)|escape('html') }}">
+            {%- if entity.name_translated is defined %}
+            {{ entity.name_translated }}
+            {% elseif entity.organizationdisplayname_translated is defined %}
+            {{ entity.organizationdisplayname_translated }}
+            {% else %}{{ entity.entityid|escape('html') }}
+            {% endif -%}</a>
+
+            {%- if entity.expire is defined %}
+            {% if entity.expire > date().timestamp %}
+            <span class="entity-expired"> (expired {{ ((date().timestamp - entity.expire) / 3600) }} hours ago)</span>
+            {% else %} (expires in {{ ((entity.expire - date().timestamp) / 3600) }} hours){% endif -%}{% endif %}
+            </li>
+        {% endfor %}
+        </ul>
+    </fieldset>
+    {% endfor %}
+    {% endif %}
+
+    <h2>{{ '{core:frontpage:tools}'|trans }}</h2>
+    <ul>
+        {% for key, link in links_federation %}
+        <li><a href="{{ link.href|escape('html') }}">{{ link.text|trans|escape('html') }}</a></li>
+        {% endfor %}
+    </ul>
+
+    {% if isadmin %}
+    <fieldset class="fancyfieldset">
+        <legend>Lookup metadata</legend>
+        <form action="{{ metadata_url }}" method="get">
+            <p>Look up metadata for entity:
+                <select name="set">
+                {% if metaentries.remote is defined and metaentries.remote is not empty %}
+                {% for key, set in metaentries.remote %}
+                    <option value="{{ key|escape('html') }}">{{ mtype[key]|trans }}</option>
+                {% endfor %}
+                {% endif %}
+                </select>
+                <input type="text" name="entityid" />
+                <button class="btn" type="submit">Lookup </button>
+            </p>
+        </form>
+    </fieldset>
+    {% endif %}
+{% endblock %}
diff --git a/modules/core/templates/frontpage_welcome.tpl.php b/modules/core/templates/frontpage_welcome.tpl.php
index 33d5ff25113874dd9ded7b920b7d94a7d5c8209d..da5c2e5297df57f79fd9fac751a7f0832cb3cebc 100644
--- a/modules/core/templates/frontpage_welcome.tpl.php
+++ b/modules/core/templates/frontpage_welcome.tpl.php
@@ -1,36 +1,23 @@
-<?php 
-
+<?php
 $this->data['header'] = $this->t('{core:frontpage:page_title}');
-$this->includeAtTemplateBase('includes/header.php'); 
-
-?>
-
+$this->includeAtTemplateBase('includes/header.php');
 
-<?php
 if ($this->data['isadmin']) {
-	echo '<p class="float-r youareadmin">' . $this->t('{core:frontpage:loggedin_as_admin}') . '</p>';
+    echo '<p class="float-r youareadmin">'.$this->t('{core:frontpage:loggedin_as_admin}').'</p>';
 } else {
-	echo '<p class="float-r youareadmin"><a href="' . $this->data['loginurl'] . '">' . $this->t('{core:frontpage:login_as_admin}') . '</a></p>';
+    echo '<p class="float-r youareadmin"><a href="'.$this->data['loginurl'].'">'.
+        $this->t('{core:frontpage:login_as_admin}').'</a></p>';
 }
 ?>
 
 <p><?php echo $this->t('{core:frontpage:intro}'); ?></p>
 
-
 <ul>
 <?php
-	foreach ($this->data['links_welcome'] AS $link) {
-		echo '<li><a href="' . htmlspecialchars($link['href']) . '">' . $this->t($link['text']) . '</a></li>';
-	}
+foreach ($this->data['links_welcome'] as $link) {
+    echo '<li><a href="'. htmlspecialchars($link['href']).'">'.$this->t($link['text']).'</a></li>';
+}
 ?>
 </ul>
-	
-	
-	
-	<h2><?php echo $this->t('{core:frontpage:about_header}'); ?></h2>
-		<p><?php echo $this->t('{core:frontpage:about_text}'); ?></p>
-
-
 
-		
 <?php $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/frontpage_welcome.twig b/modules/core/templates/frontpage_welcome.twig
new file mode 100644
index 0000000000000000000000000000000000000000..653c549352d21e8cdcd9ad4cc05bca15cfc34c2a
--- /dev/null
+++ b/modules/core/templates/frontpage_welcome.twig
@@ -0,0 +1,15 @@
+{% set pagetitle = '{core:frontpage:page_title}'|trans %}
+{% set frontpage_section = 'welcome' %}
+{% extends "base.twig" %}
+
+{% block content %}
+    {% include "@core/_frontpage_menu.twig" %}
+
+    <p>{{ '{core:frontpage:intro}'|trans|raw }}</p>
+    <ul>
+        {% for key, link in links_welcome %}
+        <li><a href="{{ link.href|escape('html') }}">{{ link.text|trans|escape('html') }}</a></li>
+        {% endfor %}
+    </ul>
+
+{% endblock %}
diff --git a/modules/core/templates/login.twig b/modules/core/templates/login.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e1b342cc0a9ba9e71324930c7ff732f2e69f860e
--- /dev/null
+++ b/modules/core/templates/login.twig
@@ -0,0 +1,20 @@
+{% set pagetitle = 'Authenticate'|trans %}
+{% extends "@core/base.twig" %}
+
+{% block content %}
+    <h1>{{ pagetitle|trans }}</h1>
+    <p>Please choose one of the following authentication methods: </p>
+
+{% if sources is empty -%}
+    <p>Please check your SimpleSAML configuration.<br>
+        Follow the link and log in with administrator credentials. <a href="{{ loginurl }}">Admin login.</a></p>
+{% else %}
+    <div class="pure-menu custom-restricted-width">
+        <ul class="pure-menu-list auth_methods">
+            {% for id, config in sources -%}
+                <li class="pure-menu-item"><a href="?as={{ id|url_encode }}" class="pure-menu-link">{{ config.name|translateFromArray|default(id) }}</a></li>
+            {% endfor -%}
+        </ul>
+    </div>
+{% endif %}
+{% endblock %}
diff --git a/modules/core/templates/loginuserpass.php b/modules/core/templates/loginuserpass.php
index d957fc43a2b0745ad86aaf14a8a2d3f57b329129..9e0fc646a1829f9fc93ac02f9cb43ea78200f744 100644
--- a/modules/core/templates/loginuserpass.php
+++ b/modules/core/templates/loginuserpass.php
@@ -8,26 +8,37 @@ if (strlen($this->data['username']) > 0) {
 }
 $this->includeAtTemplateBase('includes/header.php');
 
-?>
-
-<?php
 if ($this->data['errorcode'] !== null) {
-    ?>
+?>
     <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
         <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png"
              class="float-l erroricon" style="margin: 15px" alt=""/>
 
         <h2><?php echo $this->t('{login:error_header}'); ?></h2>
 
-        <p><strong><?php
-            echo htmlspecialchars($this->t($this->data['errorcodes']['title'][$this->data['errorcode']], $this->data['errorparams'])); ?></strong></p>
-
-        <p><?php
-            echo htmlspecialchars($this->t($this->data['errorcodes']['descr'][$this->data['errorcode']], $this->data['errorparams'])); ?></p>
+        <p><strong>
+        <?php
+            echo htmlspecialchars(
+                $this->t(
+                    $this->data['errorcodes']['title'][$this->data['errorcode']],
+                    $this->data['errorparams']
+                )
+            );
+        ?>
+        </strong></p>
+        <p>
+        <?php
+            echo htmlspecialchars(
+                $this->t(
+                    $this->data['errorcodes']['descr'][$this->data['errorcode']],
+                    $this->data['errorparams']
+                )
+            );
+        ?>
+        </p>
     </div>
 <?php
 }
-
 ?>
     <h2 style="break: both"><?php echo $this->t('{login:user_pass_header}'); ?></h2>
 
@@ -38,15 +49,14 @@ if ($this->data['errorcode'] !== null) {
             <tr>
                 <td rowspan="2" class="loginicon">
                     <img alt=""
-                        src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-authentication.48x48.png" />
+                        src="/<?php echo $this->data['baseurlpath']; ?>
+                        resources/icons/experience/gtk-dialog-authentication.48x48.png" />
                 </td>
                 <td><label for="username"><?php echo $this->t('{login:username}'); ?></label></td>
                 <td>
                     <input id="username" <?php echo ($this->data['forceUsername']) ? 'disabled="disabled"' : ''; ?>
-                           type="text" name="username"
-<?php if (!$this->data['forceUsername']) {
-    echo 'tabindex="1"';
-} ?> value="<?php echo htmlspecialchars($this->data['username']); ?>"/>
+                        type="text" name="username"<?php echo $this->data['forceUsername'] ? '' : 'tabindex="1"'; ?>
+                        value="<?php echo htmlspecialchars($this->data['username']); ?>" />
                 </td>
             <?php
             if ($this->data['rememberUsernameEnabled'] && !$this->data['forceUsername']) {
@@ -55,7 +65,7 @@ if ($this->data['errorcode'] !== null) {
                 <td id="regular_remember_username">
                     <input type="checkbox" id="remember_username" tabindex="4"
                            <?php echo ($this->data['rememberUsernameChecked']) ? 'checked="checked"' : ''; ?>
-                           name="remember_username" value="Yes"/>
+                           name="remember_username" value="Yes" />
                     <small><?php echo $this->t('{login:remember_username}'); ?></small>
                 </td>
             <?php
@@ -65,24 +75,22 @@ if ($this->data['errorcode'] !== null) {
             <?php
             if ($this->data['rememberUsernameEnabled'] && !$this->data['forceUsername']) {
                 // display the "remember my username" checkbox
-                ?>
+            ?>
             <tr id="mobile_remember_username">
                 <td>&nbsp;</td>
                 <td>
                     <input type="checkbox" id="remember_username" tabindex="4"
                         <?php echo ($this->data['rememberUsernameChecked']) ? 'checked="checked"' : ''; ?>
-                           name="remember_username" value="Yes"/>
+                        name="remember_username" value="Yes" />
                     <small><?php echo $this->t('{login:remember_username}'); ?></small>
                 </td>
             </tr>
-                <?php
+            <?php
             }
             ?>
             <tr>
                 <td><label for="password"><?php echo $this->t('{login:password}'); ?></label></td>
-                <td>
-                    <input id="password" type="password" tabindex="2" name="password"/>
-                </td>
+                <td><input id="password" type="password" tabindex="2" name="password" /></td>
             <?php
             if ($this->data['rememberMeEnabled']) {
                 // display the remember me checkbox (keep me logged in)
@@ -90,7 +98,7 @@ if ($this->data['errorcode'] !== null) {
                 <td id="regular_remember_me">
                     <input type="checkbox" id="remember_me" tabindex="5"
                         <?php echo ($this->data['rememberMeChecked']) ? 'checked="checked"' : ''; ?>
-                           name="remember_me" value="Yes"/>
+                        name="remember_me" value="Yes" />
                     <small><?php echo $this->t('{login:remember_me}'); ?></small>
                 </td>
             <?php
@@ -106,7 +114,7 @@ if ($this->data['errorcode'] !== null) {
                 <td id="mobile_remember_me">
                     <input type="checkbox" id="remember_me" tabindex="5"
                         <?php echo ($this->data['rememberMeChecked']) ? 'checked="checked"' : ''; ?>
-                           name="remember_me" value="Yes"/>
+                        name="remember_me" value="Yes" />
                     <small><?php echo $this->t('{login:remember_me}'); ?></small>
                 </td>
             </tr>
@@ -115,51 +123,62 @@ if ($this->data['errorcode'] !== null) {
             ?>
             <?php
             if (array_key_exists('organizations', $this->data)) {
-                ?>
+            ?>
                 <tr>
                     <td></td>
                     <td><label for="organization"><?php echo $this->t('{login:organization}'); ?></label></td>
                     <td><select name="organization" tabindex="3">
-                            <?php
-                            if (array_key_exists('selectedOrg', $this->data)) {
-                                $selectedOrg = $this->data['selectedOrg'];
-                            } else {
-                                $selectedOrg = null;
-                            }
-
-                            foreach ($this->data['organizations'] as $orgId => $orgDesc) {
-                                if (is_array($orgDesc)) {
-                                    $orgDesc = $this->t($orgDesc);
-                                }
+                        <?php
+                        if (array_key_exists('selectedOrg', $this->data)) {
+                            $selectedOrg = $this->data['selectedOrg'];
+                        } else {
+                            $selectedOrg = null;
+                        }
 
-                                if ($orgId === $selectedOrg) {
-                                    $selected = 'selected="selected" ';
-                                } else {
-                                    $selected = '';
-                                }
+                        foreach ($this->data['organizations'] as $orgId => $orgDesc) {
+                            if (is_array($orgDesc)) {
+                                $orgDesc = $this->t($orgDesc);
+                            }
 
-                                echo '<option '.$selected.'value="'.htmlspecialchars($orgId).'">'.htmlspecialchars($orgDesc).'</option>';
+                            if ($orgId === $selectedOrg) {
+                                $selected = 'selected="selected" ';
+                            } else {
+                                $selected = '';
                             }
-                            ?>
+
+                            echo '<option '.$selected.'value="'.htmlspecialchars($orgId).'">'.
+                                htmlspecialchars($orgDesc).'</option>';
+                        }
+                        ?>
                         </select></td>
+                    <td style="padding: .4em;">
+                        <?php
+                            if ($this->data['rememberOrganizationEnabled']) {
+                                echo str_repeat("\t", 4);
+                                echo '<input type="checkbox" id="remember_organization" tabindex="5"'.
+                                    ' name="remember_organization" value="Yes" '.
+                                    ($this->data['rememberOrganizationChecked'] ? 'checked="Yes" /> ' : '/> ').
+                                     $this->t('{login:remember_organization}');
+                            }
+                        ?>
+                    </td>
                 </tr>
-                <?php
+            <?php
             }
             ?>
             <tr id="submit">
                 <td class="loginicon"></td><td></td>
                 <td>
-                    <button class="btn"
-                            onclick="this.value='<?php echo $this->t('{login:processing}'); ?>';
-                                this.disabled=true; this.form.submit(); return true;" tabindex="6">
+                    <button id="submit_button" class="btn" tabindex="6">
                         <?php echo $this->t('{login:login_button}'); ?>
                     </button>
                 </td>
             </tr>
         </table>
+        <input type="hidden" id="processing_trans" value="<?php echo $this->t('{login:processing}'); ?>" />
         <?php
         foreach ($this->data['stateparams'] as $name => $value) {
-            echo('<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />');
+            echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
         }
         ?>
     </form>
@@ -171,7 +190,7 @@ if (!empty($this->data['links'])) {
     }
     echo '</ul>';
 }
-echo('<h2 class="logintext">'.$this->t('{login:help_header}').'</h2>');
-echo('<p class="logintext">'.$this->t('{login:help_text}').'</p>');
+echo '<h2 class="logintext">'.$this->t('{login:help_header}').'</h2>';
+echo '<p class="logintext">'.$this->t('{login:help_text}').'</p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/loginuserpass.twig b/modules/core/templates/loginuserpass.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f474a339cfe0b82ec00bdbf8eeafbd7a18de1e0b
--- /dev/null
+++ b/modules/core/templates/loginuserpass.twig
@@ -0,0 +1,129 @@
+{% set pagetitle = 'Enter your username and password'|trans %}
+
+{% extends "@core/base.twig" %}
+
+{% block postload %}
+    <script src="/{{baseurlpath}}module.php/core/assets/js/loginuserpass.js"></script>
+{% endblock %}
+
+{% block content %}
+    {% if errorcode -%}
+    <div class="pure-g">
+        <div class="pure-u-1">
+            <div class="message-box error">
+
+                {% set errtitles = errorcodes['title'] %}
+                {% set errtitle = errtitles[errorcode] %}
+
+                <h3>{{ errtitle|trans(errorparams) }}</h3>
+
+                {% set errdescs = errorcodes['descr'] %}
+                {% set errdesc = errdescs[errorcode] %}
+
+                <p>{{ errdesc|trans(errorparams) }}</p>
+
+            </div>
+        </div>
+    </div>
+    {%- endif %}
+
+    <h1>{{ 'Enter your username and password'|trans }}</h1>
+
+    <p>{{ 'A service has requested you to authenticate yourself. Please enter your username and password in the form below.'|trans }}</p>
+    <br>
+    <div class="center">
+        <form class="pure-form pure-form-aligned center-form" action="?" method="post" name="f">
+            <div class="form-align">
+
+                <div class="show-for-medium v-center-right">
+                    <img class="pure-img" src="/{{ baseurlpath }}resources/icons/experience/gtk-dialog-authentication.48x48.png"
+                         alt=""/>
+                </div>
+
+                <div class="pure-control-group">
+                    <label for="username">{{ 'Username'|trans }}</label>
+                    <input id="username" {{ forceUsername ? 'disabled="disabled"' }} placeholder="{{ username }}" type="text" name="username" class="edge"
+            {%- if not forceUsername %} tabindex="1" value="{{ username }}" {% endif %}
+            {%- if not forceUsername and not username %} autofocus {% endif %} />
+                {% if rememberUsernameEnabled and not forceUsername -%}
+                </div>
+                <div class="pure-controls pure-form-message">
+                    <label for="remember_username" class="pure-checkbox">
+                        <input id="remember_username" type="checkbox" tabindex="4"
+                                {{ rememberUsernameChecked ? 'checked="checked"' }} name="remember_username" value="Yes"/>
+                        <small>{{ 'Remember my username'|trans }}</small>
+                    </label>
+                {%- endif %}
+                </div>
+
+                <div class="pure-control-group">
+                    <label for="password">{{ 'Password'|trans}}</label>
+                    <input id="password" type="password" tabindex="2" name="password" class="edge"
+                    {%- if forceUsername or username %} autofocus {% endif %} />
+
+                {% if rememberMeEnabled -%}
+                </div>
+                <div class="pure-controls pure-form-message">
+                    <label for="remember_me" class="pure-checkbox">
+                    <input id="remember_me" type="checkbox" tabindex="5"
+                            {{ rememberMeChecked ? 'checked="checked"' }} name="remember_me" value="Yes"/>
+                        <small>{{ 'Remember me'|trans }}</small>
+                    </label>
+                {%- endif %}
+                </div>
+                {% if organizations is defined -%}
+                <div class="pure-control-group">
+                    <label for="organization">{{ 'Organization'|trans }}</label>
+                    <div class="pure-select right pure-input-1-2 pure-input-sm-1-1">
+                        <select name="organization" class="selectize" id="organization" tabindex="3">
+                            {{ selectedOrg ?: null }}
+                            {%- for id, orgDesc in organizations -%}
+                                {% if id == selectedOrg -%}
+                                    {%- set selected = 'selected="selected"' %}
+                                {%- else -%}
+                                    {% set selected = '' -%}
+                                {% endif -%}
+                                {% if orgDesc -%}
+                                    <option value="{{ id }}" {{ selected }}>{{ orgDesc|trans }}</option>
+                                {% endif -%}
+                            {% endfor %}
+                        </select>
+                    </div>
+                    {% if rememberOrganizationEnabled is defined -%}
+                    <div class="pure-controls pure-form-message">
+                        <label for="remember_organization" class="pure-checkbox">
+ 	                    <input type="checkbox" id="remember_organization" tabindex="5" name="remember_organization" value="Yes"
+                                {{ rememberOrganizationChecked ? 'checked="checked"' }} />
+                            <small>{{ 'Remember my organization'|trans }}</small>
+                        </label>
+                    </div>
+                    {%- endif %}
+                </div> <!--pure-control-group-->
+            {%- endif %}
+
+            </div> <!-- form-align-->
+            <br><br>
+            <button class="pure-button pure-button-red pure-input-1-2 pure-input-sm-1-1 right" id="submit_button" type="submit" tabindex="6">
+                {{ 'Login'|trans }}
+            </button>
+            <input type='hidden' id="processing_trans" value="{{ 'Processing...'|trans }}" />
+            {% for name, value in stateparams -%}
+                <input type="hidden" name="{{ name }}" value="{{ value }}" />
+            {%- endfor %}
+        </form>
+    </div><!--center-->
+    {% if links -%}
+    <ul>
+        {% for link in links -%}
+        <li><a href="{{ link.href }}">{{ link['text']|trans }}</a></li>
+        {% endfor %}
+    </ul>
+    {%- endif %}
+
+    <br><br>
+    <div class="pure-form-message">
+        <strong>{{ 'Help! I don\'t remember my password.'|trans }}</strong>
+        <p>{{ 'Without your username and password you cannot authenticate yourself for access to the service. There may be someone that can help you. Consult the help desk at your organization!'|trans }}</p>
+    </div>
+
+{% endblock %}
diff --git a/modules/core/templates/logout-iframe-wrapper.php b/modules/core/templates/logout-iframe-wrapper.php
index 5f56009fe1041f47de50f7ee2c2183ad19b8c35f..3392e4cb4f0dd202417ba8def2047a38bba938a2 100644
--- a/modules/core/templates/logout-iframe-wrapper.php
+++ b/modules/core/templates/logout-iframe-wrapper.php
@@ -10,8 +10,8 @@ $iframeHeight = 25 + count($SPs) * 4;
 
 $this->data['header'] = $this->t('{logout:progress}');
 $this->includeAtTemplateBase('includes/header.php');
-echo '<iframe style="width:100%; height:'.$iframeHeight.'em; border:0;" src="'.htmlspecialchars($iframeURL).
-     '"></iframe>';
+echo '<iframe style="width:100%; height:'.$iframeHeight.'em; border:0;" src="'.
+    htmlspecialchars($iframeURL).'"></iframe>';
 
 foreach ($SPs as $assocId => $sp) {
     $spId = sha1($assocId);
@@ -23,7 +23,7 @@ foreach ($SPs as $assocId => $sp) {
 
     $url = $sp["core:Logout-IFrame:URL"];
 
-    echo('<iframe style="width:0; height:0; border:0;" src="'.htmlspecialchars($url).'"></iframe>');
+    echo '<iframe style="width:0; height:0; border:0;" src="'.htmlspecialchars($url).'"></iframe>';
 }
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/logout-iframe-wrapper.twig b/modules/core/templates/logout-iframe-wrapper.twig
new file mode 100644
index 0000000000000000000000000000000000000000..7c9e415d072d9d25553bdb7e8eee4b05c76a4810
--- /dev/null
+++ b/modules/core/templates/logout-iframe-wrapper.twig
@@ -0,0 +1,16 @@
+
+{% set pagetitle = '{logout:progress}'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    {# pretty arbitrary height, but should have enough safety margins for most cases #}
+    {% set iframeHeight = (25 + (SPs|length * 4)) %}
+
+    <iframe style="width:100%; height: {{ iframeHeight }}em; border:0;" src="logout-iframe.php?type=embed&id={{ auth_state|escape('url') }}"></iframe>
+
+    {% for assocId, sp in SPs %}
+    {% if attribute(sp, 'core:Logout-IFrame:State') == 'inprogress' %}
+    <iframe style="width:0; height:0; border:0;" src="{{ attribute(sp, 'core:Logout-IFrame:URL')|escape('html') }}</iframe>
+    {% endif %}
+    {% endfor %}
+{% endblock %}
diff --git a/modules/core/templates/logout-iframe.php b/modules/core/templates/logout-iframe.php
index 6ada50bdab75ec66dc2b846030e5d7897b487ec2..54ca2c1829d135cef464a64a055d7aa965443f67 100644
--- a/modules/core/templates/logout-iframe.php
+++ b/modules/core/templates/logout-iframe.php
@@ -5,24 +5,24 @@ $type = $this->data['type'];
 $from = $this->data['from'];
 $SPs = $this->data['SPs'];
 
-$stateImage = array(
+$stateImage = [
     'unsupported' => '/'.$this->data['baseurlpath'].'resources/icons/silk/delete.png',
     'completed'   => '/'.$this->data['baseurlpath'].'resources/icons/silk/accept.png',
     'onhold'      => '/'.$this->data['baseurlpath'].'resources/icons/bullet16_grey.png',
     'inprogress'  => '/'.$this->data['baseurlpath'].'resources/progress.gif',
     'failed'      => '/'.$this->data['baseurlpath'].'resources/icons/silk/exclamation.png',
-);
+];
 
-$stateText = array(
+$stateText = [
     'unsupported' => '',
     'completed'   => $this->t('{logout:completed}'),
     'onhold'      => '',
     'inprogress'  => $this->t('{logout:progress}'),
     'failed'      => $this->t('{logout:failed}'),
-);
+];
 
-$spStatus = array();
-$spTimeout = array();
+$spStatus = [];
+$spTimeout = [];
 $nFailed = 0;
 $nProgress = 0;
 foreach ($SPs as $assocId => $sp) {
@@ -71,14 +71,14 @@ if ($type === 'embed') {
     $this->includeAtTemplateBase('includes/header.php');
 }
 ?>
- <div id="wrap">
-  <div id="content">
+<div id="wrap">
+    <div id="content">
 <?php
 if ($from !== null) {
     echo '<div><img style="float: left; margin-right: 12px" src="/'.$this->data['baseurlpath'].
-         'resources/icons/checkmark.48x48.png" alt="Successful logout" />';
+        'resources/icons/checkmark.48x48.png" alt="Successful logout" />';
     echo '<p style="padding-top: 16px; ">'.
-        $this->t('{logout:loggedoutfrom}', array('%SP%' => '<strong>'.htmlspecialchars($from).'</strong>')).'</p>';
+        $this->t('{logout:loggedoutfrom}', ['%SP%' => '<strong>'.htmlspecialchars($from).'</strong>']).'</p>';
     echo '<p style="height: 0px; clear: left;"></p></div>';
 }
 
@@ -90,9 +90,9 @@ if ($type === 'init') {
 } else {
     echo $this->t('{logout:logging_out_from}');
 }
-echo('</p>');
 ?>
-  <table id="slostatustable">
+    </p>
+    <table id="slostatustable">
 <?php
 foreach ($SPs as $assocId => $sp) {
     if (isset($sp['core:Logout-IFrame:Name'])) {
@@ -110,37 +110,39 @@ foreach ($SPs as $assocId => $sp) {
     echo '<td style="width: 3em;"></td>';
     echo '<td>';
     echo '<img class="logoutstatusimage" id="statusimage-'.$spId.'"  src="'.htmlspecialchars($stateImage[$spState]).
-         '" alt="'.htmlspecialchars($stateText[$spState]).'"/>';
+        '" alt="'.htmlspecialchars($stateText[$spState]).'"/>';
     echo '</td>';
     echo '<td>'.htmlspecialchars($spName).'</td>';
     echo '</tr>';
 }
 
 if (isset($from)) {
-    $logoutCancelText = $this->t('{logout:logout_only}', array('%SP%' => htmlspecialchars($from)));
+    $logoutCancelText = $this->t('{logout:logout_only}', ['%SP%' => htmlspecialchars($from)]);
 } else {
     $logoutCancelText = $this->t('{logout:no}');
 }
 
 ?>
-  </table>
- </div>
+    </table>
+</div>
 
 <?php
 if ($type === 'init') {
 ?>
- <div id="confirmation" style="margin-top: 1em">
-  <p><?php echo $this->t('{logout:logout_all_question}'); ?> <br/></p>
-  <form id="startform" method="get" style="display:inline;" action="logout-iframe.php">
-   <input type="hidden" name="id" value="<?php echo $id; ?>"/>
-   <input type="hidden" id="logout-type-selector" name="type" value="nojs"/>
-   <button type="submit" id="logout-all" name="ok" class="btn"><?php echo $this->t('{logout:logout_all}'); ?></button>
-  </form>
-  <form method="get" style="display:inline;" action="logout-iframe-done.php">
-   <input type="hidden" name="id" value="<?php echo $id; ?>"/>
-   <button type="submit" name="cancel" class="btn"><?php echo $logoutCancelText; ?></button>
-  </form>
- </div>
+<div id="confirmation" style="margin-top: 1em">
+    <p><?php echo $this->t('{logout:logout_all_question}'); ?> <br/></p>
+    <form id="startform" method="get" style="display:inline;" action="logout-iframe.php">
+        <input type="hidden" name="id" value="<?php echo $id; ?>"/>
+        <input type="hidden" id="logout-type-selector" name="type" value="nojs"/>
+        <button type="submit" id="logout-all" name="ok" class="btn">
+        <?php echo $this->t('{logout:logout_all}'); ?>
+        </button>
+    </form>
+    <form method="get" style="display:inline;" action="logout-iframe-done.php">
+        <input type="hidden" name="id" value="<?php echo $id; ?>"/>
+        <button type="submit" name="cancel" class="btn"><?php echo $logoutCancelText; ?></button>
+    </form>
+</div>
 <?php
 } else {
     if ($nFailed > 0) {
@@ -149,9 +151,10 @@ if ($type === 'init') {
         $displayStyle = 'display: none;';
     }
     echo '<div id="logout-failed-message" style="margin-top: 1em; border: 1px solid #ccc; padding: 1em; '.
-         'background: #eaeaea;'.$displayStyle.'">';
-    echo '<img src="/'.$this->data['baseurlpath'].'resources/icons/experience/gtk-dialog-warning.48x48.png" alt="" '.
-         'style="float: left; margin-right: 5px;" />';
+        'background: #eaeaea;'.$displayStyle.'">';
+    echo '<img src="/'.$this->data['baseurlpath'].
+        'resources/icons/experience/gtk-dialog-warning.48x48.png" alt="" '.
+        'style="float: left; margin-right: 5px;" />';
     echo '<p>'.$this->t('{logout:failedsps}').'</p>';
     echo '<form method="post" action="logout-iframe-done.php" id="failed-form" target="_top">';
     echo '<input type="hidden" name="id" value="'.$id.'" />';
@@ -166,11 +169,11 @@ if ($type === 'init') {
     }
     echo '<p>'.$this->t('{logout:success}').'</p>';
 ?>
- <form method="post" action="logout-iframe-done.php" id="done-form" target="_top">
-  <input type="hidden" name="id" value="<?php echo $id; ?>"/>
-  <button type="submit" name="continue" class="btn"><?php echo $this->t('{logout:return}'); ?></button>
- </form>
- </div>
+    <form method="post" action="logout-iframe-done.php" id="done-form" target="_top">
+        <input type="hidden" name="id" value="<?php echo $id; ?>"/>
+        <button type="submit" name="continue" class="btn"><?php echo $this->t('{logout:return}'); ?></button>
+    </form>
+</div>
 <?php
     if ($type === 'js') {
         foreach ($SPs as $assocId => $sp) {
@@ -180,13 +183,13 @@ if ($type === 'init') {
             }
             assert(isset($sp['core:Logout-IFrame:URL']));
             echo '<iframe style="width:0; height:0; border:0;" src="'.
-                 htmlspecialchars($sp['core:Logout-IFrame:URL']).'"></iframe>';
+                htmlspecialchars($sp['core:Logout-IFrame:URL']).'"></iframe>';
         }
     }
 }
 ?>
-  </div><!-- #content -->
- </div><!-- #wrap -->
+        </div><!-- #content -->
+    </div><!-- #wrap -->
 <?php
 if ($type === 'embed') {
     $this->includeAtTemplateBase('includes/footer-embed.php');
diff --git a/modules/core/templates/no_cookie.twig b/modules/core/templates/no_cookie.twig
new file mode 100644
index 0000000000000000000000000000000000000000..7205318e2a3a3355de51097c2012bd4e07ea9fda
--- /dev/null
+++ b/modules/core/templates/no_cookie.twig
@@ -0,0 +1,13 @@
+
+{% set pagetitle = '{core:no_cookie:header}'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ header }}</h2>
+    <p>{{ description }}</p>
+    {% if retryURL is not null %}
+    <ul>
+        <li><a href="{{ retryURL|escape('html') }}" id="retry">{{ retry }}</a></li>
+    </ul>
+    {% endif %}
+{% endblock %}
diff --git a/modules/core/templates/no_metadata.tpl.php b/modules/core/templates/no_metadata.tpl.php
index d3b638b22542158ff7c6042c6433947291cb612c..a00f3ce911bd2bf97f7ab11dc6200e4a109dd015 100644
--- a/modules/core/templates/no_metadata.tpl.php
+++ b/modules/core/templates/no_metadata.tpl.php
@@ -1,9 +1,8 @@
 <?php
 
-echo('<p>' . $this->t('{core:no_metadata:config_problem}') . '</p>');
-
-echo('<ul>');
-echo('<li>' . $this->t('{core:no_metadata:suggestion_user_link}') . '</li>');
-echo('<li>' . $this->t('{core:no_metadata:suggestion_developer}') . '</li>');
-echo('</ul>');
+echo '<p>'.$this->t('{core:no_metadata:config_problem}').'</p>';
 
+echo '<ul>';
+echo '<li>'.$this->t('{core:no_metadata:suggestion_user_link}').'</li>';
+echo '<li>'.$this->t('{core:no_metadata:suggestion_developer}').'</li>';
+echo '</ul>';
diff --git a/modules/core/templates/no_metadata.twig b/modules/core/templates/no_metadata.twig
new file mode 100644
index 0000000000000000000000000000000000000000..0f534fcdab94a9dbb9982ac1bfae1304c1c8e05c
--- /dev/null
+++ b/modules/core/templates/no_metadata.twig
@@ -0,0 +1,7 @@
+<p>{{ '{core:no_metadata:config_problem}'|trans }}</p>
+
+<ul>
+    <li>{{ '{core:no_metadata:suggestion_user_link}'|trans }}</li>
+    <li>{{ '{core:no_metadata:suggestion_developer}'|trans }}</li>
+</ul>
+
diff --git a/modules/core/templates/no_state.tpl.php b/modules/core/templates/no_state.tpl.php
index f86e346e0e8fdebe1360e384c0f941a7dee8a639..01ea6db789e94678cd97d8c384909037c5afdf71 100644
--- a/modules/core/templates/no_state.tpl.php
+++ b/modules/core/templates/no_state.tpl.php
@@ -1,15 +1,14 @@
 <?php
 
-echo('<h3>' . $this->t('{core:no_state:suggestions}') . '</h3>');
-echo('<ul>');
-echo('<li>' . $this->t('{core:no_state:suggestion_goback}') . '</li>');
-echo('<li>' . $this->t('{core:no_state:suggestion_closebrowser}') . '</li>');
-echo('</ul>');
-
-echo('<h3>' . $this->t('{core:no_state:causes}') . '</h3>');
-echo('<ul>');
-echo('<li>' . $this->t('{core:no_state:cause_backforward}') . '</li>');
-echo('<li>' . $this->t('{core:no_state:cause_openbrowser}') . '</li>');
-echo('<li>' . $this->t('{core:no_state:cause_nocookie}') . '</li>');
-echo('</ul>');
+echo '<h3>'.$this->t('{core:no_state:suggestions}').'</h3>';
+echo '<ul>';
+echo '<li>'.$this->t('{core:no_state:suggestion_goback}').'</li>';
+echo '<li>'.$this->t('{core:no_state:suggestion_closebrowser}').'</li>';
+echo '</ul>';
 
+echo '<h3>'.$this->t('{core:no_state:causes}').'</h3>';
+echo '<ul>';
+echo '<li>'.$this->t('{core:no_state:cause_backforward}').'</li>';
+echo '<li>'.$this->t('{core:no_state:cause_openbrowser}').'</li>';
+echo '<li>'.$this->t('{core:no_state:cause_nocookie}').'</li>';
+echo '</ul>';
diff --git a/modules/core/templates/no_state.twig b/modules/core/templates/no_state.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b811c102506c386e15a3606a3e796dc56bea93f9
--- /dev/null
+++ b/modules/core/templates/no_state.twig
@@ -0,0 +1,12 @@
+<h3>{{ '{core:no_state:suggestions}'|trans }}</h3>
+<ul>
+    <li>{{ '{core:no_state:suggestion_goback}'|trans }}</li>
+    <li>{{ '{core:no_state:suggestion_closebrowser}'|trans }}</li>
+</ul>
+
+<h3>{{ '{core:no_state:causes}'|trans }}</h3>
+<ul>
+    <li>{{ '{core:no_state:cause_backforward}'|trans }}</li>
+    <li>{{ '{core:no_state:cause_openbrowser}'|trans }}</li>
+    <li>{{ '{core:no_state:cause_nocookie}'|trans }}</li>
+</ul>
diff --git a/modules/core/templates/short_sso_interval.php b/modules/core/templates/short_sso_interval.php
index a50b3b82b7b6ab9047b6e348479d5a122ece51f0..2e305c2b9ddf1ac3a6a190c36a7fc626e3665040 100644
--- a/modules/core/templates/short_sso_interval.php
+++ b/modules/core/templates/short_sso_interval.php
@@ -14,27 +14,28 @@ $this->data['header'] = $this->t('{core:short_sso_interval:warning_header}');
 $this->data['autofocus'] = 'contbutton';
 
 $this->includeAtTemplateBase('includes/header.php');
+$target = htmlspecialchars($this->data['target']);
+$contButton = htmlspecialchars($this->t('{core:short_sso_interval:retry}'));
 ?>
 <h1><?php echo $this->data['header']; ?></h1>
-<form style="display: inline; margin: 0px; padding: 0px" action="<?php echo htmlspecialchars($this->data['target']); ?>">
+<form style="display: inline; margin: 0px; padding: 0px" action="<?php echo $target; ?>">
 
-	<?php
-		// Embed hidden fields...
-		foreach ($this->data['params'] as $name => $value) {
-			echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
-		}
-	?>
-	<p><?php echo $this->t('{core:short_sso_interval:warning}'); ?></p>
+<?php
+// Embed hidden fields...
+foreach ($this->data['params'] as $name => $value) {
+    echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
+}
+?>
+    <p><?php echo $this->t('{core:short_sso_interval:warning}'); ?></p>
     <div class="trackidtext"><p>
         <?php echo $this->t('{errors:report_trackid}'); ?>
         <span class="trackid"><?php echo $this->data['trackId']; ?></span>
         </p>
     </div>
 
-	<input type="submit" name="continue" id="contbutton" value="<?php echo htmlspecialchars($this->t('{core:short_sso_interval:retry}')) ?>" />
+    <input type="submit" name="continue" id="contbutton" value="<?php echo $contButton; ?>" />
 
 </form>
 
-
 <?php
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/core/templates/short_sso_interval.twig b/modules/core/templates/short_sso_interval.twig
new file mode 100644
index 0000000000000000000000000000000000000000..542e174c0a9315e54c873bafe4895e17dd5473f6
--- /dev/null
+++ b/modules/core/templates/short_sso_interval.twig
@@ -0,0 +1,16 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>{{ header }}</h1>
+    <form style="display: inline; margin: 0px; padding: 0px" action="{{ target|escape('html') }}">
+        {% for name, value in params %}
+            <input type="hidden" name="{{ name|escape('html') }}" value="{{ value|escape('html') }}">
+        {% endfor %}
+        <p>{{ '{core:short_sso_interval:warning}'|trans }}</p>
+        <div class="trackidtext">
+            <p>{{ '{errors:report_trackid}'|trans }}<span class="trackid">{{ trackId }}</span></p>
+        </div>
+        <input type="submit" name="continue" id="contbutton" value="'{core:short_sso_interval:retry}'|trans|escape('html') }}" autofocus>
+    </form>
+{% endblock %}
diff --git a/modules/core/templates/show_metadata.tpl.php b/modules/core/templates/show_metadata.tpl.php
index 9c5977e58480ddd9274b4d6c9914b47917d577ca..f217540c77f469542e558dd0798b5ffe128b2aa3 100644
--- a/modules/core/templates/show_metadata.tpl.php
+++ b/modules/core/templates/show_metadata.tpl.php
@@ -13,7 +13,7 @@ $metadata['<?php echo $this->data['m']['metadata-index']; unset($this->data['m']
     </pre>
 </div>
 <script type="text/javascript">
-    var clipboard = new Clipboard('#btncp');
+    var clipboard = new ClipboardJS('#btncp');
 </script>
 <br/>
 <p><a href="<?php echo $this->data['backlink']; ?>"><span class="btn">Back</span></a></p>
diff --git a/modules/core/templates/show_metadata.twig b/modules/core/templates/show_metadata.twig
new file mode 100644
index 0000000000000000000000000000000000000000..9ff0f351693792123ac7b2597252bdfcbabc39a4
--- /dev/null
+++ b/modules/core/templates/show_metadata.twig
@@ -0,0 +1,18 @@
+{% set pagetile = 'SimpleSAMLphp Show Metadata'|trans %}
+{% extends 'base.twig' %}
+{% block content %}
+    <div class="code-box">
+        <div class="code-box-title">
+            <h3>{{ 'Metadata'|trans }}</h3>
+            <button data-clipboard-target="#metadata" id="btn{{ loop.index }}" class="pure-button right clipboard-btn">
+                <span class="fa fa-copy"></span>
+            </button>
+        </div>
+        <div class="code-box-content">
+            <pre id="metadata">$metadata[{{ entityid }}] => {{ metadata|escape }}</pre>
+        </div>
+    </div>
+    <div class="center">
+        <a href="{{ backlink }}" class="pure-button pure-button-red">{{ 'Back'|trans }}</a>
+    </div>
+{% endblock content %}
diff --git a/modules/core/www/as_login.php b/modules/core/www/as_login.php
index e43a77898b7d7faa6d17279003fddad88aee2279..d73fa8ca0badc83638f3c4e887ff669536bd9ff0 100644
--- a/modules/core/www/as_login.php
+++ b/modules/core/www/as_login.php
@@ -7,26 +7,26 @@
  */
 
 if (!isset($_REQUEST['ReturnTo'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing ReturnTo parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing ReturnTo parameter.');
 }
 
 if (!isset($_REQUEST['AuthId'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthId parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthId parameter.');
 }
 
 /*
  * Setting up the options for the requireAuth() call later..
  */
-$options = array(
-	'ReturnTo' => \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']),
-);
+$options = [
+    'ReturnTo' => \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']),
+];
 
 /*
  * Allows a saml:idp query string parameter specify the IdP entity ID to be used
  * as used by the DiscoJuice embedded client.
  */
 if (!empty($_REQUEST['saml:idp'])) {
-	$options['saml:idp'] = $_REQUEST['saml:idp'];
+    $options['saml:idp'] = $_REQUEST['saml:idp'];
 }
 
 $as = new \SimpleSAML\Auth\Simple($_REQUEST['AuthId']);
diff --git a/modules/core/www/as_logout.php b/modules/core/www/as_logout.php
index bfd92341534a75c243bc33a76944c2f9b564d9e3..6fe7c95adad5ca27aa481781ffc329fa1bb97694 100644
--- a/modules/core/www/as_logout.php
+++ b/modules/core/www/as_logout.php
@@ -7,11 +7,11 @@
  */
 
 if (!isset($_REQUEST['ReturnTo']) || !is_string($_REQUEST['ReturnTo'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing ReturnTo parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing ReturnTo parameter.');
 }
 
 if (!isset($_REQUEST['AuthId']) || !is_string($_REQUEST['AuthId'])) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthId parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthId parameter.');
 }
 
 $as = new \SimpleSAML\Auth\Simple($_REQUEST['AuthId']);
diff --git a/modules/core/www/assets/js/loginuserpass.js b/modules/core/www/assets/js/loginuserpass.js
new file mode 100644
index 0000000000000000000000000000000000000000..e475e8ca6ec6a497dc7159695c82e2806d463906
--- /dev/null
+++ b/modules/core/www/assets/js/loginuserpass.js
@@ -0,0 +1,15 @@
+document.addEventListener(
+    'DOMContentLoaded',
+    function () {
+        var button = document.getElementById("submit_button");
+        button.addEventListener(
+            'click',
+            function () {
+                var translation = document.getElementById("processing_trans");
+                this.disabled = true;
+                this.innerHTML = translation.value;
+                return true;
+            }
+        );
+    }
+);
diff --git a/modules/core/www/authenticate.php b/modules/core/www/authenticate.php
index 8e04e4a6cfa45f14af92bcbad1e984a7361ad548..e1484e1fed26af74e45614a8650e3c7ff56b032c 100644
--- a/modules/core/www/authenticate.php
+++ b/modules/core/www/authenticate.php
@@ -1,11 +1,11 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
 if (!array_key_exists('as', $_REQUEST)) {
-    $t = new SimpleSAML_XHTML_Template($config, 'core:authsource_list.tpl.php');
+    $t = new \SimpleSAML\XHTML\Template($config, 'core:authsource_list.tpl.php');
 
-    $t->data['sources'] = SimpleSAML_Auth_Source::getSources();
+    $t->data['sources'] = \SimpleSAML\Auth\Source::getSources();
     $t->show();
     exit();
 }
@@ -17,31 +17,33 @@ if (array_key_exists('logout', $_REQUEST)) {
     $as->logout($config->getBasePath().'logout.php');
 }
 
-if (array_key_exists(SimpleSAML_Auth_State::EXCEPTION_PARAM, $_REQUEST)) {
+if (array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_PARAM, $_REQUEST)) {
     // This is just a simple example of an error
 
-    $state = SimpleSAML_Auth_State::loadExceptionState();
-    assert(array_key_exists(SimpleSAML_Auth_State::EXCEPTION_DATA, $state));
-    $e = $state[SimpleSAML_Auth_State::EXCEPTION_DATA];
+    $state = \SimpleSAML\Auth\State::loadExceptionState();
+    assert(array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_DATA, $state));
+    $e = $state[\SimpleSAML\Auth\State::EXCEPTION_DATA];
 
     throw $e;
 }
 
 if (!$as->isAuthenticated()) {
-    $url = SimpleSAML\Module::getModuleURL('core/authenticate.php', array('as' => $asId));
-    $params = array(
+    $url = \SimpleSAML\Module::getModuleURL('core/authenticate.php', ['as' => $asId]);
+    $params = [
         'ErrorURL' => $url,
         'ReturnTo' => $url,
-    );
+    ];
     $as->login($params);
 }
 
 $attributes = $as->getAttributes();
+$authData = $as->getAuthDataArray();
 
-$t = new SimpleSAML_XHTML_Template($config, 'status.php', 'attributes');
+$t = new \SimpleSAML\XHTML\Template($config, 'status.php', 'attributes');
 
 $t->data['header'] = '{status:header_saml20_sp}';
 $t->data['attributes'] = $attributes;
+$t->data['authData'] = $authData;
 $t->data['nameid'] = !is_null($as->getAuthData('saml:sp:NameID')) ? $as->getAuthData('saml:sp:NameID') : false;
 $t->data['logouturl'] = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery().'?as='.urlencode($asId).'&logout';
 $t->show();
diff --git a/modules/core/www/cardinality_error.php b/modules/core/www/cardinality_error.php
new file mode 100644
index 0000000000000000000000000000000000000000..b3a3e5b99c17fb4b5a446319cd719b570ac18265
--- /dev/null
+++ b/modules/core/www/cardinality_error.php
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Show a 403 Forbidden page when an attribute violates a cardinality rule
+ *
+ * @package SimpleSAMLphp
+ */
+
+if (!array_key_exists('StateId', $_REQUEST)) {
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
+}
+$id = $_REQUEST['StateId'];
+$state = \SimpleSAML\Auth\State::loadState($id, 'core:cardinality');
+$session = \SimpleSAML\Session::getSessionFromRequest();
+
+\SimpleSAML\Logger::stats('core:cardinality:error '.$state['Destination']['entityid'].' '.$state['saml:sp:IdP'].
+    ' '.implode(',', array_keys($state['core:cardinality:errorAttributes'])));
+
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:cardinality_error.tpl.php');
+$t->data['cardinalityErrorAttributes'] = $state['core:cardinality:errorAttributes'];
+if (isset($state['Source']['auth'])) {
+    $t->data['LogoutURL'] = \SimpleSAML\Module::getModuleURL(
+        'core/authenticate.php',
+        ['as' => $state['Source']['auth']]
+    )."&logout";
+}
+header('HTTP/1.0 403 Forbidden');
+$t->show();
diff --git a/modules/core/www/cleardiscochoices.php b/modules/core/www/cleardiscochoices.php
index 3628a45315554190036520efccf551a8726480e8..f997f1607fd7fc080c9caa1797f80220ae784bf3 100644
--- a/modules/core/www/cleardiscochoices.php
+++ b/modules/core/www/cleardiscochoices.php
@@ -7,31 +7,29 @@ require_once('_include.php');
  */
 
 // The base path for cookies. This should be the installation directory for SimpleSAMLphp.
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 $cookiePath = $config->getBasePath();
 
 // We delete all cookies which starts with 'idpdisco_'
-foreach($_COOKIE as $cookieName => $value) {
-	if (substr($cookieName, 0, 9) !== 'idpdisco_') {
-		/* Not a idpdisco cookie. */
-		continue;
-	}
-
-	/* Delete the cookie. We delete it once without the secure flag and once with the secure flag. This
-	 * ensures that the cookie will be deleted in any case.
-	 */
-    \SimpleSAML\Utils\HTTP::setCookie($cookieName, NULL, array('path' => $cookiePath, 'httponly' => FALSE), FALSE);
+foreach ($_COOKIE as $cookieName => $value) {
+    if (substr($cookieName, 0, 9) !== 'idpdisco_') {
+        // Not a idpdisco cookie.
+        continue;
+    }
+
+    /* Delete the cookie. We delete it once without the secure flag and once with the secure flag. This
+     * ensures that the cookie will be deleted in any case.
+     */
+    \SimpleSAML\Utils\HTTP::setCookie($cookieName, null, ['path' => $cookiePath, 'httponly' => false], false);
 }
 
-
-/* Find where we should go now. */
-if(array_key_exists('ReturnTo', $_REQUEST)) {
-	$returnTo = \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']);
+// Find where we should go now.
+if (array_key_exists('ReturnTo', $_REQUEST)) {
+    $returnTo = \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']);
 } else {
-	/* Return to the front page if no other destination is given. This is the same as the base cookie path. */
-	$returnTo = $cookiePath;
+    // Return to the front page if no other destination is given. This is the same as the base cookie path.
+    $returnTo = $cookiePath;
 }
 
-/* Redirect to destination. */
+// Redirect to destination.
 \SimpleSAML\Utils\HTTP::redirectTrustedURL($returnTo);
-
diff --git a/modules/core/www/frontpage_auth.php b/modules/core/www/frontpage_auth.php
index 59e0ee8a5daa181b6ef9d154010ed805ce52807c..081151788e230f0fccedf24d7e9f1cbb0b51b9a4 100644
--- a/modules/core/www/frontpage_auth.php
+++ b/modules/core/www/frontpage_auth.php
@@ -1,57 +1,48 @@
 <?php
 
-
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists
 if ($config->getBoolean('admin.protectindexpage', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
-$loginurl = SimpleSAML\Utils\Auth::getAdminLoginURL();
-$isadmin = SimpleSAML\Utils\Auth::isAdmin();
-
-
-
-
-	
-$links = array();
-$links_welcome = array();
-$links_config = array();
-$links_auth = array();
-$links_federation = array();
-
-
-$links_auth[] = array(
-	'href' => 'authenticate.php',
-	'text' => '{core:frontpage:authtest}',
-);
-
-$allLinks = array(
-	'links'      => &$links,
-	'welcome'    => &$links_welcome,
-	'config'     => &$links_config,
-	'auth'       => &$links_auth,
-	'federation' => &$links_federation,
-);
-SimpleSAML\Module::callHooks('frontpage', $allLinks);
-
-
-
-$t = new SimpleSAML_XHTML_Template($config, 'core:frontpage_auth.tpl.php');
+$loginurl = \SimpleSAML\Utils\Auth::getAdminLoginURL();
+$isadmin = \SimpleSAML\Utils\Auth::isAdmin();
+$logouturl = \SimpleSAML\Utils\Auth::getAdminLogoutURL();
+
+$links = [];
+$links_welcome = [];
+$links_config = [];
+$links_auth = [];
+$links_federation = [];
+
+$links_auth[] = [
+    'href' => 'login.php',
+    'text' => '{core:frontpage:authtest}',
+];
+
+$allLinks = [
+    'links' => &$links,
+    'welcome' => &$links_welcome,
+    'config' => &$links_config,
+    'auth' => &$links_auth,
+    'federation' => &$links_federation,
+];
+\SimpleSAML\Module::callHooks('frontpage', $allLinks);
+
+$t = new \SimpleSAML\XHTML\Template($config, 'core:frontpage_auth.tpl.php');
 $t->data['pageid'] = 'frontpage_auth';
 $t->data['isadmin'] = $isadmin;
 $t->data['loginurl'] = $loginurl;
+$t->data['logouturl'] = $logouturl;
 
+$t->data['header'] = $t->getTranslator()->t('{core:frontpage:page_title}');
 $t->data['links'] = $links;
 $t->data['links_welcome'] = $links_welcome;
 $t->data['links_config'] = $links_config;
 $t->data['links_auth'] = $links_auth;
 $t->data['links_federation'] = $links_federation;
 
-
-
 $t->show();
-
-
diff --git a/modules/core/www/frontpage_config.php b/modules/core/www/frontpage_config.php
index e1eef9df53d0a85709b7d47a76518e8b41925114..02accc6fb8da3ceaa3cf1e30abd9ec4f0af4f2ed 100644
--- a/modules/core/www/frontpage_config.php
+++ b/modules/core/www/frontpage_config.php
@@ -1,174 +1,182 @@
 <?php
 
-
-
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists.
 if ($config->getBoolean('admin.protectindexpage', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
-$loginurl = SimpleSAML\Utils\Auth::getAdminLoginURL();
-$isadmin = SimpleSAML\Utils\Auth::isAdmin();
-
+$loginurl = \SimpleSAML\Utils\Auth::getAdminLoginURL();
+$isadmin = \SimpleSAML\Utils\Auth::isAdmin();
+$logouturl = \SimpleSAML\Utils\Auth::getAdminLogoutURL();
 
-$warnings = array();
+$warnings = [];
 
 if (!\SimpleSAML\Utils\HTTP::isHTTPS()) {
-	$warnings[] = '{core:frontpage:warnings_https}';
+    $warnings[] = '{core:frontpage:warnings_https}';
 }
 
 if ($config->getValue('secretsalt') === 'defaultsecretsalt') {
-	$warnings[] = '{core:frontpage:warnings_secretsalt}';
+    $warnings[] = '{core:frontpage:warnings_secretsalt}';
 }
 
 if (extension_loaded('suhosin')) {
-	$suhosinLength = ini_get('suhosin.get.max_value_length');
-	if (empty($suhosinLength) || (int)$suhosinLength < 2048) {
-		$warnings[] = '{core:frontpage:warnings_suhosin_url_length}';
-	}
+    $suhosinLength = ini_get('suhosin.get.max_value_length');
+    if (empty($suhosinLength) || (int) $suhosinLength < 2048) {
+        $warnings[] = '{core:frontpage:warnings_suhosin_url_length}';
+    }
 }
 
-
-
-
-
-$links = array();
-$links_welcome = array();
-$links_config = array();
-$links_auth = array();
-$links_federation = array();
-
-
-
-$links_config[] = array(
-	'href' => \SimpleSAML\Utils\HTTP::getBaseURL() . 'admin/hostnames.php',
-	'text' => '{core:frontpage:link_diagnostics}'
-);
-
-$links_config[] = array(
-	'href' => \SimpleSAML\Utils\HTTP::getBaseURL() . 'admin/phpinfo.php',
-	'text' => '{core:frontpage:link_phpinfo}'
-);
-
-$allLinks = array(
-	'links'      => &$links,
-	'welcome'    => &$links_welcome,
-	'config'     => &$links_config,
-	'auth'       => &$links_auth,
-	'federation' => &$links_federation,
-);
-SimpleSAML\Module::callHooks('frontpage', $allLinks);
+$links = [];
+$links_welcome = [];
+$links_config = [];
+$links_auth = [];
+$links_federation = [];
+
+$links_config[] = [
+    'href' => \SimpleSAML\Utils\HTTP::getBaseURL().'admin/hostnames.php',
+    'text' => '{core:frontpage:link_diagnostics}'
+];
+
+$links_config[] = [
+    'href' => \SimpleSAML\Utils\HTTP::getBaseURL().'admin/phpinfo.php',
+    'text' => '{core:frontpage:link_phpinfo}'
+];
+
+$allLinks = [
+    'links'      => &$links,
+    'welcome'    => &$links_welcome,
+    'config'     => &$links_config,
+    'auth'       => &$links_auth,
+    'federation' => &$links_federation,
+];
+\SimpleSAML\Module::callHooks('frontpage', $allLinks);
 
 // Check for updates. Store the remote result in the session so we
 // don't need to fetch it on every access to this page.
 $current = $config->getVersion();
 if ($config->getBoolean('admin.checkforupdates', true) && $current !== 'master') {
-	$latest = $session->getData("core:latest_simplesamlphp_version", "version");
-
-	if (!$latest) {
-		$api_url = 'https://api.github.com/repos/simplesamlphp/simplesamlphp/releases';
-		$ch = curl_init($api_url.'/latest');
-		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-		curl_setopt($ch, CURLOPT_USERAGENT, 'SimpleSAMLphp');
-		curl_setopt($ch, CURLOPT_TIMEOUT, 2);
-        curl_setopt($ch, CURLOPT_PROXY, $config->getString('proxy', null));
-        curl_setopt($ch, CURLOPT_PROXYUSERPWD, $config->getstring('proxy.auth', null));
-		$response = curl_exec($ch);
-
-		if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
-			$latest = json_decode($response, true);
-			$session->setData("core:latest_simplesamlphp_version", "version", $latest);
-		}
-		curl_close($ch);
-	}
-
-	if ($latest && version_compare($current, ltrim($latest['tag_name'], 'v'), 'lt')) {
-		$outdated = true;
-		$warnings[] = array(
-			'{core:frontpage:warnings_outdated}',
-			array('%LATEST_URL%' => $latest['html_url'])
-		);
-	}
+    if (!function_exists('curl_init')) {
+        $warnings[] = ['{core:frontpage:warnings_curlmissing}'];
+    } else {
+        $latest = $session->getData("core:latest_simplesamlphp_version", "version");
+
+        if (!$latest) {
+            $api_url = 'https://api.github.com/repos/simplesamlphp/simplesamlphp/releases';
+            $ch = curl_init($api_url.'/latest');
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+            curl_setopt($ch, CURLOPT_USERAGENT, 'SimpleSAMLphp');
+            curl_setopt($ch, CURLOPT_TIMEOUT, 2);
+            curl_setopt($ch, CURLOPT_PROXY, $config->getString('proxy', null));
+            curl_setopt($ch, CURLOPT_PROXYUSERPWD, $config->getValue('proxy.auth', null));
+            $response = curl_exec($ch);
+
+            if (curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200) {
+                $latest = json_decode($response, true);
+                $session->setData("core:latest_simplesamlphp_version", "version", $latest);
+            }
+            curl_close($ch);
+        }
+
+        if ($latest && version_compare($current, ltrim($latest['tag_name'], 'v'), 'lt')) {
+            $outdated = true;
+            $warnings[] = [
+                '{core:frontpage:warnings_outdated}',
+                ['%LATEST_URL%' => $latest['html_url']]
+            ];
+        }
+    }
 }
 
-$enablematrix = array(
-	'saml20-idp' => $config->getBoolean('enable.saml20-idp', false),
-	'shib13-idp' => $config->getBoolean('enable.shib13-idp', false),
-);
-
-
-$functionchecks = array(
-	'time'             => array('required', 'Date/Time Extension'),
-	'hash'             => array('required',  'Hashing function'),
-	'gzinflate'        => array('required',  'ZLib'),
-	'openssl_sign'     => array('required',  'OpenSSL'),
-	'dom_import_simplexml' => array('required', 'XML DOM'),
-	'preg_match'       => array('required',  'RegEx support'),
-	'json_decode'      => array('required', 'JSON support'),
-	'class_implements' => array('required', 'Standard PHP Library (SPL)'),
-	'mb_strlen'        => array('required', 'Multibyte String Extension'),
-	'curl_init'        => array('optional', 'cURL (required if automatic version checks are used, also by some modules.'),
-	'session_start'  => array('optional', 'Session Extension (required if PHP sessions are used)'),
-	'pdo_drivers'    => array('optional',  'PDO Extension (required if a database backend is used)'),
-);
-if (SimpleSAML\Module::isModuleEnabled('ldap')) {
-	$functionchecks['ldap_bind'] = array('optional',  'LDAP Extension (required if an LDAP backend is used)');
+$enablematrix = [
+    'saml20idp' => $config->getBoolean('enable.saml20-idp', false),
+    'shib13idp' => $config->getBoolean('enable.shib13-idp', false),
+];
+
+
+$functionchecks = [
+    'time'             => ['required', 'Date/Time Extension'],
+    'hash'             => ['required', 'Hashing function'],
+    'gzinflate'        => ['required', 'ZLib'],
+    'openssl_sign'     => ['required', 'OpenSSL'],
+    'dom_import_simplexml' => ['required', 'XML DOM'],
+    'preg_match'       => ['required', 'RegEx support'],
+    'json_decode'      => ['required', 'JSON support'],
+    'class_implements' => ['required', 'Standard PHP Library (SPL)'],
+    'mb_strlen'        => ['required', 'Multibyte String Extension'],
+    'curl_init' => ['optional', 'cURL (required if automatic version checks are used, also by some modules.'],
+    'session_start'  => ['optional', 'Session Extension (required if PHP sessions are used)'],
+    'pdo_drivers'    => ['optional', 'PDO Extension (required if a database backend is used)'],
+];
+if (\SimpleSAML\Module::isModuleEnabled('ldap')) {
+    $functionchecks['ldap_bind'] = ['optional', 'LDAP Extension (required if an LDAP backend is used)'];
 }
-if (SimpleSAML\Module::isModuleEnabled('radius')) {
-        $functionchecks['radius_auth_open'] = array('optional',  'Radius Extension (required if a Radius backend is used)');
+if (\SimpleSAML\Module::isModuleEnabled('radius')) {
+    $functionchecks['radius_auth_open'] = ['optional', 'Radius Extension (required if a Radius backend is used)'];
 }
 
-$funcmatrix = array();
-$funcmatrix[] = array(
-	'required' => 'required', 
-	'descr' => 'PHP Version >= 5.4. You run: ' . phpversion(),
-	'enabled' => version_compare(phpversion(), '5.4', '>='));
-foreach ($functionchecks AS $func => $descr) {
-	$funcmatrix[] = array('descr' => $descr[1], 'required' => $descr[0], 'enabled' => function_exists($func));
+$funcmatrix = [];
+$funcmatrix[] = [
+    'required' => 'required',
+    'descr' => 'PHP Version >= 5.5. You run: '.phpversion(),
+    'enabled' => version_compare(phpversion(), '5.5', '>=')
+];
+foreach ($functionchecks as $func => $descr) {
+    $funcmatrix[] = ['descr' => $descr[1], 'required' => $descr[0], 'enabled' => function_exists($func)];
 }
 
-$funcmatrix[] = array(
+$funcmatrix[] = [
     'required' => 'optional',
     'descr' => 'predis/predis (required if the redis data store is used)',
     'enabled' => class_exists('\Predis\Client'),
-);
+];
 
-$funcmatrix[] = array(
+$funcmatrix[] = [
     'required' => 'optional',
     'descr' => 'Memcache or Memcached Extension (required if a Memcached backend is used)',
     'enabled' => class_exists('Memcache') || class_exists('Memcached'),
-);
+];
 
-/* Some basic configuration checks */
+// Some basic configuration checks
 
-if($config->getString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
-	$mail_ok = FALSE;
+if ($config->getString('technicalcontact_email', 'na@example.org') === 'na@example.org') {
+    $mail_ok = false;
 } else {
-	$mail_ok = TRUE;
+    $mail_ok = true;
 }
-$funcmatrix[] = array(
-	'required' => 'recommended',
-	'descr' => 'technicalcontact_email option set',
-	'enabled' => $mail_ok
-	);
-if($config->getString('auth.adminpassword', '123') === '123') {
-	$password_ok = FALSE;
+$funcmatrix[] = [
+    'required' => 'recommended',
+    'descr' => 'technicalcontact_email option set',
+    'enabled' => $mail_ok
+];
+if ($config->getString('auth.adminpassword', '123') === '123') {
+    $password_ok = false;
 } else {
-	$password_ok = TRUE;
+    $password_ok = true;
 }
-$funcmatrix[] = array(
-	'required' => 'required',
-	'descr' => 'auth.adminpassword option set',
-	'enabled' => $password_ok
-);
-
-$t = new SimpleSAML_XHTML_Template($config, 'core:frontpage_config.tpl.php');
+$funcmatrix[] = [
+    'required' => 'required',
+    'descr' => 'auth.adminpassword option set',
+    'enabled' => $password_ok
+];
+
+$t = new \SimpleSAML\XHTML\Template($config, 'core:frontpage_config.tpl.php');
+$translator = $t->getTranslator();
 $t->data['pageid'] = 'frontpage_config';
+$t->data['header'] = $translator->t('{core:frontpage:page_title}');
 $t->data['isadmin'] = $isadmin;
 $t->data['loginurl'] = $loginurl;
+$t->data['logouturl'] = $logouturl;
+
+foreach ($warnings as &$warning) {
+    if (is_array($warning)) {
+        $warning = $translator->t($warning[0], $warning[1]);
+    } else {
+        $warning = $translator->t($warning);
+    }
+}
 $t->data['warnings'] = $warnings;
 
 
@@ -179,17 +187,14 @@ $t->data['links_auth'] = $links_auth;
 $t->data['links_federation'] = $links_federation;
 
 
-
 $t->data['enablematrix'] = $enablematrix;
 $t->data['funcmatrix'] = $funcmatrix;
-$t->data['requiredmap'] = array(
-    'recommended' => $t->noop('{core:frontpage:recommended}'),
-    'required' => $t->noop('{core:frontpage:required}'),
-    'optional' => $t->noop('{core:frontpage:optional}'),
-);
+$t->data['requiredmap'] = [
+    'recommended' => $translator->noop('{core:frontpage:recommended}'),
+    'required' => $translator->noop('{core:frontpage:required}'),
+    'optional' => $translator->noop('{core:frontpage:optional}'),
+];
 $t->data['version'] = $config->getVersion();
 $t->data['directory'] = dirname(dirname(dirname(dirname(__FILE__))));
 
 $t->show();
-
-
diff --git a/modules/core/www/frontpage_federation.php b/modules/core/www/frontpage_federation.php
index 80f8aa7eda3c71ac3f2a9c68d132279c679a6420..267a54a53ff1c0911924375e53cf60a6562d656f 100644
--- a/modules/core/www/frontpage_federation.php
+++ b/modules/core/www/frontpage_federation.php
@@ -1,154 +1,175 @@
 <?php
 
-
-
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists.
 if ($config->getBoolean('admin.protectindexpage', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
-$loginurl = SimpleSAML\Utils\Auth::getAdminLoginURL();
-$isadmin = SimpleSAML\Utils\Auth::isAdmin();
-
-
-
-
-	
-	
-	
-$links = array();
-$links_welcome = array();
-$links_config = array();
-$links_auth = array();
-$links_federation = array();
-
-
-
-
-if($config->getBoolean('idpdisco.enableremember', FALSE)) {
-	$links_federation[] = array(
-		'href' => 'cleardiscochoices.php',
-		'text' => '{core:frontpage:link_cleardiscochoices}',
-	);
+$logouturl = \SimpleSAML\Utils\Auth::getAdminLogoutURL();
+$loginurl = \SimpleSAML\Utils\Auth::getAdminLoginURL();
+$isadmin = \SimpleSAML\Utils\Auth::isAdmin();
+
+$links = [];
+$links_welcome = [];
+$links_config = [];
+$links_auth = [];
+$links_federation = [];
+
+if ($config->getBoolean('idpdisco.enableremember', false)) {
+    $links_federation[] = [
+        'href' => 'cleardiscochoices.php',
+        'text' => '{core:frontpage:link_cleardiscochoices}',
+    ];
 }
 
 
-$links_federation[] = array(
-	'href' => \SimpleSAML\Utils\HTTP::getBaseURL() . 'admin/metadata-converter.php',
-	'text' => '{core:frontpage:link_xmlconvert}',
-);
-
-
-
-
-$allLinks = array(
-	'links'      => &$links,
-	'welcome'    => &$links_welcome,
-	'config'     => &$links_config,
-	'auth'       => &$links_auth,
-	'federation' => &$links_federation,
-);
-SimpleSAML\Module::callHooks('frontpage', $allLinks);
-
-
-$metadataHosted = array();
-SimpleSAML\Module::callHooks('metadata_hosted', $metadataHosted);
+$links_federation[] = [
+    'href' => \SimpleSAML\Utils\HTTP::getBaseURL().'admin/metadata-converter.php',
+    'text' => '{core:frontpage:link_xmlconvert}',
+];
 
+$allLinks = [
+    'links' => &$links,
+    'welcome' => &$links_welcome,
+    'config' => &$links_config,
+    'auth' => &$links_auth,
+    'federation' => &$links_federation,
+];
+\SimpleSAML\Module::callHooks('frontpage', $allLinks);
 
 
+$metadataHosted = [];
+\SimpleSAML\Module::callHooks('metadata_hosted', $metadataHosted);
 
 
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
-
-
-
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
-
-$metaentries = array('hosted' => $metadataHosted, 'remote' => array() );
+$metaentries = ['hosted' => $metadataHosted, 'remote' => []];
 
 
 if ($isadmin) {
-	$metaentries['remote']['saml20-idp-remote'] = $metadata->getList('saml20-idp-remote');
-	$metaentries['remote']['shib13-idp-remote'] = $metadata->getList('shib13-idp-remote');
+    $metaentries['remote']['saml20-idp-remote'] = $metadata->getList('saml20-idp-remote');
+    $metaentries['remote']['shib13-idp-remote'] = $metadata->getList('shib13-idp-remote');
 }
 
-if ($config->getBoolean('enable.saml20-idp', FALSE) === true) {
-	try {
-		$metaentries['hosted']['saml20-idp'] = $metadata->getMetaDataCurrent('saml20-idp-hosted');
-		$metaentries['hosted']['saml20-idp']['metadata-url'] = $config->getBasePath() .
-                                                               'saml2/idp/metadata.php?output=xhtml';
-		if ($isadmin)
-			$metaentries['remote']['saml20-sp-remote'] = $metadata->getList('saml20-sp-remote');
-	} catch(Exception $e) {
-        SimpleSAML\Logger::error('Federation: Error loading saml20-idp: ' . $e->getMessage());
+if ($config->getBoolean('enable.saml20-idp', false) === true) {
+    try {
+        $metaentries['hosted']['saml20-idp'] = $metadata->getMetaDataCurrent('saml20-idp-hosted');
+        $metaentries['hosted']['saml20-idp']['metadata-url'] =
+            $config->getBasePath().'saml2/idp/metadata.php?output=xhtml';
+        if ($isadmin) {
+            $metaentries['remote']['saml20-sp-remote'] = $metadata->getList('saml20-sp-remote');
+        }
+    } catch (Exception $e) {
+        \SimpleSAML\Logger::error('Federation: Error loading saml20-idp: '.$e->getMessage());
     }
 }
-if ($config->getBoolean('enable.shib13-idp', FALSE) === true) {
-	try {
-		$metaentries['hosted']['shib13-idp'] = $metadata->getMetaDataCurrent('shib13-idp-hosted');
-		$metaentries['hosted']['shib13-idp']['metadata-url'] = $config->getBasePath() .
-                                                               'shib13/idp/metadata.php?output=xhtml';
-		if ($isadmin)
-			$metaentries['remote']['shib13-sp-remote'] = $metadata->getList('shib13-sp-remote');
-	} catch(Exception $e) {
-        SimpleSAML\Logger::error('Federation: Error loading shib13-idp: ' . $e->getMessage());
+if ($config->getBoolean('enable.shib13-idp', false) === true) {
+    try {
+        $metaentries['hosted']['shib13-idp'] = $metadata->getMetaDataCurrent('shib13-idp-hosted');
+        $metaentries['hosted']['shib13-idp']['metadata-url'] =
+            $config->getBasePath().'shib13/idp/metadata.php?output=xhtml';
+        if ($isadmin) {
+            $metaentries['remote']['shib13-sp-remote'] = $metadata->getList('shib13-sp-remote');
+        }
+    } catch (Exception $e) {
+        \SimpleSAML\Logger::error('Federation: Error loading shib13-idp: '.$e->getMessage());
     }
 }
-if ($config->getBoolean('enable.adfs-idp', FALSE) === true) {
+if ($config->getBoolean('enable.adfs-idp', false) === true) {
     try {
         $metaentries['hosted']['adfs-idp'] = $metadata->getMetaDataCurrent('adfs-idp-hosted');
-        $metaentries['hosted']['adfs-idp']['metadata-url'] = SimpleSAML\Module::getModuleURL('adfs/idp/metadata.php',
-                                                                                             array('output' => 'xhtml'));
-        if ($isadmin)
+        $metaentries['hosted']['adfs-idp']['metadata-url'] = \SimpleSAML\Module::getModuleURL(
+            'adfs/idp/metadata.php',
+            ['output' => 'xhtml']
+        );
+        if ($isadmin) {
             $metaentries['remote']['adfs-sp-remote'] = $metadata->getList('adfs-sp-remote');
-    } catch(Exception $e) {
-        SimpleSAML\Logger::error('Federation: Error loading adfs-idp: ' . $e->getMessage());
+        }
+    } catch (Exception $e) {
+        \SimpleSAML\Logger::error('Federation: Error loading adfs-idp: '.$e->getMessage());
     }
 }
 
 foreach ($metaentries['remote'] as $key => $value) {
-	if (empty($value)) {
-		unset($metaentries['remote'][$key]);
-	}
+    if (empty($value)) {
+        unset($metaentries['remote'][$key]);
+    }
 }
 
-$t = new SimpleSAML_XHTML_Template($config, 'core:frontpage_federation.tpl.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'core:frontpage_federation.tpl.php');
+$translator = $t->getTranslator();
+
+$language = $translator->getLanguage()->getLanguage();
+$fallbackLanguage = 'en';
+$defaultLanguage = $config->getString('language.default', $fallbackLanguage);
+
+$translators = [
+    'name' => 'name_translated',
+    'descr' => 'descr_translated',
+    'OrganizationDisplayName' => 'organizationdisplayname_translated',
+];
+
+foreach ($metaentries['hosted'] as $index => $entity) {
+    foreach ($translators as $old => $new) {
+        if (isset($entity[$old][$language])) {
+            $metaentries['hosted'][$index][$new] = $entity[$old][$language];
+        } elseif (isset($entity[$old][$defaultLanguage])) {
+            $metaentries['hosted'][$index][$new] = $entity[$old][$defaultLanguage];
+        } elseif (isset($entity[$old][$fallbackLanguage])) {
+            $metaentries['hosted'][$index][$new] = $entity[$old][$fallbackLanguage];
+        }
+    }
+}
+foreach ($metaentries['remote'] as $key => $set) {
+    foreach ($set as $entityid => $entity) {
+        foreach ($translators as $old => $new) {
+            if (isset($entity[$old][$language])) {
+                $metaentries['remote'][$key][$entityid][$new] = $entity[$old][$language];
+            } elseif (isset($entity[$old][$defaultLanguage])) {
+                $metaentries['remote'][$key][$entityid][$new] = $entity[$old][$defaultLanguage];
+            } elseif (isset($entity[$old][$fallbackLanguage])) {
+                $metaentries['remote'][$key][$entityid][$new] = $entity[$old][$fallbackLanguage];
+            } elseif (isset($metaentries['remote'][$key][$entityid][$old])) {
+                $metaentries['remote'][$key][$entityid][$new] = $metaentries['remote'][$key][$entityid][$old];
+            }
+        }
+    }
+}
 
 # look up translated string
-$mtype = array(
-    'saml20-sp-remote' => $t->noop('{admin:metadata_saml20-sp}'),
-    'saml20-sp-hosted' => $t->noop('{admin:metadata_saml20-sp}'),
-    'saml20-idp-remote' => $t->noop('{admin:metadata_saml20-idp}'),
-    'saml20-idp-hosted' => $t->noop('{admin:metadata_saml20-idp}'),
-    'shib13-sp-remote' => $t->noop('{admin:metadata_shib13-sp}'),
-    'shib13-sp-hosted' => $t->noop('{admin:metadata_shib13-sp}'),
-    'shib13-idp-remote' => $t->noop('{admin:metadata_shib13-idp}'),
-    'shib13-idp-hosted' => $t->noop('{admin:metadata_shib13-idp}'),
-    'adfs-sp-remote' => $t->noop('{admin:metadata_adfs-sp}'),
-    'adfs-sp-hosted' => $t->noop('{admin:metadata_adfs-sp}'),
-    'adfs-idp-remote' => $t->noop('{admin:metadata_adfs-idp}'),
-    'adfs-idp-hosted' => $t->noop('{admin:metadata_adfs-idp}'),
-);
+$mtype = [
+    'saml20-sp-remote' => $translator->noop('{admin:metadata_saml20-sp}'),
+    'saml20-sp-hosted' => $translator->noop('{admin:metadata_saml20-sp}'),
+    'saml20-idp-remote' => $translator->noop('{admin:metadata_saml20-idp}'),
+    'saml20-idp-hosted' => $translator->noop('{admin:metadata_saml20-idp}'),
+    'shib13-sp-remote' => $translator->noop('{admin:metadata_shib13-sp}'),
+    'shib13-sp-hosted' => $translator->noop('{admin:metadata_shib13-sp}'),
+    'shib13-idp-remote' => $translator->noop('{admin:metadata_shib13-idp}'),
+    'shib13-idp-hosted' => $translator->noop('{admin:metadata_shib13-idp}'),
+    'adfs-sp-remote' => $translator->noop('{admin:metadata_adfs-sp}'),
+    'adfs-sp-hosted' => $translator->noop('{admin:metadata_adfs-sp}'),
+    'adfs-idp-remote' => $translator->noop('{admin:metadata_adfs-idp}'),
+    'adfs-idp-hosted' => $translator->noop('{admin:metadata_adfs-idp}'),
+];
 
 $t->data['pageid'] = 'frontpage_federation';
 $t->data['isadmin'] = $isadmin;
 $t->data['loginurl'] = $loginurl;
-
+$t->data['logouturl'] = $logouturl;
 
 $t->data['links'] = $links;
 $t->data['links_welcome'] = $links_welcome;
 $t->data['links_config'] = $links_config;
 $t->data['links_auth'] = $links_auth;
 $t->data['links_federation'] = $links_federation;
+$t->data['header'] = $translator->t('{core:frontpage:page_title}');
 
-
-
+$t->data['metadata_url'] = \SimpleSAML\Module::getModuleURL('core/show_metadata.php');
 $t->data['metaentries'] = $metaentries;
 $t->data['mtype'] = $mtype;
 
-
 $t->show();
-
diff --git a/modules/core/www/frontpage_welcome.php b/modules/core/www/frontpage_welcome.php
index abeeecea12715fb6b7db7334c8437de5c3889f7b..4dfb4fef195ac8fb0f803e6c2bb2e8e0e4229f81 100644
--- a/modules/core/www/frontpage_welcome.php
+++ b/modules/core/www/frontpage_welcome.php
@@ -1,66 +1,49 @@
 <?php
 
-
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists.
 if ($config->getBoolean('admin.protectindexpage', false)) {
     SimpleSAML\Utils\Auth::requireAdmin();
 }
-$loginurl = SimpleSAML\Utils\Auth::getAdminLoginURL();
-$isadmin = SimpleSAML\Utils\Auth::isAdmin();
-
-
-
-
-
-$links = array();
-$links_welcome = array();
-$links_config = array();
-$links_auth = array();
-$links_federation = array();
-
-
-
-$allLinks = array(
-	'links'      => &$links,
-	'welcome'    => &$links_welcome,
-	'config'     => &$links_config,
-	'auth'       => &$links_auth,
-	'federation' => &$links_federation,
-);
-
-$links_welcome[] = array(
-	'href' => 'https://simplesamlphp.org/docs/stable/',
-	'text' => '{core:frontpage:doc_header}',
-);
-
-SimpleSAML\Module::callHooks('frontpage', $allLinks);
-
-
-
-
-
-
-
-
-
-$t = new SimpleSAML_XHTML_Template($config, 'core:frontpage_welcome.tpl.php');
+$logouturl = \SimpleSAML\Utils\Auth::getAdminLogoutURL();
+$loginurl = \SimpleSAML\Utils\Auth::getAdminLoginURL();
+$isadmin = \SimpleSAML\Utils\Auth::isAdmin();
+
+$links = [];
+$links_welcome = [];
+$links_config = [];
+$links_auth = [];
+$links_federation = [];
+
+$allLinks = [
+    'links'      => &$links,
+    'welcome'    => &$links_welcome,
+    'config'     => &$links_config,
+    'auth'       => &$links_auth,
+    'federation' => &$links_federation,
+];
+
+$links_welcome[] = [
+    'href' => 'https://simplesamlphp.org/docs/stable/',
+    'text' => '{core:frontpage:doc_header}',
+];
+
+\SimpleSAML\Module::callHooks('frontpage', $allLinks);
+
+$t = new \SimpleSAML\XHTML\Template($config, 'core:frontpage_welcome.tpl.php');
 $t->data['pageid'] = 'frontpage_welcome';
 $t->data['isadmin'] = $isadmin;
 $t->data['loginurl'] = $loginurl;
+$t->data['logouturl'] = $logouturl;
 
 $t->data['links'] = $links;
 $t->data['links_welcome'] = $links_welcome;
 $t->data['links_config'] = $links_config;
 $t->data['links_auth'] = $links_auth;
 $t->data['links_federation'] = $links_federation;
-
-
-
+$t->data['header'] = $t->getTranslator()->t('{core:frontpage:page_title}');
 
 $t->show();
-
-
diff --git a/modules/core/www/idp/logout-iframe-done.php b/modules/core/www/idp/logout-iframe-done.php
index 6b00621b842b3f334939797f93ea2c78172cb88c..7725754e48b0e10d2b3e468274b640a42ed41a93 100644
--- a/modules/core/www/idp/logout-iframe-done.php
+++ b/modules/core/www/idp/logout-iframe-done.php
@@ -1,22 +1,22 @@
 <?php
 
 if (!isset($_REQUEST['id'])) {
-    throw new SimpleSAML_Error_BadRequest('Missing required parameter: id');
+    throw new \SimpleSAML\Error\BadRequest('Missing required parameter: id');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['id'], 'core:Logout-IFrame');
-$idp = SimpleSAML_IdP::getByState($state);
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout-IFrame');
+$idp = \SimpleSAML\IdP::getByState($state);
 
 $associations = $idp->getAssociations();
 
 if (!isset($_REQUEST['cancel'])) {
-    SimpleSAML\Logger::stats('slo-iframe done');
-    SimpleSAML_Stats::log('core:idp:logout-iframe:page', array('type' => 'done'));
+    \SimpleSAML\Logger::stats('slo-iframe done');
+    \SimpleSAML\Stats::log('core:idp:logout-iframe:page', ['type' => 'done']);
     $SPs = $state['core:Logout-IFrame:Associations'];
 } else {
     // user skipped global logout
-    SimpleSAML\Logger::stats('slo-iframe skip');
-    SimpleSAML_Stats::log('core:idp:logout-iframe:page', array('type' => 'skip'));
-    $SPs = array(); // no SPs should have been logged out
+    \SimpleSAML\Logger::stats('slo-iframe skip');
+    \SimpleSAML\Stats::log('core:idp:logout-iframe:page', ['type' => 'skip']);
+    $SPs = []; // no SPs should have been logged out
     $state['core:Failed'] = true; // mark as partial logout
 }
 
@@ -42,14 +42,14 @@ foreach ($SPs as $assocId => $sp) {
     if ($sp['core:Logout-IFrame:State'] === 'completed') {
         $idp->terminateAssociation($assocId);
     } else {
-        SimpleSAML\Logger::warning('Unable to terminate association with '.var_export($assocId, true).'.');
+        \SimpleSAML\Logger::warning('Unable to terminate association with '.var_export($assocId, true).'.');
         if (isset($sp['saml:entityID'])) {
             $spId = $sp['saml:entityID'];
         } else {
             $spId = $assocId;
         }
-        SimpleSAML\Logger::stats('slo-iframe-fail '.$spId);
-        SimpleSAML_Stats::log('core:idp:logout-iframe:spfail', array('sp' => $spId));
+        \SimpleSAML\Logger::stats('slo-iframe-fail '.$spId);
+        \SimpleSAML\Stats::log('core:idp:logout-iframe:spfail', ['sp' => $spId]);
         $state['core:Failed'] = true;
     }
 }
diff --git a/modules/core/www/idp/logout-iframe-post.php b/modules/core/www/idp/logout-iframe-post.php
index 7079e19aa6b63be297bf5031e43141b3b30c92e6..2081dfe26d69fb87b55b54c814d3bd1d8fe7911d 100644
--- a/modules/core/www/idp/logout-iframe-post.php
+++ b/modules/core/www/idp/logout-iframe-post.php
@@ -1,13 +1,13 @@
 <?php
 
 if (!isset($_REQUEST['idp'])) {
-    throw new SimpleSAML_Error_BadRequest('Missing "idp" parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing "idp" parameter.');
 }
 $idp = (string) $_REQUEST['idp'];
-$idp = SimpleSAML_IdP::getById($idp);
+$idp = \SimpleSAML\IdP::getById($idp);
 
 if (!isset($_REQUEST['association'])) {
-    throw new SimpleSAML_Error_BadRequest('Missing "association" parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing "association" parameter.');
 }
 $assocId = urldecode($_REQUEST['association']);
 
@@ -18,15 +18,15 @@ if (isset($_REQUEST['RelayState'])) {
 
 $associations = $idp->getAssociations();
 if (!isset($associations[$assocId])) {
-    throw new SimpleSAML_Error_BadRequest('Invalid association id.');
+    throw new \SimpleSAML\Error\BadRequest('Invalid association id.');
 }
 $association = $associations[$assocId];
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpMetadata = $idp->getConfig();
 $spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
 
-$lr = sspmod_saml_Message::buildLogoutRequest($idpMetadata, $spMetadata);
+$lr = \SimpleSAML\Module\saml\Message::buildLogoutRequest($idpMetadata, $spMetadata);
 $lr->setSessionIndex($association['saml:SessionIndex']);
 $lr->setNameId($association['saml:NameID']);
 
@@ -41,15 +41,15 @@ if ($encryptNameId === null) {
     $encryptNameId = $idpMetadata->getBoolean('nameid.encryption', false);
 }
 if ($encryptNameId) {
-    $lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
+    $lr->encryptNameId(\SimpleSAML\Module\saml\Message::getEncryptionKey($spMetadata));
 }
 
-SimpleSAML_Stats::log('saml:idp:LogoutRequest:sent', array(
+\SimpleSAML\Stats::log('saml:idp:LogoutRequest:sent', [
     'spEntityID'  => $association['saml:entityID'],
     'idpEntityID' => $idpMetadata->getString('entityid'),
-));
+]);
 
-$bindings = array(\SAML2\Constants::BINDING_HTTP_POST);
+$bindings = [\SAML2\Constants::BINDING_HTTP_POST];
 
 $dst = $spMetadata->getDefaultEndpoint('SingleLogoutService', $bindings);
 $binding = \SAML2\Binding::getBinding($dst['Binding']);
diff --git a/modules/core/www/idp/logout-iframe.js b/modules/core/www/idp/logout-iframe.js
index 6fc401070571c41ec845234551588333276da539..921c23cdfebd5acbd42369e5f571f509fcd0ab74 100644
--- a/modules/core/www/idp/logout-iframe.js
+++ b/modules/core/www/idp/logout-iframe.js
@@ -1,8 +1,8 @@
 /**
  * This function updates the global logout status.
  */
-function updateStatus() {
-
+function updateStatus()
+{
     var nFailed = 0;
     var nProgress = 0;
     for (sp in window.spStatus) {
@@ -33,7 +33,8 @@ function updateStatus() {
  * @param status The new status.
  * @param reason The reason for the status change.
  */
-function updateSPStatus(spId, status, reason) {
+function updateSPStatus(spId, status, reason)
+{
     if (window.spStatus[spId] === status) {
         // unchanged
         return;
@@ -63,7 +64,8 @@ function updateSPStatus(spId, status, reason) {
  *
  * @param spId The SP that completed logout successfully.
  */
-function logoutCompleted(spId) {
+function logoutCompleted(spId)
+{
     updateSPStatus(spId, 'completed', '');
 }
 
@@ -75,7 +77,8 @@ function logoutCompleted(spId) {
  * @param spId The SP that failed to complete logout.
  * @param reason The reason why logout failed.
  */
-function logoutFailed(spId, reason) {
+function logoutFailed(spId, reason)
+{
     updateSPStatus(spId, 'failed', reason);
 }
 
@@ -84,7 +87,8 @@ function logoutFailed(spId, reason) {
  *
  * If an SP didn't reply by the timeout, we'll mark it as failed.
  */
-function timeoutSPs() {
+function timeoutSPs()
+{
     var cTime = ((new Date()).getTime() - window.startTime) / 1000;
     for (var sp in window.spStatus) {
         if (window.spTimeout[sp] <= cTime && window.spStatus[sp] === 'inprogress') {
diff --git a/modules/core/www/idp/logout-iframe.php b/modules/core/www/idp/logout-iframe.php
index caf00f11db1a154534a9cf8eebf6326da7b78cbe..27195af6b83b40fc2d7e6be4baee1cf8bbfa64af 100644
--- a/modules/core/www/idp/logout-iframe.php
+++ b/modules/core/www/idp/logout-iframe.php
@@ -1,28 +1,29 @@
 <?php
 
 if (!isset($_REQUEST['id'])) {
-    throw new SimpleSAML_Error_BadRequest('Missing required parameter: id');
+    throw new \SimpleSAML\Error\BadRequest('Missing required parameter: id');
 }
 
 if (isset($_REQUEST['type'])) {
     $type = (string) $_REQUEST['type'];
-    if (!in_array($type, array('init', 'js', 'nojs', 'embed'), true)) {
-        throw new SimpleSAML_Error_BadRequest('Invalid value for type.');
+    if (!in_array($type, ['init', 'js', 'nojs', 'embed'], true)) {
+        throw new \SimpleSAML\Error\BadRequest('Invalid value for type.');
     }
 } else {
     $type = 'init';
 }
 
 if ($type !== 'embed') {
-    SimpleSAML\Logger::stats('slo-iframe '.$type);
-    SimpleSAML_Stats::log('core:idp:logout-iframe:page', array('type' => $type));
+    \SimpleSAML\Logger::stats('slo-iframe '.$type);
+    \SimpleSAML\Stats::log('core:idp:logout-iframe:page', ['type' => $type]);
 }
 
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['id'], 'core:Logout-IFrame');
-$idp = SimpleSAML_IdP::getByState($state);
-$mdh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout-IFrame');
+$idp = \SimpleSAML\IdP::getByState($state);
+$mdh = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
-if ($type !== 'init') { // update association state
+if ($type !== 'init') {
+    // update association state
     foreach ($state['core:Logout-IFrame:Associations'] as $assocId => &$sp) {
         $spId = sha1($assocId);
 
@@ -53,8 +54,8 @@ if ($type !== 'init') { // update association state
 
         if (!isset($sp['core:Logout-IFrame:Timeout'])) {
             if (method_exists($sp['Handler'], 'getAssociationConfig')) {
-                $assocIdP = SimpleSAML_IdP::getByState($sp);
-                $assocConfig = call_user_func(array($sp['Handler'], 'getAssociationConfig'), $assocIdP, $sp);
+                $assocIdP = \SimpleSAML\IdP::getByState($sp);
+                $assocConfig = call_user_func([$sp['Handler'], 'getAssociationConfig'], $assocIdP, $sp);
                 $sp['core:Logout-IFrame:Timeout'] = $assocConfig->getInteger('core:logout-timeout', 5) + time();
             } else {
                 $sp['core:Logout-IFrame:Timeout'] = time() + 5;
@@ -71,10 +72,10 @@ foreach ($state['core:Logout-IFrame:Associations'] as $assocId => &$sp) {
     }
 
     try {
-        $assocIdP = SimpleSAML_IdP::getByState($sp);
-        $url = call_user_func(array($sp['Handler'], 'getLogoutURL'), $assocIdP, $sp, null);
+        $assocIdP = \SimpleSAML\IdP::getByState($sp);
+        $url = call_user_func([$sp['Handler'], 'getLogoutURL'], $assocIdP, $sp, null);
         $sp['core:Logout-IFrame:URL'] = $url;
-    } catch (Exception $e) {
+    } catch (\Exception $e) {
         $sp['core:Logout-IFrame:State'] = 'failed';
     }
 }
@@ -90,7 +91,7 @@ if ($state['core:TerminatedAssocId'] !== null) {
 }
 
 // build an array with information about all services currently logged in
-$remaining = array();
+$remaining = [];
 foreach ($state['core:Logout-IFrame:Associations'] as $association) {
     $key = sha1($association['id']);
     $mdset = 'saml20-sp-remote';
@@ -98,7 +99,7 @@ foreach ($state['core:Logout-IFrame:Associations'] as $association) {
         $mdset = 'adfs-sp-remote';
     }
 
-    $remaining[$key] = array(
+    $remaining[$key] = [
         'id' => $association['id'],
         'expires_on' => $association['Expires'],
         'entityID' => $association['saml:entityID'],
@@ -106,26 +107,27 @@ foreach ($state['core:Logout-IFrame:Associations'] as $association) {
         'status' => $association['core:Logout-IFrame:State'],
         'logoutURL' => $association['core:Logout-IFrame:URL'],
         'metadata' => $mdh->getMetaDataConfig($association['saml:entityID'], $mdset)->toArray(),
-    );
+    ];
     if (isset($association['core:Logout-IFrame:Timeout'])) {
         $remaining[$key]['timeout'] = $association['core:Logout-IFrame:Timeout'];
     }
 }
 
-$id = SimpleSAML_Auth_State::saveState($state, 'core:Logout-IFrame');
-$globalConfig = SimpleSAML_Configuration::getInstance();
-
-$template_id = 'core:logout-iframe.php';
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 if ($type === 'nojs') {
-    $template_id = 'core:logout-iframe-wrapper.php';
+    $t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:logout-iframe-wrapper.php');
+} else {
+    $t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:logout-iframe.php');
 }
 
-$t = new SimpleSAML_XHTML_Template($globalConfig, $template_id);
-$t->data['auth_state'] = $id;
 /**
  * @deprecated The "id" variable will be removed. Please use "auth_state" instead.
  */
+$id = \SimpleSAML\Auth\State::saveState($state, 'core:Logout-IFrame');
 $t->data['id'] = $id;
+$t->data['auth_state'] = $id;
+
+$t->data['header'] = $t->getTranslator()->t('{logout:progress}');
 $t->data['type'] = $type;
 $t->data['terminated_service'] = $terminated;
 $t->data['remaining_services'] = $remaining;
@@ -138,7 +140,7 @@ $t->data['SPs'] = $state['core:Logout-IFrame:Associations'];
 
 if ($type !== 'nojs') {
     /** @deprecated The "jquery" array will be removed in 2.0 */
-    $t->data['jquery'] = array('core' => true, 'ui' => false, 'css' => false);
+    $t->data['jquery'] = ['core' => true, 'ui' => false, 'css' => false];
 }
 
 $t->show();
diff --git a/modules/core/www/idp/resumelogout.php b/modules/core/www/idp/resumelogout.php
index 199dad3b6f33515cf24ea1c944d89bfa1eb9b252..3e84b3a4e2a8b78c001ef8db9b810dc221e556c5 100644
--- a/modules/core/www/idp/resumelogout.php
+++ b/modules/core/www/idp/resumelogout.php
@@ -1,10 +1,10 @@
 <?php
 
 if (!isset($_REQUEST['id'])) {
-    throw new SimpleSAML_Error_BadRequest('Missing id-parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing id-parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['id'], 'core:Logout:afterbridge');
-$idp = SimpleSAML_IdP::getByState($state);
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['id'], 'core:Logout:afterbridge');
+$idp = \SimpleSAML\IdP::getByState($state);
 
 $assocId = $state['core:TerminatedAssocId'];
 
diff --git a/modules/core/www/login-admin.php b/modules/core/www/login-admin.php
index 22bc7854aed50348332d85f3cc0aabd8cb9a7ff8..59246f6731c6db0c7cbc2bff6dba5f1e5a4e065e 100644
--- a/modules/core/www/login-admin.php
+++ b/modules/core/www/login-admin.php
@@ -1,13 +1,12 @@
 <?php
+
 /*
  * Helper page for starting a admin login. Can be used as a target for links.
  */
 
 if (!array_key_exists('ReturnTo', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing ReturnTo parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing ReturnTo parameter.');
 }
 
-SimpleSAML\Utils\Auth::requireAdmin();
-
+\SimpleSAML\Utils\Auth::requireAdmin();
 \SimpleSAML\Utils\HTTP::redirectUntrustedURL($_REQUEST['ReturnTo']);
-
diff --git a/modules/core/www/login.php b/modules/core/www/login.php
new file mode 100644
index 0000000000000000000000000000000000000000..53d57ca44976bbc805c2df889255182449eabe98
--- /dev/null
+++ b/modules/core/www/login.php
@@ -0,0 +1,63 @@
+<?php
+
+$config = \SimpleSAML\Configuration::getInstance();
+$sources = \SimpleSAML\Configuration::getOptionalConfig('authsources.php')->toArray();
+
+//delete admin
+if (isset($sources['admin'])) {
+    unset($sources['admin']);
+}
+
+//if only 1 auth
+if (count($sources) == 1) {
+    $_REQUEST['as'] = key($sources);
+}
+
+if (!array_key_exists('as', $_REQUEST)) {
+    $t = new \SimpleSAML\XHTML\Template($config, 'core:login.twig');
+
+    $t->data['loginurl'] = \SimpleSAML\Utils\Auth::getAdminLoginURL();
+    $t->data['sources'] = $sources;
+    $t->show();
+    exit();
+}
+
+$asId = (string) $_REQUEST['as'];
+$as = new \SimpleSAML\Auth\Simple($asId);
+
+if (array_key_exists('logout', $_REQUEST)) {
+    $as->logout($config->getBasePath().'logout.php');
+}
+
+if (array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_PARAM, $_REQUEST)) {
+    // This is just a simple example of an error
+
+    $state = \SimpleSAML\Auth\State::loadExceptionState();
+    assert(array_key_exists(\SimpleSAML\Auth\State::EXCEPTION_DATA, $state));
+    $e = $state[\SimpleSAML\Auth\State::EXCEPTION_DATA];
+
+    throw $e;
+}
+
+if (!$as->isAuthenticated()) {
+    $url = \SimpleSAML\Module::getModuleURL('core/login.php', ['as' => $asId]);
+    $params = [
+        'ErrorURL' => $url,
+        'ReturnTo' => $url,
+    ];
+    $as->login($params);
+}
+
+$attributes = $as->getAttributes();
+$session = \SimpleSAML\Session::getSessionFromRequest();
+
+$t = new \SimpleSAML\XHTML\Template($config, 'auth_status.twig', 'attributes');
+
+
+$t->data['header'] = '{status:header_saml20_sp}';
+$t->data['attributes'] = $attributes;
+$t->data['nameid'] = !is_null($as->getAuthData('saml:sp:NameID')) ? $as->getAuthData('saml:sp:NameID') : false;
+$t->data['logouturl'] = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery().'?as='.urlencode($asId).'&logout';
+$t->data['remaining'] = $session->getAuthData($asId, 'Expire') - time();
+
+$t->show();
diff --git a/modules/core/www/loginuserpass.php b/modules/core/www/loginuserpass.php
index 78ba32a0a384f38983bbb6bc25c495794f2fbe08..747506f898d1e969212cd17a2c5acca85e6ffcd9 100644
--- a/modules/core/www/loginuserpass.php
+++ b/modules/core/www/loginuserpass.php
@@ -2,7 +2,7 @@
 
 /**
  * This page shows a username/password login form, and passes information from it
- * to the sspmod_core_Auth_UserPassBase class, which is a generic class for
+ * to the \SimpleSAML\Module\core\Auth\UserPassBase class, which is a generic class for
  * username/password authentication.
  *
  * @author Olav Morken, UNINETT AS.
@@ -11,97 +11,126 @@
 
 // Retrieve the authentication state
 if (!array_key_exists('AuthState', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthState parameter.');
 }
 $authStateId = $_REQUEST['AuthState'];
-$state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassBase::STAGEID);
+$state = \SimpleSAML\Auth\State::loadState($authStateId, \SimpleSAML\Module\core\Auth\UserPassBase::STAGEID);
 
-$source = SimpleSAML_Auth_Source::getById($state[sspmod_core_Auth_UserPassBase::AUTHID]);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $state[sspmod_core_Auth_UserPassBase::AUTHID]);
+$source = \SimpleSAML\Auth\Source::getById($state[\SimpleSAML\Module\core\Auth\UserPassBase::AUTHID]);
+if ($source === null) {
+    throw new \Exception(
+        'Could not find authentication source with id '.$state[\SimpleSAML\Module\core\Auth\UserPassBase::AUTHID]
+    );
 }
 
 
 if (array_key_exists('username', $_REQUEST)) {
-	$username = $_REQUEST['username'];
-} elseif ($source->getRememberUsernameEnabled() && array_key_exists($source->getAuthId() . '-username', $_COOKIE)) {
-	$username = $_COOKIE[$source->getAuthId() . '-username'];
+    $username = $_REQUEST['username'];
+} elseif ($source->getRememberUsernameEnabled() && array_key_exists($source->getAuthId().'-username', $_COOKIE)) {
+    $username = $_COOKIE[$source->getAuthId().'-username'];
 } elseif (isset($state['core:username'])) {
-	$username = (string)$state['core:username'];
+    $username = (string) $state['core:username'];
 } else {
-	$username = '';
+    $username = '';
 }
 
 if (array_key_exists('password', $_REQUEST)) {
-	$password = $_REQUEST['password'];
+    $password = $_REQUEST['password'];
 } else {
-	$password = '';
+    $password = '';
 }
 
-$errorCode = NULL;
-$errorParams = NULL;
+$errorCode = null;
+$errorParams = null;
+$queryParams = [];
+
+if (isset($state['error'])) {
+    $errorCode = $state['error']['code'];
+    $errorParams = $state['error']['params'];
+    $queryParams = ['AuthState' => $authStateId];
+}
 
 if (!empty($_REQUEST['username']) || !empty($password)) {
-	// Either username or password set - attempt to log in
+    // Either username or password set - attempt to log in
 
-	if (array_key_exists('forcedUsername', $state)) {
-		$username = $state['forcedUsername'];
-	}
+    if (array_key_exists('forcedUsername', $state)) {
+        $username = $state['forcedUsername'];
+    }
 
-	if ($source->getRememberUsernameEnabled()) {
-		$sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
-		$params = $sessionHandler->getCookieParams();
-		$params['expire'] = time();
-		$params['expire'] += (isset($_REQUEST['remember_username']) && $_REQUEST['remember_username'] == 'Yes' ? 31536000 : -300);
-        \SimpleSAML\Utils\HTTP::setCookie($source->getAuthId() . '-username', $username, $params, FALSE);
-	}
+    if ($source->getRememberUsernameEnabled()) {
+        $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+        $params = $sessionHandler->getCookieParams();
+        
+        if (isset($_REQUEST['remember_username']) && $_REQUEST['remember_username'] == 'Yes') {
+            $params['expire'] = time() + 31536000;
+        } else {
+            $params['expire'] = time() - 300;
+        }
+        \SimpleSAML\Utils\HTTP::setCookie($source->getAuthId().'-username', $username, $params, false);
+    }
 
     if ($source->isRememberMeEnabled()) {
         if (array_key_exists('remember_me', $_REQUEST) && $_REQUEST['remember_me'] === 'Yes') {
-            $state['RememberMe'] = TRUE;
-            $authStateId = SimpleSAML_Auth_State::saveState($state, sspmod_core_Auth_UserPassBase::STAGEID);
+            $state['RememberMe'] = true;
+            $authStateId = \SimpleSAML\Auth\State::saveState(
+                $state,
+                \SimpleSAML\Module\core\Auth\UserPassBase::STAGEID
+            );
         }
     }
 
-	try {
-		sspmod_core_Auth_UserPassBase::handleLogin($authStateId, $username, $password);
-	} catch (SimpleSAML_Error_Error $e) {
-		/* Login failed. Extract error code and parameters, to display the error. */
-		$errorCode = $e->getErrorCode();
-		$errorParams = $e->getParameters();
-	}
+    try {
+        \SimpleSAML\Module\core\Auth\UserPassBase::handleLogin($authStateId, $username, $password);
+    } catch (\SimpleSAML\Error\Error $e) {
+        // Login failed. Extract error code and parameters, to display the error
+        $errorCode = $e->getErrorCode();
+        $errorParams = $e->getParameters();
+        $state['error'] = [
+            'code' => $errorCode,
+            'params' => $errorParams
+        ];
+        $authStateId = \SimpleSAML\Auth\State::saveState($state, \SimpleSAML\Module\core\Auth\UserPassBase::STAGEID);
+        $queryParams = ['AuthState' => $authStateId];
+    }
+    if (isset($state['error'])) {
+        unset($state['error']);
+    }
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'core:loginuserpass.php');
-$t->data['stateparams'] = array('AuthState' => $authStateId);
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:loginuserpass.php');
+$t->data['stateparams'] = ['AuthState' => $authStateId];
 if (array_key_exists('forcedUsername', $state)) {
-	$t->data['username'] = $state['forcedUsername'];
-	$t->data['forceUsername'] = TRUE;
-	$t->data['rememberUsernameEnabled'] = FALSE;
-	$t->data['rememberUsernameChecked'] = FALSE;
+    $t->data['username'] = $state['forcedUsername'];
+    $t->data['forceUsername'] = true;
+    $t->data['rememberUsernameEnabled'] = false;
+    $t->data['rememberUsernameChecked'] = false;
     $t->data['rememberMeEnabled'] = $source->isRememberMeEnabled();
     $t->data['rememberMeChecked'] = $source->isRememberMeChecked();
 } else {
-	$t->data['username'] = $username;
-	$t->data['forceUsername'] = FALSE;
-	$t->data['rememberUsernameEnabled'] = $source->getRememberUsernameEnabled();
-	$t->data['rememberUsernameChecked'] = $source->getRememberUsernameChecked();
+    $t->data['username'] = $username;
+    $t->data['forceUsername'] = false;
+    $t->data['rememberUsernameEnabled'] = $source->getRememberUsernameEnabled();
+    $t->data['rememberUsernameChecked'] = $source->getRememberUsernameChecked();
     $t->data['rememberMeEnabled'] = $source->isRememberMeEnabled();
     $t->data['rememberMeChecked'] = $source->isRememberMeChecked();
-	if (isset($_COOKIE[$source->getAuthId() . '-username'])) $t->data['rememberUsernameChecked'] = TRUE;
+    if (isset($_COOKIE[$source->getAuthId().'-username'])) {
+        $t->data['rememberUsernameChecked'] = true;
+    }
 }
 $t->data['links'] = $source->getLoginLinks();
 $t->data['errorcode'] = $errorCode;
 $t->data['errorcodes'] = SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
 $t->data['errorparams'] = $errorParams;
+if (!empty($queryParams)) {
+    $t->data['queryParams'] = $queryParams;
+}
 
 if (isset($state['SPMetadata'])) {
-	$t->data['SPMetadata'] = $state['SPMetadata'];
+    $t->data['SPMetadata'] = $state['SPMetadata'];
 } else {
-	$t->data['SPMetadata'] = NULL;
+    $t->data['SPMetadata'] = null;
 }
 
 $t->show();
 exit();
-
diff --git a/modules/core/www/loginuserpassorg.php b/modules/core/www/loginuserpassorg.php
index 81deccf83583f8a0883a231d884ce29fb3a14288..2b9ec4dba32a09252629180f31d82f4ce349c30d 100644
--- a/modules/core/www/loginuserpassorg.php
+++ b/modules/core/www/loginuserpassorg.php
@@ -2,7 +2,7 @@
 
 /**
  * This page shows a username/password/organization login form, and passes information from
- * itto the sspmod_core_Auth_UserPassBase class, which is a generic class for
+ * into the \SimpleSAML\Module\core\Auth\UserPassBase class, which is a generic class for
  * username/password/organization authentication.
  *
  * @author Olav Morken, UNINETT AS.
@@ -11,90 +11,153 @@
 
 // Retrieve the authentication state
 if (!array_key_exists('AuthState', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthState parameter.');
 }
 $authStateId = $_REQUEST['AuthState'];
-$state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_core_Auth_UserPassOrgBase::STAGEID);
+$state = \SimpleSAML\Auth\State::loadState($authStateId, \SimpleSAML\Module\core\Auth\UserPassOrgBase::STAGEID);
 
-$source = SimpleSAML_Auth_Source::getById($state[sspmod_core_Auth_UserPassOrgBase::AUTHID]);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $state[sspmod_core_Auth_UserPassOrgBase::AUTHID]);
+$source = \SimpleSAML\Auth\Source::getById($state[\SimpleSAML\Module\core\Auth\UserPassOrgBase::AUTHID]);
+if ($source === null) {
+    throw new \Exception(
+        'Could not find authentication source with id '.$state[\SimpleSAML\Module\core\Auth\UserPassOrgBase::AUTHID]
+    );
 }
 
-$organizations = sspmod_core_Auth_UserPassOrgBase::listOrganizations($authStateId);
+$organizations = \SimpleSAML\Module\core\Auth\UserPassOrgBase::listOrganizations($authStateId);
 
 if (array_key_exists('username', $_REQUEST)) {
-	$username = $_REQUEST['username'];
-} elseif ($source->getRememberUsernameEnabled() && array_key_exists($source->getAuthId() . '-username', $_COOKIE)) {
-	$username = $_COOKIE[$source->getAuthId() . '-username'];
+    $username = $_REQUEST['username'];
+} elseif ($source->getRememberUsernameEnabled() && array_key_exists($source->getAuthId().'-username', $_COOKIE)) {
+    $username = $_COOKIE[$source->getAuthId().'-username'];
 } elseif (isset($state['core:username'])) {
-	$username = (string)$state['core:username'];
+    $username = (string) $state['core:username'];
 } else {
-	$username = '';
+    $username = '';
 }
 
 if (array_key_exists('password', $_REQUEST)) {
-	$password = $_REQUEST['password'];
+    $password = $_REQUEST['password'];
 } else {
-	$password = '';
+    $password = '';
 }
 
 if (array_key_exists('organization', $_REQUEST)) {
-	$organization = $_REQUEST['organization'];
+    $organization = $_REQUEST['organization'];
+} elseif ($source->getRememberOrganizationEnabled() &&
+    array_key_exists($source->getAuthId().'-organization', $_COOKIE)
+  ) {
+    $organization = $_COOKIE[$source->getAuthId().'-organization'];
 } elseif (isset($state['core:organization'])) {
-	$organization = (string)$state['core:organization'];
+    $organization = (string) $state['core:organization'];
 } else {
-	$organization = '';
+    $organization = '';
 }
 
-$errorCode = NULL;
-$errorParams = NULL;
-if ($organizations === NULL || !empty($organization)) {
-	if (!empty($username) && !empty($password)) {
-
-		if ($source->getRememberUsernameEnabled()) {
-			$sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
-			$params = $sessionHandler->getCookieParams();
-			$params['expire'] = time();
-			$params['expire'] += (isset($_REQUEST['remember_username']) && $_REQUEST['remember_username'] == 'Yes' ? 31536000 : -300);
-            \SimpleSAML\Utils\HTTP::setCookie($source->getAuthId() . '-username', $username, $params, FALSE);
-		}
-
-		try {
-			sspmod_core_Auth_UserPassOrgBase::handleLogin($authStateId, $username, $password, $organization);
-		} catch (SimpleSAML_Error_Error $e) {
-			// Login failed. Extract error code and parameters, to display the error
-			$errorCode = $e->getErrorCode();
-			$errorParams = $e->getParameters();
-		}
-	}
+$errorCode = null;
+$errorParams = null;
+$queryParams = [];
+
+if (isset($state['error'])) {
+    $errorCode = $state['error']['code'];
+    $errorParams = $state['error']['params'];
+    $queryParams = ['AuthState' => $authStateId];
+}
+
+if ($organizations === null || !empty($organization)) {
+    if (!empty($username) || !empty($password)) {
+        if ($source->getRememberUsernameEnabled()) {
+            $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+            $params = $sessionHandler->getCookieParams();
+            if (isset($_REQUEST['remember_username']) && $_REQUEST['remember_username'] == 'Yes') {
+                $params['expire'] = time() + 3153600;
+            } else {
+                $params['expire'] = time() - 300;
+            }
+
+            \SimpleSAML\Utils\HTTP::setCookie($source->getAuthId().'-username', $username, $params, false);
+        }
+
+        if ($source->getRememberOrganizationEnabled()) {
+            $sessionHandler = \SimpleSAML\SessionHandler::getSessionHandler();
+            $params = $sessionHandler->getCookieParams();
+            if (isset($_REQUEST['remember_organization']) && $_REQUEST['remember_organization'] == 'Yes') {
+                $params['expire'] = time() + 3153600;
+            } else {
+                $params['expire'] = time() - 300;
+            }
+            setcookie(
+                $source->getAuthId().'-organization',
+                $organization,
+                $params['expire'],
+                $params['path'],
+                $params['domain'],
+                $params['secure'],
+                $params['httponly']
+            );
+        }
+
+        try {
+            \SimpleSAML\Module\core\Auth\UserPassOrgBase::handleLogin(
+                $authStateId,
+                $username,
+                $password,
+                $organization
+            );
+        } catch (\SimpleSAML\Error\Error $e) {
+            // Login failed. Extract error code and parameters, to display the error
+            $errorCode = $e->getErrorCode();
+            $errorParams = $e->getParameters();
+            $state['error'] = [
+                'code' => $errorCode,
+                'params' => $errorParams
+            ];
+            $authStateId = \SimpleSAML\Auth\State::saveState(
+                $state,
+                \SimpleSAML\Module\core\Auth\UserPassOrgBase::STAGEID
+            );
+            $queryParams = ['AuthState' => $authStateId];
+        }
+        if (isset($state['error'])) {
+            unset($state['error']);
+        }
+    }
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'core:loginuserpass.php');
-$t->data['stateparams'] = array('AuthState' => $authStateId);
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:loginuserpass.php');
+$t->data['stateparams'] = ['AuthState' => $authStateId];
 $t->data['username'] = $username;
-$t->data['forceUsername'] = FALSE;
+$t->data['forceUsername'] = false;
 $t->data['rememberUsernameEnabled'] = $source->getRememberUsernameEnabled();
 $t->data['rememberUsernameChecked'] = $source->getRememberUsernameChecked();
 $t->data['rememberMeEnabled'] = false;
 $t->data['rememberMeChecked'] = false;
-if (isset($_COOKIE[$source->getAuthId() . '-username'])) $t->data['rememberUsernameChecked'] = TRUE;
+if (isset($_COOKIE[$source->getAuthId().'-username'])) {
+    $t->data['rememberUsernameChecked'] = true;
+}
+$t->data['rememberOrganizationEnabled'] = $source->getRememberOrganizationEnabled();
+$t->data['rememberOrganizationChecked'] = $source->getRememberOrganizationChecked();
+if (isset($_COOKIE[$source->getAuthId().'-organization'])) {
+    $t->data['rememberOrganizationChecked'] = true;
+}
 $t->data['errorcode'] = $errorCode;
-$t->data['errorcodes'] = SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
+$t->data['errorcodes'] = \SimpleSAML\Error\ErrorCodes::getAllErrorCodeMessages();
 $t->data['errorparams'] = $errorParams;
 
-if ($organizations !== NULL) {
-	$t->data['selectedOrg'] = $organization;
-	$t->data['organizations'] = $organizations;
+if (!empty($queryParams)) {
+    $t->data['queryParams'] = $queryParams;
+}
+
+if ($organizations !== null) {
+    $t->data['selectedOrg'] = $organization;
+    $t->data['organizations'] = $organizations;
 }
 
 if (isset($state['SPMetadata'])) {
-	$t->data['SPMetadata'] = $state['SPMetadata'];
+    $t->data['SPMetadata'] = $state['SPMetadata'];
 } else {
-	$t->data['SPMetadata'] = NULL;
+    $t->data['SPMetadata'] = null;
 }
 
 $t->show();
 exit();
-
diff --git a/modules/core/www/no_cookie.php b/modules/core/www/no_cookie.php
index 46e67a579909bcb345a2fa752752912fc3b43dff..3575d85f6b4b3cc3e623baa4c457c7dff2cd7de7 100644
--- a/modules/core/www/no_cookie.php
+++ b/modules/core/www/no_cookie.php
@@ -7,7 +7,12 @@ if (isset($_REQUEST['retryURL'])) {
     $retryURL = null;
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'core:no_cookie.tpl.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:no_cookie.tpl.php');
+$translator = $t->getTranslator();
+
+$t->data['header'] = htmlspecialchars($translator->t('{core:no_cookie:header}'));
+$t->data['description'] = htmlspecialchars($translator->t('{core:no_cookie:description}'));
+$t->data['retry'] = htmlspecialchars($translator->t('{core:no_cookie:retry}'));
 $t->data['retryURL'] = $retryURL;
 $t->show();
diff --git a/modules/core/www/postredirect.php b/modules/core/www/postredirect.php
index 2f3cb131c4f5bb3afc05f2279d84425d7623051c..a748eea8272995f9056235fcf906d565bdfbadd7 100644
--- a/modules/core/www/postredirect.php
+++ b/modules/core/www/postredirect.php
@@ -7,35 +7,35 @@
  */
 
 if (array_key_exists('RedirId', $_REQUEST)) {
-	$postId = $_REQUEST['RedirId'];
-	$session = SimpleSAML_Session::getSessionFromRequest();
+    $postId = $_REQUEST['RedirId'];
+    $session = \SimpleSAML\Session::getSessionFromRequest();
 } elseif (array_key_exists('RedirInfo', $_REQUEST)) {
-	$encData = base64_decode($_REQUEST['RedirInfo']);
+    $encData = base64_decode($_REQUEST['RedirInfo']);
 
-	if (empty($encData)) {
-		throw new SimpleSAML_Error_BadRequest('Invalid RedirInfo data.');
-	}
+    if (empty($encData)) {
+        throw new \SimpleSAML\Error\BadRequest('Invalid RedirInfo data.');
+    }
 
-	list($sessionId, $postId) = explode(':', SimpleSAML\Utils\Crypto::aesDecrypt($encData));
+    list($sessionId, $postId) = explode(':', \SimpleSAML\Utils\Crypto::aesDecrypt($encData));
 
-	if (empty($sessionId) || empty($postId)) {
-		throw new SimpleSAML_Error_BadRequest('Invalid session info data.');
-	}
+    if (empty($sessionId) || empty($postId)) {
+        throw new \SimpleSAML\Error\BadRequest('Invalid session info data.');
+    }
 
-	$session = SimpleSAML_Session::getSession($sessionId);
+    $session = \SimpleSAML\Session::getSession($sessionId);
 } else {
-	throw new SimpleSAML_Error_BadRequest('Missing redirection info parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing redirection info parameter.');
 }
 
-if ($session === NULL) {
-	throw new Exception('Unable to load session.');
+if ($session === null) {
+    throw new Exception('Unable to load session.');
 }
 
 $postData = $session->getData('core_postdatalink', $postId);
 
-if ($postData === NULL) {
-	// The post data is missing, probably because it timed out
-	throw new Exception('The POST data we should restore was lost.');
+if ($postData === null) {
+    // The post data is missing, probably because it timed out
+    throw new Exception('The POST data we should restore was lost.');
 }
 
 $session->deleteData('core_postdatalink', $postId);
@@ -44,8 +44,8 @@ assert(is_array($postData));
 assert(array_key_exists('url', $postData));
 assert(array_key_exists('post', $postData));
 
-$config = SimpleSAML_Configuration::getInstance();
-$template = new SimpleSAML_XHTML_Template($config, 'post.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$template = new \SimpleSAML\XHTML\Template($config, 'post.php');
 $template->data['destination'] = $postData['url'];
 $template->data['post'] = $postData['post'];
 $template->show();
diff --git a/modules/core/www/short_sso_interval.php b/modules/core/www/short_sso_interval.php
index 0690b1b4f581c3d40e217a24d6a5d25871aa50fa..5a937c66c15c4f48a85d0d107dceeb81edabdbfa 100644
--- a/modules/core/www/short_sso_interval.php
+++ b/modules/core/www/short_sso_interval.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Show a warning to an user about the SP requesting SSO a short time after
  * doing it previously.
@@ -7,20 +8,22 @@
  */
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'core:short_sso_interval');
-$session = SimpleSAML_Session::getSessionFromRequest();
+$state = \SimpleSAML\Auth\State::loadState($id, 'core:short_sso_interval');
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 if (array_key_exists('continue', $_REQUEST)) {
-	// The user has pressed the continue/retry-button
-	SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+    // The user has pressed the continue/retry-button
+    \SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'core:short_sso_interval.php');
-$t->data['target'] = SimpleSAML\Module::getModuleURL('core/short_sso_interval.php');
-$t->data['params'] = array('StateId' => $id);
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'core:short_sso_interval.php');
+$t->data['target'] = \SimpleSAML\Module::getModuleURL('core/short_sso_interval.php');
+$t->data['params'] = ['StateId' => $id];
 $t->data['trackId'] = $session->getTrackID();
+$this->data['header'] = $this->t('{core:short_sso_interval:warning_header}');
+$this->data['autofocus'] = 'contbutton';
 $t->show();
diff --git a/modules/core/www/show_metadata.php b/modules/core/www/show_metadata.php
index fd03d9f56a6ec113770db3b6aa16f426e5815934..e8f3bf223e91b45cad24bda780d99983a0e9ef75 100644
--- a/modules/core/www/show_metadata.php
+++ b/modules/core/www/show_metadata.php
@@ -1,10 +1,10 @@
 <?php
 
 // load configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
-SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
 if (!array_key_exists('entityid', $_REQUEST)) {
     throw new Exception('required parameter [entityid] missing');
@@ -14,21 +14,24 @@ if (!array_key_exists('set', $_REQUEST)) {
 }
 if (!in_array(
     $_REQUEST['set'],
-    array('saml20-idp-remote', 'saml20-sp-remote', 'shib13-idp-remote', 'shib13-sp-remote'),
+    ['saml20-idp-remote', 'saml20-sp-remote', 'shib13-idp-remote', 'shib13-sp-remote'],
     true
 )) {
     throw new Exception('Invalid set');
 }
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
-$m = $metadata->getMetadata($_REQUEST['entityid'], $_REQUEST['set']);
+$m = $metadata->getMetaData($_REQUEST['entityid'], $_REQUEST['set']);
 
-$t = new SimpleSAML_XHTML_Template($config, 'core:show_metadata.tpl.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'core:show_metadata.tpl.php');
 $t->data['clipboard.js'] = true;
 $t->data['pageid'] = 'show_metadata';
 $t->data['header'] = 'SimpleSAMLphp Show Metadata';
-$t->data['backlink'] = SimpleSAML\Module::getModuleURL('core/frontpage_federation.php');
+$t->data['backlink'] = \SimpleSAML\Module::getModuleURL('core/frontpage_federation.php');
 $t->data['m'] = $m;
+$t->data['entityid'] = $m['metadata-index'];
+unset($m['metadata-index']);
+$t->data['metadata'] = var_export($m, true);
 
 $t->show();
diff --git a/modules/cron/bin/cron.php b/modules/cron/bin/cron.php
index 073c278cbea20179f238d99e5477a11acf568ce8..61e690e0fd05f42be515dd2f5ff4cc208e6829ed 100755
--- a/modules/cron/bin/cron.php
+++ b/modules/cron/bin/cron.php
@@ -11,12 +11,12 @@
 $baseDir = dirname(dirname(dirname(dirname(__FILE__))));
 
 // Add library autoloader.
-require_once($baseDir . '/lib/_autoload.php');
+require_once($baseDir.'/lib/_autoload.php');
 
 if (!SimpleSAML\Module::isModuleEnabled('cron')) {
-    echo("You need to enable the cron module before this script can be used.\n");
-    echo("You can enable it by running the following command:\n");
-    echo('  echo >"' . $baseDir . '/modules/cron/enable' . "\"\n");
+    echo "You need to enable the cron module before this script can be used.\n";
+    echo "You can enable it by running the following command:\n";
+    echo '  echo >"'.$baseDir.'/modules/cron/enable'."\"\n";
     exit(1);
 }
 
diff --git a/modules/cron/config-templates/module_cron.php b/modules/cron/config-templates/module_cron.php
index 32d5c28e7b6339f5b7b2f7f5c0647c5a64187d61..29a35d9e9c535cb80e19c1fea2aea89e6ec7ae9f 100644
--- a/modules/cron/config-templates/module_cron.php
+++ b/modules/cron/config-templates/module_cron.php
@@ -1,13 +1,11 @@
 <?php
-/* 
+/*
  * Configuration for the Cron module.
  */
 
-$config = array (
-
-	'key' => 'secret',
-	'allowed_tags' => array('daily', 'hourly', 'frequent'),
-	'debug_message' => TRUE,
-	'sendemail' => TRUE,
-
-);
+$config = [
+    'key' => 'secret',
+    'allowed_tags' => ['daily', 'hourly', 'frequent'],
+    'debug_message' => true,
+    'sendemail' => true,
+];
diff --git a/modules/cron/hooks/hook_cron.php b/modules/cron/hooks/hook_cron.php
index ba175b4eb2ebb4c6224309fff310007a7556ad4c..61812906a2e8fee62ba13e042314d827ca36f39d 100644
--- a/modules/cron/hooks/hook_cron.php
+++ b/modules/cron/hooks/hook_cron.php
@@ -4,16 +4,16 @@
  *
  * @param array &$croninfo  Output
  */
-function cron_hook_cron(&$croninfo) {
-	assert(is_array($croninfo));
-	assert(array_key_exists('summary', $croninfo));
-	assert(array_key_exists('tag', $croninfo));
 
-	$cronconfig = SimpleSAML_Configuration::getConfig('module_cron.php');
-	
-	if ($cronconfig->getValue('debug_message', TRUE)) {
+function cron_hook_cron(&$croninfo)
+{
+    assert(is_array($croninfo));
+    assert(array_key_exists('summary', $croninfo));
+    assert(array_key_exists('tag', $croninfo));
 
-		$croninfo['summary'][] = 'Cron did run tag [' . $croninfo['tag'] . '] at ' . date(DATE_RFC822);
-	}
+    $cronconfig = \SimpleSAML\Configuration::getConfig('module_cron.php');
 
+    if ($cronconfig->getValue('debug_message', true)) {
+        $croninfo['summary'][] = 'Cron did run tag ['.$croninfo['tag'].'] at '.date(DATE_RFC822);
+    }
 }
diff --git a/modules/cron/hooks/hook_frontpage.php b/modules/cron/hooks/hook_frontpage.php
index d4d11edd09aae31994ff2563db64c595df60323b..c9e2eb2dcb25e88141556375de42d44841a32a35 100644
--- a/modules/cron/hooks/hook_frontpage.php
+++ b/modules/cron/hooks/hook_frontpage.php
@@ -4,13 +4,14 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function cron_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
 
-	$links['config'][] = array(
-		'href' => SimpleSAML\Module::getModuleURL('cron/croninfo.php'),
-		'text' => array('en' => 'Cron module information page'),
-	);
+function cron_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
 
+    $links['config'][] = [
+        'href' => SimpleSAML\Module::getModuleURL('cron/croninfo.php'),
+        'text' => '{core:frontpage:link_cron}',
+    ];
 }
diff --git a/modules/cron/lib/Cron.php b/modules/cron/lib/Cron.php
index bba782afaca5d768b123c5667fa6d9577600aa95..f8bda653b8b23b4dc6061668160c453e8044ba13 100644
--- a/modules/cron/lib/Cron.php
+++ b/modules/cron/lib/Cron.php
@@ -9,18 +9,18 @@ class Cron
 {
     /**
      * The configuration for the Cron module
-     * @var \SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $cronconfig;
 
     /*
-     * @param \SimpleSAML_Configuration $cronconfig The cron configuration to use. If not specified defaults
+     * @param \SimpleSAML\Configuration $cronconfig The cron configuration to use. If not specified defaults
      * to `config/module_cron.php`
      */
-    public function __construct(\SimpleSAML_Configuration $cronconfig = null)
+    public function __construct(\SimpleSAML\Configuration $cronconfig = null)
     {
         if ($cronconfig == null) {
-            $cronconfig = \SimpleSAML_Configuration::getConfig('module_cron.php');
+            $cronconfig = \SimpleSAML\Configuration::getConfig('module_cron.php');
         }
         $this->cronconfig = $cronconfig;
     }
@@ -38,16 +38,16 @@ class Cron
             throw new \Exception("Invalid cron tag '$tag''");
         }
 
-        $summary = array();
-        $croninfo = array(
+        $summary = [];
+        $croninfo = [
             'summary' => &$summary,
             'tag' => $tag,
-        );
+        ];
 
         \SimpleSAML\Module::callHooks('cron', $croninfo);
 
         foreach ($summary as $s) {
-            \SimpleSAML\Logger::debug('Cron - Summary: ' . $s);
+            \SimpleSAML\Logger::debug('Cron - Summary: '.$s);
         }
 
         return $croninfo;
diff --git a/modules/cron/templates/croninfo-result.php b/modules/cron/templates/croninfo-result.php
index 489cd5d51f383eb93401d88e2e8b9d9240bfa20f..e4f0dc1695a06d856d5eba5a01732e0810641ca2 100644
--- a/modules/cron/templates/croninfo-result.php
+++ b/modules/cron/templates/croninfo-result.php
@@ -3,16 +3,16 @@
 $this->data['header'] = $this->t('cron_header');
 $this->includeAtTemplateBase('includes/header.php');
 ?>
-		<p><?php echo $this->t('cron_result_title') ?></p>
-		<pre style="color: #444; padding: 1em; border: 1px solid #eee; margin: .4em "><code>
-		<?php
-			echo '<h1>' .$this->t('cron_report_title'). '</h1><p>' .$this->t('ran_text'). ' ' .$this->data['time'] . '</p>' .
-				'<p>URL: <tt>' . $this->data['url'] . '</tt></p>' .
-				'<p>Tag: ' . $this->data['tag'] . "</p>\n\n" .
-				'<ul><li>' . join('</li><li>', $this->data['summary']) . '</li></ul>';
-		?>
-		</code>
-		</pre>
+        <p><?php echo $this->t('cron_result_title') ?></p>
+        <pre style="color: #444; padding: 1em; border: 1px solid #eee; margin: .4em "><code>
+<?php
+
+echo '            <h1>'.$this->t('cron_report_title').'</h1><p>'.$this->t('ran_text').
+    ' '.$this->data['time'].'</p>'.'<p>URL: <code>'.$this->data['url'].'</code></p>'.
+    '<p>Tag: '.$this->data['tag']."</p>\n\n".
+    '<ul><li>'.join('</li><li>', $this->data['summary']).'</li></ul>';
+?>
+        </code></pre>
 </div>
 
 <?php
diff --git a/modules/cron/templates/croninfo-result.twig b/modules/cron/templates/croninfo-result.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f226ffe07e9c24c14680f98223b10bb0b5ce7ef2
--- /dev/null
+++ b/modules/cron/templates/croninfo-result.twig
@@ -0,0 +1,30 @@
+{% set pagetitle = 'Cron result page'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+
+<p>
+{{ 'Here are the result for the cron job execution:'|trans }}
+</p>
+
+<div class="code-box code-box-content">
+<h2>{{ 'Cron report'|trans }}</h2>
+
+<code>
+{{ 'Cron ran at'|trans }} {{ time }}
+<p>
+URL: {{ url }}
+</p>
+<p>
+Tag: {{ tag }}
+</p>
+<p><ul>
+{% for sum in summary %}
+        <li> {{ sum }}</li>
+{% endfor %}
+</ul><br />
+</p>
+</code>
+
+</div>
+{% endblock %}
diff --git a/modules/cron/templates/croninfo.tpl.php b/modules/cron/templates/croninfo.tpl.php
index 49aa3131e0f90b77260b96f85eb9a73f9e74fc31..50efe15a1ec53e6ef527448cc4b3e72cb5aa13b8 100644
--- a/modules/cron/templates/croninfo.tpl.php
+++ b/modules/cron/templates/croninfo.tpl.php
@@ -6,31 +6,27 @@ $this->includeAtTemplateBase('includes/header.php');
 $run_text = $this->t('run_text');
 ?>
 
-	<p><?php echo $this->t('cron_info') ?></p>
+        <p><?php echo $this->t('cron_info') ?></p>
 
-	<p><?php echo $this->t('cron_suggestion') ?></p>
-	<pre style="font-size: x-small; color: #444; padding: 1em; border: 1px solid #eee; margin: .4em "><code><?php
-		
-		foreach ($this->data['urls'] AS $url ) {
-			echo "# " . $run_text. ' [' .$url['tag']. ']' . "\n";
-			echo "" . $url['int'] . " curl --silent \"" . $url['href'] . "\" > /dev/null 2>&1\n";
-		}
-		
-		?>
-	</code></pre>
-
-	<br><p><?php echo $this->t('cron_execution') ?></p>
-	<ul>
-		<?php
-
-		foreach ($this->data['urls'] AS $url ) {
-			echo '<li><a href="' . $url['href'] . '&amp;output=xhtml">' . $run_text. ' [' .$url['tag']. ']' . '</a></li>';
-		}
-
-		?>
-		
-	</ul>
+        <p><?php echo $this->t('cron_suggestion') ?></p>
+        <pre style="font-size: x-small; color: #444; padding: 1em; border: 1px solid #eee; margin: .4em "><code>
+<?php
+foreach ($this->data['urls'] as $url) {
+    echo "# ".$run_text. ' ['.$url['tag'].']'."\n";
+    echo $url['int']." curl --silent \"".$url['href']."\" > /dev/null 2>&1\n";
+}
+?>
+        </code></pre>
 
+        <br />
+        <p><?php echo $this->t('cron_execution') ?></p>
+        <ul>
+<?php
+foreach ($this->data['urls'] as $url) {
+    echo '        <li><a href="'.$url['href'].'&amp;output=xhtml">'.$run_text.' ['.$url['tag'].']'.'</a></li>';
+}
+?>
+        </ul>
 </div>
 
 <?php
diff --git a/modules/cron/templates/croninfo.twig b/modules/cron/templates/croninfo.twig
new file mode 100644
index 0000000000000000000000000000000000000000..b00b8905b8ab2107cb0c9d1980dc0a7fea539ea4
--- /dev/null
+++ b/modules/cron/templates/croninfo.twig
@@ -0,0 +1,29 @@
+{% set pagetitle = 'Cron result page'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+<link rel="stylesheet" type="text/css" href="{{ baseurlpath }}assets/css/cron.css">
+{% endblock %}
+
+{% block content %}
+    <h2>{{ 'Cron result page'|trans }}</h2>
+    <p>{{ 'Cron is a way to run things regularly on unix systems.'|trans }}<br /><br /></p>
+    <p>{{ 'Here is a suggestion for a crontab file:'|trans }}<br /><br /></p>
+
+    <div class="code-box code-box-content">
+        <code id="cronlist">
+        {% for url in urls %}
+            # {{ 'Run cron:'|trans }} [{{ url.tag }}]<br />
+            {{ url.int }} curl --silent "{{ url.href }}" > /dev/null 2>&amp;1<br />
+        {% endfor %}
+    </code></div><br />
+
+    <p>{{ 'Click here to run the cron jobs:'|trans }}</p>
+      <ul>
+        {% for url in urls %}
+        <li><a href="{{ url.href }}&amp;output=xhtml">{{ 'Run cron:'|trans }} {{ url.tag }}</a></li>
+        {% endfor %}
+      </ul>
+    </p>
+
+{% endblock %}    
diff --git a/modules/cron/www/assets/css/cron.css b/modules/cron/www/assets/css/cron.css
new file mode 100644
index 0000000000000000000000000000000000000000..459178ed6c2c31566f70bc580c763c100a3e3462
--- /dev/null
+++ b/modules/cron/www/assets/css/cron.css
@@ -0,0 +1,3 @@
+code#cronlist {
+    font-size: 0.8vw;
+}
diff --git a/modules/cron/www/cron.php b/modules/cron/www/cron.php
index 4f22fc5df0b111403d9fd6e119264a8d083b04f2..fb930592812ce20bf6370618cdb708677d63cb81 100644
--- a/modules/cron/www/cron.php
+++ b/modules/cron/www/cron.php
@@ -1,52 +1,49 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
-$cronconfig = SimpleSAML_Configuration::getConfig('module_cron.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$cronconfig = \SimpleSAML\Configuration::getConfig('module_cron.php');
 
 if (!is_null($cronconfig->getValue('key'))) {
-	if ($_REQUEST['key'] !== $cronconfig->getValue('key')) {
-		SimpleSAML\Logger::error('Cron - Wrong key provided. Cron will not run.');
-		exit;
-	}
+    if ($_REQUEST['key'] !== $cronconfig->getValue('key')) {
+        \SimpleSAML\Logger::error('Cron - Wrong key provided. Cron will not run.');
+        exit;
+    }
 }
 
-$cron = new SimpleSAML\Module\cron\Cron();
+$cron = new \SimpleSAML\Module\cron\Cron();
 if (!$cron->isValidTag($_REQUEST['tag'])) {
-    SimpleSAML\Logger::error('Cron - Illegal tag [' . $_REQUEST['tag'] . '].');
+    SimpleSAML\Logger::error('Cron - Illegal tag ['.$_REQUEST['tag'].'].');
     exit;
 }
 
-
 $url = \SimpleSAML\Utils\HTTP::getSelfURL();
 $time = date(DATE_RFC822);
 
 $croninfo = $cron->runTag($_REQUEST['tag']);
 $summary = $croninfo['summary'];
 
-if ($cronconfig->getValue('sendemail', TRUE) && count($summary) > 0) {
-
-	$message = '<h1>Cron report</h1><p>Cron ran at ' . $time . '</p>' .
-		'<p>URL: <tt>' . $url . '</tt></p>' .
-		'<p>Tag: ' . $croninfo['tag'] . "</p>\n\n" .
-		'<ul><li>' . join('</li><li>', $summary) . '</li></ul>';
-
-	$toaddress = $config->getString('technicalcontact_email', 'na@example.org');
-	if($toaddress == 'na@example.org') {
-		SimpleSAML\Logger::error('Cron - Could not send email. [technicalcontact_email] not set in config.');
-	} else {
-		// Use $toaddress for both TO and FROM
-		$email = new SimpleSAML_XHTML_EMail($toaddress, 'SimpleSAMLphp cron report', $toaddress);
-		$email->setBody($message);
-		$email->send();
-	}
-	
+if ($cronconfig->getValue('sendemail', true) && count($summary) > 0) {
+    $message = '<h1>Cron report</h1><p>Cron ran at '.$time.'</p>'.
+        '<p>URL: <code>'.$url.'</code></p>'.
+        '<p>Tag: '.$croninfo['tag']."</p>\n\n".
+        '<ul><li>'.join('</li><li>', $summary).'</li></ul>';
+
+    $toaddress = $config->getString('technicalcontact_email', 'na@example.org');
+    if ($toaddress == 'na@example.org') {
+        \SimpleSAML\Logger::error('Cron - Could not send email. [technicalcontact_email] not set in config.');
+    } else {
+        // Use $toaddress for both TO and FROM
+        $email = new \SimpleSAML\XHTML\EMail($toaddress, 'SimpleSAMLphp cron report', $toaddress);
+        $email->setBody($message);
+        $email->send();
+    }
 }
 
 if (isset($_REQUEST['output']) && $_REQUEST['output'] == "xhtml") {
-	$t = new SimpleSAML_XHTML_Template($config, 'cron:croninfo-result.php','cron:cron');
-	$t->data['tag'] = $croninfo['tag'];
-	$t->data['time'] = $time;
-	$t->data['url'] = $url;
-	$t->data['summary'] = $summary;
-	$t->show();
+    $t = new \SimpleSAML\XHTML\Template($config, 'cron:croninfo-result.php', 'cron:cron');
+    $t->data['tag'] = $croninfo['tag'];
+    $t->data['time'] = $time;
+    $t->data['url'] = $url;
+    $t->data['summary'] = $summary;
+    $t->show();
 }
diff --git a/modules/cron/www/croninfo.php b/modules/cron/www/croninfo.php
index 93b7acb5b15bc25898aaab4d587d12fbb05b791e..8a0aac4d52a90de827a0344822163813ce15cfc4 100644
--- a/modules/cron/www/croninfo.php
+++ b/modules/cron/www/croninfo.php
@@ -4,38 +4,36 @@
  * The _include script registers a autoloader for the SimpleSAMLphp libraries. It also
  * initializes the SimpleSAMLphp config class with the correct path.
  */
-require_once('_include.php');
 
+require_once('_include.php');
 
-// Load SimpleSAMLphp, configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration and metadata
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
-SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
-$cronconfig = SimpleSAML_Configuration::getConfig('module_cron.php');
+$cronconfig = \SimpleSAML\Configuration::getConfig('module_cron.php');
 
 $key = $cronconfig->getValue('key', '');
 $tags = $cronconfig->getValue('allowed_tags');
 
-$def = array(
-	'weekly' 	=> "22 0 * * 0",
-	'daily' 	=> "02 0 * * *",
-	'hourly'	=> "01 * * * *",
-	'default' 	=> "XXXXXXXXXX",
-);
-
-$urls = array();
-foreach ($tags AS $tag) {
-	$urls[] = array(
-		'href' => SimpleSAML\Module::getModuleURL('cron/cron.php', array('key' => $key, 'tag' => $tag)),
-		'tag' => $tag,
-		'int' => (array_key_exists($tag, $def) ? $def[$tag] : $def['default']),
-	);
+$def = [
+    'weekly' => "22 0 * * 0",
+    'daily' => "02 0 * * *",
+    'hourly' => "01 * * * *",
+    'default' => "XXXXXXXXXX",
+];
+
+$urls = [];
+foreach ($tags as $tag) {
+    $urls[] = [
+        'href' => \SimpleSAML\Module::getModuleURL('cron/cron.php', ['key' => $key, 'tag' => $tag]),
+        'tag' => $tag,
+        'int' => (array_key_exists($tag, $def) ? $def[$tag] : $def['default']),
+    ];
 }
 
-
-
-$t = new SimpleSAML_XHTML_Template($config, 'cron:croninfo.tpl.php', 'cron:cron');
+$t = new \SimpleSAML\XHTML\Template($config, 'cron:croninfo.tpl.php', 'cron:cron');
 $t->data['urls'] = $urls;
 $t->show();
diff --git a/modules/discopower/config-templates/module_discopower.php b/modules/discopower/config-templates/module_discopower.php
index 5f5507f764e2e522e58b767b68a301dacae476b1..498cadad83962445faa726abed4e8da675561189 100644
--- a/modules/discopower/config-templates/module_discopower.php
+++ b/modules/discopower/config-templates/module_discopower.php
@@ -1,46 +1,45 @@
 <?php
-/* 
+/*
  * Configuration for the DiscoPower module.
  */
 
-$config = array (
+$config = [
+    // Which tab should be set as default. 0 is the first tab
+    'defaulttab' => 0,
 
-	// Which tab should be set as default. 0 is the first tab
-	'defaulttab' => 0,
-	
-	/*
-	 * List a set of tags (Tabs) that should be listed in a specific order.
-	 * All other available tabs will be listed after the ones specified below.
-	 */
-	'taborder' => array('norway'),
-	/*
-	 * the 'tab' parameter allows you to limit the tabs to a specific list. (excluding unlisted tags)
-	 *
-	 * 'tabs' => array('norway', 'finland'),
-	 */
-	 
-	 /**
-	  * If you want to change the scoring algorithm to a more google suggest like one
-	  * (filters by start of words) uncomment this ... 
-	  *
-	  * 'score' => 'suggest', 
-	  */
+    /*
+     * List a set of tags (Tabs) that should be listed in a specific order.
+     * All other available tabs will be listed after the ones specified below.
+     */
+    'taborder' => ['norway'],
 
-	/*
-	 * The domain to use for common domain cookie support.
-	 * This must be a parent domain of the domain hosting the discovery service.
-	 *
-	 * If this is NULL (the default), common domain cookie support will be disabled.
-	 */
-	'cdc.domain' => NULL,
+    /*
+     * the 'tab' parameter allows you to limit the tabs to a specific list. (excluding unlisted tags)
+     *
+     * 'tabs' => array('norway', 'finland'),
+     */
 
-	/*
-	 * The lifetime of the common domain cookie, in seconds.
-	 *
-	 * If this is NULL (the default), the common domain cookie will be deleted when the browser closes.
-	 *
-	 * Example: 'cdc.lifetime' => 180*24*60*60, // 180 days
-	 */
-	'cdc.lifetime' => NULL,
+    /*
+     * If you want to change the scoring algorithm to a more google suggest like one
+     * (filters by start of words) uncomment this ...
+     *
+     * 'score' => 'suggest',
+     */
 
-);
+    /*
+     * The domain to use for common domain cookie support.
+     * This must be a parent domain of the domain hosting the discovery service.
+     *
+     * If this is NULL (the default), common domain cookie support will be disabled.
+     */
+    'cdc.domain' => null,
+
+    /*
+     * The lifetime of the common domain cookie, in seconds.
+     *
+     * If this is NULL (the default), the common domain cookie will be deleted when the browser closes.
+     *
+     * Example: 'cdc.lifetime' => 180*24*60*60, // 180 days
+     */
+    'cdc.lifetime' => null,
+];
diff --git a/modules/discopower/dictionaries/tabs.translation.json b/modules/discopower/dictionaries/tabs.translation.json
index 558d2d572f6b39496373e63d7a2c82965bc581b1..709544a2733baad7e09239c6be3c16c868979c3b 100644
--- a/modules/discopower/dictionaries/tabs.translation.json
+++ b/modules/discopower/dictionaries/tabs.translation.json
@@ -70,7 +70,6 @@
 	},
 	"greece": {
 		"es": "Grecia",
-		"ru": "\u0413\u0440\u0435\u0446\u0438\u044f",
 		"nl": "Griekenland",
 		"gl": "Grecia",
 		"ru": "\u0413\u0440\u0435\u0446\u0438\u044f",
diff --git a/modules/discopower/lib/PowerIdPDisco.php b/modules/discopower/lib/PowerIdPDisco.php
index d7f0e7f6496f6b099247d279ec5658008439dcea..a0955cb32d320448ab03a89f55a7dd0252d8dfee 100644
--- a/modules/discopower/lib/PowerIdPDisco.php
+++ b/modules/discopower/lib/PowerIdPDisco.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Module\discopower;
 
 /**
  * This class implements a generic IdP discovery service, for use in various IdP discovery service pages. This should
@@ -10,14 +11,13 @@
  * @author Andreas Ă…kre Solberg <andreas@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
-{
-
 
+class PowerIdPDisco extends \SimpleSAML\XHTML\IdPDisco
+{
     /**
      * The configuration for this instance.
      *
-     * @var SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     private $discoconfig;
 
@@ -51,7 +51,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
     {
         parent::__construct($metadataSets, $instance);
 
-        $this->discoconfig = SimpleSAML_Configuration::getConfig('module_discopower.php');
+        $this->discoconfig = \SimpleSAML\Configuration::getConfig('module_discopower.php');
 
         $this->cdcDomain = $this->discoconfig->getString('cdc.domain', null);
         if ($this->cdcDomain !== null && $this->cdcDomain[0] !== '.') {
@@ -72,7 +72,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
      */
     protected function log($message)
     {
-        SimpleSAML\Logger::info('PowerIdPDisco.'.$this->instance.': '.$message);
+        \SimpleSAML\Logger::info('PowerIdPDisco.'.$this->instance.': '.$message);
     }
 
 
@@ -110,24 +110,24 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
      */
     protected function idplistStructured($list)
     {
-        $slist = array();
+        $slist = [];
 
         $order = $this->discoconfig->getValue('taborder');
         if (is_array($order)) {
             foreach ($order as $oe) {
-                $slist[$oe] = array();
+                $slist[$oe] = [];
             }
         }
 
         $enableTabs = $this->discoconfig->getValue('tabs', null);
 
         foreach ($list as $key => $val) {
-            $tags = array('misc');
+            $tags = ['misc'];
             if (array_key_exists('tags', $val)) {
                 $tags = $val['tags'];
             }
             foreach ($tags as $tag) {
-                if (!empty($enableTabs) && !in_array($tag, $enableTabs, true)) {
+                if (!empty($enableTabs) && !in_array($tag, $enableTabs)) {
                     continue;
                 }
                 $slist[$tag][$key] = $val;
@@ -135,7 +135,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
         }
 
         foreach ($slist as $tab => $tbslist) {
-            uasort($slist[$tab], array('sspmod_discopower_PowerIdPDisco', 'mcmp'));
+            uasort($slist[$tab], ['\SimpleSAML\Module\discopower\PowerIdPDisco', 'mcmp']);
         }
 
         return $slist;
@@ -153,21 +153,21 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
      */
     private function processFilter($filter, $entry, $default = true)
     {
-        if (in_array($entry['entityid'], $filter['entities.include'], true)) {
+        if (in_array($entry['entityid'], $filter['entities.include'])) {
             return true;
         }
-        if (in_array($entry['entityid'], $filter['entities.exclude'], true)) {
+        if (in_array($entry['entityid'], $filter['entities.exclude'])) {
             return false;
         }
 
         if (array_key_exists('tags', $entry)) {
             foreach ($filter['tags.include'] as $fe) {
-                if (in_array($fe, $entry['tags'], true)) {
+                if (in_array($fe, $entry['tags'])) {
                     return true;
                 }
             }
             foreach ($filter['tags.exclude'] as $fe) {
-                if (in_array($fe, $entry['tags'], true)) {
+                if (in_array($fe, $entry['tags'])) {
                     return false;
                 }
             }
@@ -190,7 +190,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
 
         try {
             $spmd = $this->metadata->getMetaData($this->spEntityId, 'saml20-sp-remote');
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             return $list;
         }
 
@@ -203,27 +203,26 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
         $filter = $spmd['discopower.filter'];
 
         if (!array_key_exists('entities.include', $filter)) {
-            $filter['entities.include'] = array();
+            $filter['entities.include'] = [];
         }
         if (!array_key_exists('entities.exclude', $filter)) {
-            $filter['entities.exclude'] = array();
+            $filter['entities.exclude'] = [];
         }
         if (!array_key_exists('tags.include', $filter)) {
-            $filter['tags.include'] = array();
+            $filter['tags.include'] = [];
         }
         if (!array_key_exists('tags.exclude', $filter)) {
-            $filter['tags.exclude'] = array();
+            $filter['tags.exclude'] = [];
         }
 
         $defaultrule = true;
         if (array_key_exists('entities.include', $spmd['discopower.filter']) ||
             array_key_exists('tags.include', $spmd['discopower.filter'])
         ) {
-
             $defaultrule = false;
         }
 
-        $returnlist = array();
+        $returnlist = [];
         foreach ($list as $key => $entry) {
             if ($this->processFilter($filter, $entry, $defaultrule)) {
                 $returnlist[$key] = $entry;
@@ -246,44 +245,123 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
         $idpList = $this->getIdPList();
         $idpList = $this->idplistStructured($this->filterList($idpList));
         $preferredIdP = $this->getRecommendedIdP();
-        $faventry = NULL;
-        foreach ($idpList AS $tab => $slist) {
+
+        $t = new \SimpleSAML\XHTML\Template($this->config, 'discopower:disco.tpl.php', 'disco');
+        $discoPowerTabs = [
+            'denmark' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:denmark}'),
+            'edugain' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:edugain}'),
+            'finland' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:finland}'),
+            'greece' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:greece}'),
+            'southafrica' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:southafrica}'),
+            'iceland' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:iceland}'),
+            'incommon' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:incommon}'),
+            'kalmar' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:kalmar}'),
+            'misc' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:misc}'),
+            'norway' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:norway}'),
+            'sweden' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:sweden}'),
+            'switzerland' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:switzerland}'),
+            'ukacessfederation' => \SimpleSAML\Locale\Translate::noop('{discopower:tabs:ukacessfederation}'),
+        ];
+
+        $t->data['return'] = $this->returnURL;
+        $t->data['returnIDParam'] = $this->returnIdParam;
+        $t->data['entityID'] = $this->spEntityId;
+        $t->data['defaulttab'] = $this->discoconfig->getValue('defaulttab', 0);
+
+        $idpList = $this->processMetadata($t, $idpList, $preferredIdP);
+
+        $t->data['idplist'] = $idpList;
+        foreach ($idpList as $tab => $slist) {
             if (!empty($preferredIdP) && array_key_exists($preferredIdP, $slist)) {
-                $faventry = $slist[$preferredIdP];
+                $t->data['faventry'] = $slist[$preferredIdP];
+                break;
             }
         }
 
-        $t = new SimpleSAML_XHTML_Template($this->config, 'discopower:disco.tpl.php', 'disco');
-        $discoPowerTabs = array(
-            'denmark' => $t->noop('{discopower:tabs:denmark}'),
-            'edugain' => $t->noop('{discopower:tabs:edugain}'),
-            'finland' => $t->noop('{discopower:tabs:finland}'),
-            'greece' => $t->noop('{discopower:tabs:greece}'),
-            'southafrica' => $t->noop('{discopower:tabs:southafrica}'),
-            'iceland' => $t->noop('{discopower:tabs:iceland}'),
-            'incommon' => $t->noop('{discopower:tabs:incommon}'),
-            'kalmar' => $t->noop('{discopower:tabs:kalmar}'),
-            'misc' => $t->noop('{discopower:tabs:misc}'),
-            'norway' => $t->noop('{discopower:tabs:norway}'),
-            'sweden' => $t->noop('{discopower:tabs:sweden}'),
-            'switzerland' => $t->noop('{discopower:tabs:switzerland}'),
-            'ukacessfederation' => $t->noop('{discopower:tabs:ukacessfederation}'),
-        );
-        $t->data['faventry'] = $faventry;
+        if (!empty($t->data['faventry'])) {
+            $t->data['autofocus'] = 'favouritesubmit';
+        }
+
+        $search = '<script type="text/javascript">
+            $(document).ready(function() {
+                $("#tabdiv").tabs({ selected: '.$t->data['defaulttab'].' });';
+        $i = 0;
+        foreach ($idpList as $tab => $slist) {
+            $search .= "\n".'$("#query_'.$tab.'").liveUpdate("#list_'.$tab.'")'.
+            (($i++ == 0) && (empty($this->data['faventry'])) ? '.focus()' : '').';';
+        }
+        $search .= "});\n</script>";
+
+        $t->data['search'] = $search;
+        $t->data['score'] = $this->discoconfig->getValue('score', 'quicksilver');
         $t->data['tabNames'] = $discoPowerTabs;
-        $t->data['idplist'] = $idpList;
         $t->data['preferredidp'] = $preferredIdP;
-        $t->data['return'] = $this->returnURL;
-        $t->data['returnIDParam'] = $this->returnIdParam;
-        $t->data['entityID'] = $this->spEntityId;
         $t->data['urlpattern'] = htmlspecialchars(\SimpleSAML\Utils\HTTP::getSelfURLNoQuery());
         $t->data['rememberenabled'] = $this->config->getBoolean('idpdisco.enableremember', false);
         $t->data['rememberchecked'] = $this->config->getBoolean('idpdisco.rememberchecked', false);
-        $t->data['defaulttab'] = $this->discoconfig->getValue('defaulttab', 0);
-        $t->data['score'] = $this->discoconfig->getValue('score', 'quicksilver');
+        $t->data['jquery'] = ['core' => true, 'ui' => true];
         $t->show();
     }
 
+    private function processMetadata($t, $metadata, $favourite)
+    {
+        $basequerystring = '?'.
+            'entityID='.urlencode($t->data['entityID']).'&amp;'.
+            'return='.urlencode($t->data['return']).'&amp;'.
+            'returnIDParam='.urlencode($t->data['returnIDParam']).'&amp;idpentityid=';
+
+        foreach ($metadata as $tab => $idps) {
+            foreach ($idps as $entityid => $entity) {
+                $translation = false;
+
+                // Translate name
+                if (isset($entity['UIInfo']['DisplayName'])) {
+                    $displayName = $entity['UIInfo']['DisplayName'];
+
+                    // Should always be an array of language code -> translation
+                    assert(is_array($displayName));
+
+                    if (!empty($displayName)) {
+                        $translation = $t->getTranslator()->getPreferredTranslation($displayName);
+                    }
+                }
+
+                if (($translation === false) && array_key_exists('name', $entity)) {
+                    if (is_array($entity['name'])) {
+                        $translation = $t->getTranslator()->getPreferredTranslation($entity['name']);
+                    } else {
+                        $translation = $entity['name'];
+                    }
+                }
+
+                if ($translation === false) {
+                    $translation = $entity['entityid'];
+                }
+                $entity['translated'] = $translation;
+
+                // HTML output
+                if ($entity['entityid'] === $favourite) {
+                    $html = '<a class="metaentry favourite" href="'.
+                        $basequerystring.urlencode($entity['entityid']).'">';
+                } else {
+                    $html = '<a class="metaentry" href="'.
+                        $basequerystring.urlencode($entity['entityid']).'">';
+                }
+                $html .= $entity['translated'];
+                if (array_key_exists('icon', $entity) && $entity['icon'] !== null) {
+                    $iconUrl = \SimpleSAML\Utils\HTTP::resolveURL($entity['icon']);
+                    $html .= '<img alt="Icon for identity provider" class="entryicon" src="'.
+                        htmlspecialchars($iconUrl).'" />';
+                }
+                $html .= '</a>';
+                $entity['html'] = $html;
+
+                // Save processed data
+                $metadata[$tab][$entityid] = $entity;
+            }
+        }
+        return $metadata;
+    }
 
     /**
      * Get the IdP entities saved in the common domain cookie.
@@ -293,7 +371,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
     private function getCDC()
     {
         if (!isset($_COOKIE['_saml_idp'])) {
-            return array();
+            return [];
         }
 
         $ret = (string) $_COOKIE['_saml_idp'];
@@ -302,7 +380,7 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
             $idp = base64_decode($idp);
             if ($idp === false) {
                 // not properly base64 encoded
-                return array();
+                return [];
             }
         }
 
@@ -349,12 +427,12 @@ class sspmod_discopower_PowerIdPDisco extends SimpleSAML_XHTML_IdPDisco
             $newCookie = $tmp[1];
         }
 
-        $params = array(
+        $params = [
             'lifetime' => $this->cdcLifetime,
             'domain'   => $this->cdcDomain,
             'secure'   => true,
             'httponly' => false,
-        );
+        ];
         \SimpleSAML\Utils\HTTP::setCookie('_saml_idp', $newCookie, $params, false);
     }
 
diff --git a/modules/discopower/templates/disco.tpl.php b/modules/discopower/templates/disco.tpl.php
index b7b1001219a31da01cb39fd8219fd950f990631d..4174ace4ca80724f08a5d54bcf02688c1dd19aae 100644
--- a/modules/discopower/templates/disco.tpl.php
+++ b/modules/discopower/templates/disco.tpl.php
@@ -1,175 +1,148 @@
 <?php
 
-if(!array_key_exists('header', $this->data)) {
-	$this->data['header'] = 'selectidp';
-}
-$this->data['header'] = $this->t($this->data['header']);
-$this->data['jquery'] = array('core' => TRUE, 'ui' => TRUE, 'css' => TRUE);
-
-$this->data['head'] = '<link rel="stylesheet" media="screen" type="text/css" href="' . SimpleSAML\Module::getModuleUrl('discopower/style.css')  . '" />';
+$this->data['header'] = $this->t('selectidp');
+$this->data['jquery'] = ['core' => true, 'ui' => true, 'css' => true];
 
-$this->data['head'] .= '<script type="text/javascript" src="' . SimpleSAML\Module::getModuleUrl('discopower/js/jquery.livesearch.js')  . '"></script>';
-$this->data['head'] .= '<script type="text/javascript" src="' . SimpleSAML\Module::getModuleUrl('discopower/js/' . $this->data['score'] . '.js')  . '"></script>';
-
-$this->data['head'] .= '<script type="text/javascript">
-
-$(document).ready(function() {
-	$("#discotabs").tabs({ selected: ' . $this->data['defaulttab'] . ' }); ';
-	
-$i = 0;
-foreach ($this->data['idplist'] AS $tab => $slist) {
-	$this->data['head'] .= "\n" . '$("#query_' . $tab . '").liveUpdate("#list_' . $tab . '")' .
-		(($i++ == 0) && (empty($this->data['faventry'])) ? '.focus()' : '') .
-		';';
+$this->data['head'] = '<link rel="stylesheet" media="screen" type="text/css" href="'.
+    SimpleSAML\Module::getModuleURL('discopower/assets/css/style.css').'" />';
 
+$this->data['post'] = '<script type="text/javascript" src="'.
+    SimpleSAML\Module::getModuleURL('discopower/assets/js/jquery.livesearch.js').'"></script>';
+$this->data['post'] .= '<script type="text/javascript" src="'.
+    SimpleSAML\Module::getModuleURL('discopower/assets/js/quicksilver.js').'"></script>';
 
+if (!empty($this->data['faventry'])) {
+    $this->data['autofocus'] = 'favouritesubmit';
 }
 
-$this->data['head'] .= '
-});
-
-</script>';
-
-
-
-
-
-if (!empty($this->data['faventry'])) $this->data['autofocus'] = 'favouritesubmit';
-
 $this->includeAtTemplateBase('includes/header.php');
 
-function showEntry($t, $metadata, $favourite = FALSE) {
-	
-	$basequerystring = '?' . 
-		'entityID=' . urlencode($t->data['entityID']) . '&amp;' . 
-		'return=' . urlencode($t->data['return']) . '&amp;' . 
-		'returnIDParam=' . urlencode($t->data['returnIDParam']) . '&amp;idpentityid=';
-	
-	$extra = ($favourite ? ' favourite' : '');
-	$html = '<a class="metaentry' . $extra . '" href="' . $basequerystring . urlencode($metadata['entityid']) . '">';
-	
-	$html .= '' . htmlspecialchars(getTranslatedName($t, $metadata)) . '';
-
-	if(array_key_exists('icon', $metadata) && $metadata['icon'] !== NULL) {
-		$iconUrl = \SimpleSAML\Utils\HTTP::resolveURL($metadata['icon']);
-		$html .= '<img alt="Icon for identity provider" class="entryicon" src="' . htmlspecialchars($iconUrl) . '" />';
-	}
-
-	$html .= '</a>';
-	
-	return $html;
-}
-
-?>
-
+function showEntry($t, $metadata, $favourite = false)
+{
+    $basequerystring = '?'.
+        'entityID='.urlencode($t->data['entityID']).'&amp;'.
+        'return='.urlencode($t->data['return']).'&amp;'.
+        'returnIDParam='.urlencode($t->data['returnIDParam']).'&amp;idpentityid=';
 
+    $extra = ($favourite ? ' favourite' : '');
+    $html = '<a class="metaentry'.$extra.'" href="'.$basequerystring.urlencode($metadata['entityid']).'">';
 
+    $html .= htmlspecialchars(getTranslatedName($t, $metadata)).'';
 
-<?php
+    if (array_key_exists('icon', $metadata) && $metadata['icon'] !== null) {
+        $iconUrl = \SimpleSAML\Utils\HTTP::resolveURL($metadata['icon']);
+        $html .= '<img alt="Icon for identity provider" class="entryicon" src="'.htmlspecialchars($iconUrl).'" />';
+    }
 
-function getTranslatedName($t, $metadata) {
-	if (isset($metadata['UIInfo']['DisplayName'])) {
-		$displayName = $metadata['UIInfo']['DisplayName'];
-		assert(is_array($displayName)); // Should always be an array of language code -> translation
-		if (!empty($displayName)) {
-			return $t->getTranslator()->getPreferredTranslation($displayName);
-		}
-	}
-
-	if (array_key_exists('name', $metadata)) {
-		if (is_array($metadata['name'])) {
-			return $t->getTranslator()->getPreferredTranslation($metadata['name']);
-		} else {
-			return $metadata['name'];
-		}
-	}
-	return $metadata['entityid'];
+    $html .= '</a>';
+    return $html;
 }
 
-
-
+function getTranslatedName($t, $metadata)
+{
+    if (isset($metadata['UIInfo']['DisplayName'])) {
+        $displayName = $metadata['UIInfo']['DisplayName'];
+        assert(is_array($displayName)); // Should always be an array of language code -> translation
+        if (!empty($displayName)) {
+            return $t->getTranslator()->getPreferredTranslation($displayName);
+        }
+    }
+
+    if (array_key_exists('name', $metadata)) {
+        if (is_array($metadata['name'])) {
+            return $t->getTranslator()->getPreferredTranslation($metadata['name']);
+        } else {
+            return $metadata['name'];
+        }
+    }
+    return $metadata['entityid'];
+}
 
 if (!empty($this->data['faventry'])) {
-
-
-	echo('<div class="favourite">');
-	echo($this->t('previous_auth'));
-	echo(' <strong>' . htmlspecialchars(getTranslatedName($this, $this->data['faventry'])) . '</strong>');
-	echo('
-	<form id="idpselectform" method="get" action="' . $this->data['urlpattern'] . '">
-		<input type="hidden" name="entityID" value="' . htmlspecialchars($this->data['entityID']) . '" />
-		<input type="hidden" name="return" value="' . htmlspecialchars($this->data['return']) . '" />
-		<input type="hidden" name="returnIDParam" value="' . htmlspecialchars($this->data['returnIDParam']) . '" />
-		<input type="hidden" name="idpentityid" value="' . htmlspecialchars($this->data['faventry']['entityid']) . '" />
-
-		<input type="submit" name="formsubmit" id="favouritesubmit" value="' . $this->t('login_at') . ' ' . htmlspecialchars(getTranslatedName($this, $this->data['faventry'])) . '" /> 
-	</form>');
-
-	echo('</div>');
+    echo '<div class="favourite">' ;
+    echo $this->t('previous_auth');
+    echo ' <strong>'.htmlspecialchars(getTranslatedName($this, $this->data['faventry'])).'</strong>';
+    echo '<form id="idpselectform" method="get" action="'.$this->data['urlpattern'].
+        '"><input type="hidden" name="entityID" value="'.htmlspecialchars($this->data['entityID']).
+        '" /><input type="hidden" name="return" value="'.htmlspecialchars($this->data['return']).
+        '" /><input type="hidden" name="returnIDParam" value="'.htmlspecialchars($this->data['returnIDParam']).
+        '" /><input type="hidden" name="idpentityid" value="'.htmlspecialchars($this->data['faventry']['entityid']).
+        '" /><input type="submit" name="formsubmit" id="favouritesubmit" value="'.$this->t('login_at').' '.
+        htmlspecialchars(getTranslatedName($this, $this->data['faventry'])).'" /></form>';
+    echo '</div>';
 }
-
-
 ?>
 
-
-
-
-
-
-<div id="discotabs"> 
-
+<div id="tabdiv"> 
     <ul class="tabset_tabs">     
-    	<?php
-    	
-    		$tabs = array_keys( $this->data['idplist']);
-    		foreach ($tabs AS $tab) {
-			if(!empty($this->data['idplist'][$tab])) {
-				echo '<li><a href="#' . $tab . '"><span>' . $this->t($this->data['tabNames'][$tab]) . '</span></a></li> ';
-			}
-    		}
-    	
-    	?>
+        <?php
+        $tabs = array_keys($this->data['idplist']);
+        $i = 1;
+        foreach ($tabs as $tab) {
+            if (!empty($this->data['idplist'][$tab])) {
+                if ($i === 1) {
+                    echo '<li class="tab-link current" data-tab="'.$tab.'"><a href="#'.$tab.
+                        '"><span>'.$this->t($this->data['tabNames'][$tab]).'</span></a></li>';
+                } else {
+                    echo '<li class="tab-link" data-tab="'.$tab.'"><a href="#'.$tab.
+                        '"><span>'.$this->t($this->data['tabNames'][$tab]).'</span></a></li> ';
+                }
+                $i++;
+            }
+        }
+        ?>
     </ul> 
-    
 
 <?php
 
+foreach ($this->data['idplist'] as $tab => $slist) {
+    $first = array_keys($this->data['idplist']);
+    if ($first[0] === $tab) {
+        echo '<div id="'.$tab.'" class="tabset_content current">';
+    } else {
+        echo '<div id="'.$tab.'" class="tabset_content">';
+    }
+    if (!empty($slist)) {
+        echo '<div class="inlinesearch">';
+        echo '<p>Incremental search...</p>';
+        echo '<form id="idpselectform" action="?" method="get">';
+        echo '<input class="inlinesearch" type="text" value="" name="query_'.$tab.'" id="query_'.$tab.'" /></form>';
+        echo '</div>';
+
+        echo '<div class="metalist" id="list_'.$tab .'">';
+        if (!empty($this->data['preferredidp']) && array_key_exists($this->data['preferredidp'], $slist)) {
+            $idpentry = $slist[$this->data['preferredidp']];
+            echo showEntry($this, $idpentry, true);
+        }
+
+        foreach ($slist as $idpentry) {
+            if ($idpentry['entityid'] != $this->data['preferredidp']) {
+                echo showEntry($this, $idpentry);
+            }
+        }
+        echo '</div>';
+    }
+    echo '</div>';
+}
 
+?>
 
+</div>
 
-foreach( $this->data['idplist'] AS $tab => $slist) {
-
-	echo '<div id="' . $tab . '">';
-
-	if (!empty($slist)) {
-
-		echo('	<div class="inlinesearch">');
-		echo('	<p>Incremental search...</p>');
-		echo('	<form id="idpselectform" action="?" method="get"><input class="inlinesearchf" type="text" value="" name="query_' . $tab . '" id="query_' . $tab . '" /></form>');
-		echo('	</div>');
-	
-		echo('	<div class="metalist" id="list_' . $tab  . '">');
-		if (!empty($this->data['preferredidp']) && array_key_exists($this->data['preferredidp'], $slist)) {
-			$idpentry = $slist[$this->data['preferredidp']];
-			echo (showEntry($this, $idpentry, TRUE));
-		}
-
-		foreach ($slist AS $idpentry) {
-			if ($idpentry['entityid'] != $this->data['preferredidp']) {
-				echo (showEntry($this, $idpentry));
-			}
-		}
-		echo('	</div>');
-	}
-	echo '</div>';
-
+<script type="text/javascript">
+$(document).ready(function () {
+<?php
+$i = 0;
+foreach ($this->data['idplist'] as $tab => $slist) {
+    echo "\n".'$("#query_'.$tab.'").liveUpdate("#list_'.$tab.'")'.
+        (($i++ == 0) && (empty($this->data['faventry'])) ? '.focus()' : '').';';
 }
-	
 ?>
+});
 
+</script>
 
-
-</div>
-
-		
-<?php $this->includeAtTemplateBase('includes/footer.php');
+<?php
+$this->data['post'] .= '<script type="text/javascript" src="'.
+    SimpleSAML\Module::getModuleURL('discopower/js/javascript.js').'"></script>';
+$this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/discopower/templates/disco.twig b/modules/discopower/templates/disco.twig
new file mode 100644
index 0000000000000000000000000000000000000000..8e7082304c16f598e75ada0fc0fb0274ef95ee15
--- /dev/null
+++ b/modules/discopower/templates/disco.twig
@@ -0,0 +1,54 @@
+{% set pagetitle = 'selectidp'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}style.css" rel="stylesheet" type="text/css" media="screen" />
+{% endblock %}
+{% block postload %}
+    <script type="text/javascript" src="{{ baseurlpath }}js/jquery.livesearch.js"></script>
+    <script type="text/javascript" src="{{ baseurlpath }}js/{{ score }}.js"></script>
+    {{ search|raw }}
+{% endblock %}
+
+{% block content %}
+    {% if faventry is not empty %}
+    <div class="favourite">{{ '{disco:previous_auth}'|trans }}
+        <strong>{{ faventry.translated|escape('html') }}</strong>
+        <form id="idpselectform" method="get" action="{{ urlpattern }}">
+            <input type="hidden" name="entityID" value="{{ entityID|escape('html') }}" />
+            <input type="hidden" name="return" value="{{ return|escape('html') }}" />
+            <input type="hidden" name="returnIDParam" value="{{ returnIDParam|escape('html') }}" />
+            <input type="hidden" name="idpentityid" value="{{ faventry.entityid|escape('html') }}" />
+            <input type="submit" name="formsubmit" id="favouritesubmit" value="{{ '{disco:login_at}'|trans }} {{ faventry.translated|escape('html') }}" /> 
+	</form>
+    </div>
+    {% endif %}
+
+    <div id="tabdiv">
+        <ul class="tabset_tabs">
+        {% for tab, idps in idplist %}
+            {% if idps is not empty %}
+            <li class="tab-link{% if loop.first %}current{% endif %}" data-tab="{{ tab }}"><a href="#{{ tab }}"><span>{{ tabNames[tab]|trans }}</span></a></li>
+            {% endif %}
+        {% endfor %}
+        </ul>
+
+        {% for tab, idps in idplist %}
+        {% if idps is not empty %}
+          <div id="{{ tab }}" class="tabset_content{% if loop.first %} current{% endif %}">
+          <div class="inlinesearch">
+              <p>Incremental search...</p>
+              <form id="idpselectform" method="get">
+                  <input class="inlinesearch" type="text" value="" name="query_{{ tab }}" id="query_{{ tab }}" />
+              </form>
+          </div>
+          <div class="metalist" id="list_{{ tab }}">
+          {% for entityid, entity in idps %}
+              {{ entity.html|raw }}
+          {% endfor %}
+          </div>
+          </div>
+        {% endif %}
+        {% endfor %}
+    </div>
+{% endblock %}
diff --git a/modules/discopower/www/assets/css/disco.css b/modules/discopower/www/assets/css/disco.css
new file mode 100644
index 0000000000000000000000000000000000000000..c270798321da61b199164d62918d58d3e952f184
--- /dev/null
+++ b/modules/discopower/www/assets/css/disco.css
@@ -0,0 +1,107 @@
+.inlinesearch {
+    float: right;
+    margin: 0em 3px .5em 1em;
+}
+.inlinesearch p {
+    font-size: 94%;
+    color: #aaa;
+}
+.inlinesearch input {
+    background-image:url('../../resources/icons/silk/magnifier.png');
+    background-repeat:no-repeat;
+    background-position:center left;
+    border: 1px solid #ccc;
+    padding: 2px 2px 2px 20px;
+    margin: 0px 2px 0px 0px;
+}
+.inlinesearch * {
+    margin: 0px;
+    padding: 0px;
+}
+div.metalist {
+    clear: both;
+    list-style: none;
+    margin: 1em 2px .5em 2px;
+    padding: 0px;
+}
+a.metaentry {
+    display: block;
+    border: 1px solid #ccc;
+    margin: 0px 0px -1px 0px;
+    padding: .2em 1em .2em 20px;
+    cursor: pointer;
+    cursor: hand;
+}
+a.metaentry.favourite {
+    background-image:url('../../resources/icons/silk/heart.png');
+    background-repeat:no-repeat;
+    background-position:center left;
+}
+a.metaentry:hover {
+    border: 1px solid #ccc;
+    background: #eee;
+    background-image:url('../../resources/icons/silk/star.png');
+    background-repeat:no-repeat;
+    background-position:center left;
+}
+a.metaentry img.entryicon {
+    display: none;
+}
+a.metaentry:hover img.entryicon {
+    display: inline;
+    top: 0px;
+    bottom: 0px;
+    clear: both;
+    float: right;
+    margin: 1em;
+    padding: 3px;
+    border: 1px solid #999;
+}
+
+div.favourite {
+    margin: 1em 0px;
+    padding: 1em;
+    border: 1px solid #ccc;
+    background-color: #eee;
+}
+
+div#content {
+    margin: .4em ! important;
+}
+
+form {
+    display: inline;
+}
+
+table#statmeta {
+    width: 100%;
+}
+
+ul.tabset_tabs {
+    margin: 0px;
+    padding: 0px;
+    list-style: none;
+}
+
+ul.tabset_tabs li {
+    background: none;
+    color: #222;
+    display: inline-block;
+    padding: 10px 15px;
+    cursor: pointer;
+}
+
+ul.tabset_tabs li.current {
+    background: #ededed;
+    color: #222;
+}
+
+.tabset_content {
+    display: none;
+    background: #ededed;
+    padding: 15px;
+}
+
+.tabset_content.current {
+    display: inherit;
+}
diff --git a/modules/discopower/www/assets/js/jquery.livesearch.js b/modules/discopower/www/assets/js/jquery.livesearch.js
new file mode 100644
index 0000000000000000000000000000000000000000..2b125ff951350ae8c49fd0de49442da48a7bc3f2
--- /dev/null
+++ b/modules/discopower/www/assets/js/jquery.livesearch.js
@@ -0,0 +1,43 @@
+jQuery.fn.liveUpdate = function (list) {
+    list = jQuery(list);
+
+    if (list.length) {
+        var rows = list.children('a'),
+        cache = rows.map(function () {
+            return jQuery(this).text().toLowerCase();
+        });
+
+        this.keyup(filter).keyup().parents('form').submit(function () {
+            return false;
+        });
+    }
+
+    return this;
+
+    function filter()
+    {
+        var term = jQuery.trim(jQuery(this).val().toLowerCase()), scores = [];
+
+        if (!term) {
+            rows.show();
+        } else {
+            rows.hide();
+
+            cache.each(function (i) {
+                var score = this.score(term);
+                if (score > 0) {
+                    scores.push([score, i]);
+                }
+            });
+
+            jQuery.each(
+                scores.sort(function (a, b) {
+                    return b[0] - a[0];
+                }),
+                function () {
+                    jQuery(rows[ this[1] ]).show();
+                }
+            );
+        }
+    }
+};
diff --git a/modules/discopower/www/assets/js/quicksilver.js b/modules/discopower/www/assets/js/quicksilver.js
new file mode 100644
index 0000000000000000000000000000000000000000..079ea87d5c2c03ec140396014394dbed08ad4dad
--- /dev/null
+++ b/modules/discopower/www/assets/js/quicksilver.js
@@ -0,0 +1,102 @@
+// qs_score - Quicksilver Score
+//
+// A port of the Quicksilver string ranking algorithm
+//
+// "hello world".score("axl") //=> 0.0
+// "hello world".score("ow") //=> 0.6
+// "hello world".score("hello world") //=> 1.0
+//
+// Tested in Firefox 2 and Safari 3
+//
+// The Quicksilver code is available here
+// http://code.google.com/p/blacktree-alchemy/
+// http://blacktree-alchemy.googlecode.com/svn/trunk/Crucible/Code/NSString+BLTRRanking.m
+//
+// The MIT License
+//
+// Copyright (c) 2008 Lachie Cox
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+String.prototype.score = function (abbreviation,offset) {
+    offset = offset || 0 // TODO: I think this is unused... remove
+ 
+    if (abbreviation.length == 0) {
+        return 0.9
+    }
+    if (abbreviation.length > this.length) {
+        return 0.0
+    }
+
+    for (var i = abbreviation.length; i > 0; i--) {
+        var sub_abbreviation = abbreviation.substring(0,i)
+        var index = this.indexOf(sub_abbreviation)
+
+
+        if (index < 0) {
+            continue;
+        }
+        if (index + abbreviation.length > this.length + offset) {
+            continue;
+        }
+
+        var next_string = this.substring(index+sub_abbreviation.length)
+        var next_abbreviation = null
+
+        if (i >= abbreviation.length) {
+            next_abbreviation = ''
+        } else {
+            next_abbreviation = abbreviation.substring(i)
+        }
+ 
+        var remaining_score = next_string.score(next_abbreviation,offset + index)
+ 
+        if (remaining_score > 0) {
+            var score = this.length - next_string.length;
+
+            if (index != 0) {
+                var j = 0;
+                var c = this.charCodeAt(index - 1)
+                if ( c==32 || c == 9) {
+                    for (var j=(index-2); j >= 0; j--) {
+                        c = this.charCodeAt(j)
+                        score -= ((c == 32 || c == 9) ? 1 : 0.15)
+                    }
+                // XXX maybe not port this heuristic
+                //
+                // } else if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:matchedRange.location]]) {
+                //     for (j = matchedRange.location-1; j >= (int) searchRange.location; j--) {
+                //         if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:j]])
+                //             score--;
+                //         else
+                //             score -= 0.15;
+                //     }
+                } else {
+                    score -= index
+                }
+            }
+   
+            score += remaining_score * next_string.length
+            score /= this.length;
+            return score
+        }
+    }
+    return 0.0
+}
diff --git a/modules/discopower/www/assets/js/suggest.js b/modules/discopower/www/assets/js/suggest.js
new file mode 100644
index 0000000000000000000000000000000000000000..b404edd0a0509dad13cab4d2d6fab86feaa0c85b
--- /dev/null
+++ b/modules/discopower/www/assets/js/suggest.js
@@ -0,0 +1,25 @@
+var suggest_cache = new Array;
+
+String.prototype.score = function (abbreviation,offset) {
+    if (suggest_cache['abv'] != abbreviation) {
+        suggest_cache['abv'] = abbreviation;
+        var words = abbreviation.split(/\s/);
+        suggest_cache['len'] = words.length;
+        suggest_cache.re = new Array;
+
+        //words.each();
+        for (var i = 0; i < suggest_cache['len']; ++i) {
+            suggest_cache['re'][i] = new Array();
+            // /\b<x>/ doesn't work when <x> i a non-ascii - oddly enough \s does ...
+            suggest_cache['re'][i]['initialword'] = new RegExp("^"+words[i], "i");
+            suggest_cache['re'][i]['word'] = new RegExp("[\\s-()_]"+words[i], "i");
+        }
+    }
+
+    for (var i = 0; i < suggest_cache['len']; ++i) {
+        if (!(this.match(suggest_cache['re'][i]['initialword']) || this.match(suggest_cache['re'][i]['word']))) {
+            return 0;
+        }
+    }
+    return 1;
+}
diff --git a/modules/discopower/www/disco.php b/modules/discopower/www/disco.php
index bfadb7c986dd9b5bb342d0b33cdd629b8d94cb99..6a074787153d2076ba1dc7d872f2ad0cfadc50a5 100644
--- a/modules/discopower/www/disco.php
+++ b/modules/discopower/www/disco.php
@@ -1,15 +1,18 @@
 <?php
 
 try {
-	$discoHandler = new sspmod_discopower_PowerIdPDisco(array('saml20-idp-remote', 'shib13-idp-remote'), 'poweridpdisco');
-} catch (Exception $exception) {
-	// An error here should be caused by invalid query parameters
-	throw new SimpleSAML_Error_Error('DISCOPARAMS', $exception);
+    $discoHandler = new \SimpleSAML\Module\discopower\PowerIdPDisco(
+        ['saml20-idp-remote', 'shib13-idp-remote'],
+        'poweridpdisco'
+    );
+} catch (\Exception $exception) {
+    // An error here should be caused by invalid query parameters
+    throw new \SimpleSAML\Error\Error('DISCOPARAMS', $exception);
 }
 
 try {
-	$discoHandler->handleRequest();
-} catch(Exception $exception) {
-	// An error here should be caused by metadata
-	throw new SimpleSAML_Error_Error('METADATA', $exception);
+    $discoHandler->handleRequest();
+} catch (\Exception $exception) {
+    // An error here should be caused by metadata
+    throw new \SimpleSAML\Error\Error('METADATA', $exception);
 }
diff --git a/modules/discopower/www/js/jquery.livesearch.js b/modules/discopower/www/js/jquery.livesearch.js
deleted file mode 100644
index 06c30437371ed145f78c5d27b085fae6c825a47c..0000000000000000000000000000000000000000
--- a/modules/discopower/www/js/jquery.livesearch.js
+++ /dev/null
@@ -1,37 +0,0 @@
-jQuery.fn.liveUpdate = function(list){
-	list = jQuery(list);
-
-	if ( list.length ) {
-		var rows = list.children('a'),
-			cache = rows.map(function(){
-				return jQuery(this).text().toLowerCase();
-			});
-			
-		this
-			.keyup(filter).keyup()
-			.parents('form').submit(function(){
-				return false;
-			});
-	}
-		
-	return this;
-		
-	function filter(){
-		var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];
-		
-		if ( !term ) {
-			rows.show();
-		} else {
-			rows.hide();
-
-			cache.each(function(i){
-				var score = this.score(term);
-				if (score > 0) { scores.push([score, i]); }
-			});
-
-			jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
-				jQuery(rows[ this[1] ]).show();
-			});
-		}
-	}
-};
diff --git a/modules/discopower/www/js/quicksilver.js b/modules/discopower/www/js/quicksilver.js
deleted file mode 100644
index af29f732b48a5609bb09c6beb3c04f99610f2534..0000000000000000000000000000000000000000
--- a/modules/discopower/www/js/quicksilver.js
+++ /dev/null
@@ -1,95 +0,0 @@
-// qs_score - Quicksilver Score
-// 
-// A port of the Quicksilver string ranking algorithm
-// 
-// "hello world".score("axl") //=> 0.0
-// "hello world".score("ow") //=> 0.6
-// "hello world".score("hello world") //=> 1.0
-//
-// Tested in Firefox 2 and Safari 3
-//
-// The Quicksilver code is available here
-// http://code.google.com/p/blacktree-alchemy/
-// http://blacktree-alchemy.googlecode.com/svn/trunk/Crucible/Code/NSString+BLTRRanking.m
-//
-// The MIT License
-// 
-// Copyright (c) 2008 Lachie Cox
-// 
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-// 
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-
-String.prototype.score = function(abbreviation,offset) {
-  offset = offset || 0 // TODO: I think this is unused... remove
- 
-  if(abbreviation.length == 0) return 0.9
-  if(abbreviation.length > this.length) return 0.0
-
-  for (var i = abbreviation.length; i > 0; i--) {
-    var sub_abbreviation = abbreviation.substring(0,i)
-    var index = this.indexOf(sub_abbreviation)
-
-
-    if(index < 0) continue;
-    if(index + abbreviation.length > this.length + offset) continue;
-
-    var next_string       = this.substring(index+sub_abbreviation.length)
-    var next_abbreviation = null
-
-    if(i >= abbreviation.length)
-      next_abbreviation = ''
-    else
-      next_abbreviation = abbreviation.substring(i)
- 
-    var remaining_score   = next_string.score(next_abbreviation,offset+index)
- 
-    if (remaining_score > 0) {
-      var score = this.length-next_string.length;
-
-      if(index != 0) {
-        var j = 0;
-
-        var c = this.charCodeAt(index-1)
-        if(c==32 || c == 9) {
-          for(var j=(index-2); j >= 0; j--) {
-            c = this.charCodeAt(j)
-            score -= ((c == 32 || c == 9) ? 1 : 0.15)
-          }
-
-          // XXX maybe not port this heuristic
-          // 
-          //          } else if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:matchedRange.location]]) {
-          //            for (j = matchedRange.location-1; j >= (int) searchRange.location; j--) {
-          //              if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember:[self characterAtIndex:j]])
-          //                score--;
-          //              else
-          //                score -= 0.15;
-          //            }
-        } else {
-          score -= index
-        }
-      }
-   
-      score += remaining_score * next_string.length
-      score /= this.length;
-      return score
-    }
-  }
-  return 0.0
-}
\ No newline at end of file
diff --git a/modules/discopower/www/js/suggest.js b/modules/discopower/www/js/suggest.js
deleted file mode 100644
index 667b35ac944d2aead91124e72542bba5409e00e6..0000000000000000000000000000000000000000
--- a/modules/discopower/www/js/suggest.js
+++ /dev/null
@@ -1,23 +0,0 @@
-var suggest_cache = new Array;
-
-String.prototype.score = function(abbreviation,offset) {
-	if (suggest_cache['abv'] != abbreviation) {
-		suggest_cache['abv'] = abbreviation;
-		var words = abbreviation.split(/\s/);
-		suggest_cache['len'] = words.length;
-		suggest_cache.re = new Array;
-
-		//words.each();
-		for ( var i=0; i<suggest_cache['len']; ++i ){
-			suggest_cache['re'][i] = new Array();
-			// /\b<x>/ doesn't work when <x> i a non-ascii - oddly enough \s does ...
-			suggest_cache['re'][i]['initialword'] = new RegExp("^"+words[i], "i");
-			suggest_cache['re'][i]['word'] = new RegExp("[\\s-()_]"+words[i], "i");
-		}
-	}
-
-	for ( var i=0; i<suggest_cache['len']; ++i ){
-		if (!(this.match(suggest_cache['re'][i]['initialword']) || this.match(suggest_cache['re'][i]['word']))) return 0;
-	}
-	return 1;
-}
diff --git a/modules/discopower/www/style.css b/modules/discopower/www/style.css
deleted file mode 100644
index 3af002dff4a6006a83c75275ea6d9870465a30e8..0000000000000000000000000000000000000000
--- a/modules/discopower/www/style.css
+++ /dev/null
@@ -1,76 +0,0 @@
-.inlinesearch:hover {
-
-}
-.inlinesearch {
-	float: right;
-	margin: 0em 3px .5em 1em;
-	
-/*	padding: .3em;*/
-}
-.inlinesearch p {
-	font-size: 94%;
-	color: #aaa;
-
-}
-.inlinesearch input {
-	background-image:url('../../resources/icons/silk/magnifier.png');
-	background-repeat:no-repeat;
-	background-position:center left;
-	border: 1px solid #ccc;
-	padding: 2px 2px 2px 20px;
-	margin: 0px 2px 0px 0px;
-}
-.inlinesearch * {
-	margin: 0px; 
-	padding: 0px;
-}
-div.metalist {
-	clear: both;
-	list-style: none;
-	margin: 1em 2px .5em 2px;
-	padding: 0px;
-}
-a.metaentry {
-	display: block;
-	border: 1px solid #ccc;
-	margin: 0px 0px -1px 0px;
-	padding: .2em 1em .2em 20px;
-	cursor: pointer;
-	cursor: hand;
-}
-a.metaentry.favourite {
-	background-image:url('../../resources/icons/silk/heart.png');
-	background-repeat:no-repeat;
-	background-position:center left;
-
-}
-a.metaentry:hover {
-	border: 1px solid #ccc;
-	background: #eee;
-
-	background-image:url('../../resources/icons/silk/star.png');
-	background-repeat:no-repeat;
-	background-position:center left;
-}
-a.metaentry img.entryicon {
-	display: none;
-}
-a.metaentry:hover img.entryicon {
-	display: inline;
-	top: 0px;
-	bottom: 0px;
-	clear: both; 
-	float: right; 
-	margin: 1em; 
-	padding: 3px; 
-	border: 1px solid #999;
-}
-
-div.favourite {
-
-	margin: 1em 0px;
-	padding: 1em;
-	border: 1px solid #ccc;
-	background-color: #eee;
-
-}
diff --git a/modules/exampleattributeserver/www/attributeserver.php b/modules/exampleattributeserver/www/attributeserver.php
index 8f257c2a427bf9fb8564cbe8ceeba1a8a744a4ad..5664e415c640326369489746774d8fde36c44504 100644
--- a/modules/exampleattributeserver/www/attributeserver.php
+++ b/modules/exampleattributeserver/www/attributeserver.php
@@ -1,93 +1,89 @@
 <?php
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
 $binding = \SAML2\Binding::getCurrentBinding();
 $query = $binding->receive();
 if (!($query instanceof \SAML2\AttributeQuery)) {
-	throw new SimpleSAML_Error_BadRequest('Invalid message received to AttributeQuery endpoint.');
+    throw new \SimpleSAML\Error\BadRequest('Invalid message received to AttributeQuery endpoint.');
 }
 
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
 
 
 $spEntityId = $query->getIssuer();
-if ($spEntityId === NULL) {
-	throw new SimpleSAML_Error_BadRequest('Missing <saml:Issuer> in <samlp:AttributeQuery>.');
+if ($spEntityId === null) {
+    throw new \SimpleSAML\Error\BadRequest('Missing <saml:Issuer> in <samlp:AttributeQuery>.');
 }
 
-$idpMetadata = $metadata->getMetadataConfig($idpEntityId, 'saml20-idp-hosted');
+$idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
 $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
 
 // The endpoint we should deliver the message to
 $endpoint = $spMetadata->getString('testAttributeEndpoint');
 
 // The attributes we will return
-$attributes = array(
-	'name' => array('value1', 'value2', 'value3'),
-	'test' => array('test'),
-);
+$attributes = [
+    'name' => ['value1', 'value2', 'value3'],
+    'test' => ['test'],
+];
 
-/* The name format of the attributes. */
+// The name format of the attributes
 $attributeNameFormat = \SAML2\Constants::NAMEFORMAT_UNSPECIFIED;
 
-
-/* Determine which attributes we will return. */
+// Determine which attributes we will return
 $returnAttributes = array_keys($query->getAttributes());
 if (count($returnAttributes) === 0) {
-	SimpleSAML\Logger::debug('No attributes requested - return all attributes.');
-	$returnAttributes = $attributes;
-
+    SimpleSAML\Logger::debug('No attributes requested - return all attributes.');
+    $returnAttributes = $attributes;
 } elseif ($query->getAttributeNameFormat() !== $attributeNameFormat) {
-	SimpleSAML\Logger::debug('Requested attributes with wrong NameFormat - no attributes returned.');
-	$returnAttributes = array();
+    SimpleSAML\Logger::debug('Requested attributes with wrong NameFormat - no attributes returned.');
+    $returnAttributes = [];
 } else {
-	foreach ($returnAttributes as $name => $values) {
-		if (!array_key_exists($name, $attributes)) {
-			/* We don't have this attribute. */
-			unset($returnAttributes[$name]);
-			continue;
-		}
-
-		if (count($values) === 0) {
-			/* Return all attributes. */
-			$returnAttributes[$name] = $attributes[$name];
-			continue;
-		}
-
-		/* Filter which attribute values we should return. */
-		$returnAttributes[$name] = array_intersect($values, $attributes[$name]);
-	}
+    foreach ($returnAttributes as $name => $values) {
+        if (!array_key_exists($name, $attributes)) {
+            // We don't have this attribute
+            unset($returnAttributes[$name]);
+            continue;
+        }
+        if (count($values) === 0) {
+            // Return all attributes
+            $returnAttributes[$name] = $attributes[$name];
+            continue;
+        }
+
+        // Filter which attribute values we should return
+        $returnAttributes[$name] = array_intersect($values, $attributes[$name]);
+    }
 }
 
-
-/* $returnAttributes contains the attributes we should return. Send them. */
+// $returnAttributes contains the attributes we should return. Send them
 $assertion = new \SAML2\Assertion();
 $assertion->setIssuer($idpEntityId);
 $assertion->setNameId($query->getNameId());
 $assertion->setNotBefore(time());
-$assertion->setNotOnOrAfter(time() + 5*60);
-$assertion->setValidAudiences(array($spEntityId));
+$assertion->setNotOnOrAfter(time() + 300); // 60*5 = 5min
+$assertion->setValidAudiences([$spEntityId]);
 $assertion->setAttributes($returnAttributes);
 $assertion->setAttributeNameFormat($attributeNameFormat);
 
 $sc = new \SAML2\XML\saml\SubjectConfirmation();
 $sc->Method = \SAML2\Constants::CM_BEARER;
 $sc->SubjectConfirmationData = new \SAML2\XML\saml\SubjectConfirmationData();
-$sc->SubjectConfirmationData->NotOnOrAfter = time() + 5*60;
+$sc->SubjectConfirmationData->NotOnOrAfter = time() + 300; // 60*5 = 5min
 $sc->SubjectConfirmationData->Recipient = $endpoint;
 $sc->SubjectConfirmationData->InResponseTo = $query->getId();
-$assertion->setSubjectConfirmation(array($sc));
+$assertion->setSubjectConfirmation([$sc]);
 
-sspmod_saml_Message::addSign($idpMetadata, $spMetadata, $assertion);
+\SimpleSAML\Module\saml\Message::addSign($idpMetadata, $spMetadata, $assertion);
 
 $response = new \SAML2\Response();
 $response->setRelayState($query->getRelayState());
 $response->setDestination($endpoint);
 $response->setIssuer($idpEntityId);
 $response->setInResponseTo($query->getId());
-$response->setAssertions(array($assertion));
-sspmod_saml_Message::addSign($idpMetadata, $spMetadata, $response);
+$response->setAssertions([$assertion]);
+\SimpleSAML\Module\saml\Message::addSign($idpMetadata, $spMetadata, $response);
 
 $binding = new \SAML2\HTTPPost();
 $binding->send($response);
diff --git a/modules/exampleauth/lib/Auth/Process/RedirectTest.php b/modules/exampleauth/lib/Auth/Process/RedirectTest.php
index 7e3e93ee03fae8c09354a4af286c8b4ac52ccc7a..13ff82dbd2e92a09d64943c2b2d938a09f7f3537 100644
--- a/modules/exampleauth/lib/Auth/Process/RedirectTest.php
+++ b/modules/exampleauth/lib/Auth/Process/RedirectTest.php
@@ -1,28 +1,30 @@
 <?php
 
+namespace SimpleSAML\Module\exampleautth\Auth\Process;
+
 /**
  * A simple processing filter for testing that redirection works as it should.
  *
  */
-class sspmod_exampleauth_Auth_Process_RedirectTest extends SimpleSAML_Auth_ProcessingFilter {
-
-
-	/**
-	 * Initialize processing of the redirect test.
-	 *
-	 * @param array &$state  The state we should update.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-		assert(array_key_exists('Attributes', $state));
 
-		// To check whether the state is saved correctly
-		$state['Attributes']['RedirectTest1'] = array('OK');
+class RedirectTest extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Initialize processing of the redirect test.
+     *
+     * @param array &$state  The state we should update.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+        assert(array_key_exists('Attributes', $state));
 
-		// Save state and redirect
-		$id = SimpleSAML_Auth_State::saveState($state, 'exampleauth:redirectfilter-test');
-		$url = SimpleSAML\Module::getModuleURL('exampleauth/redirecttest.php');
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-	}
+        // To check whether the state is saved correctly
+        $state['Attributes']['RedirectTest1'] = ['OK'];
 
+        // Save state and redirect
+        $id = \SimpleSAML\Auth\State::saveState($state, 'exampleauth:redirectfilter-test');
+        $url = \SimpleSAML\Module::getModuleURL('exampleauth/redirecttest.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+    }
 }
diff --git a/modules/exampleauth/lib/Auth/Source/External.php b/modules/exampleauth/lib/Auth/Source/External.php
index 6b37a541a54a569627074c034959d0d2e2f41fd9..fef113edb9ed6a4fe6375a8baf614ea072bb1162 100644
--- a/modules/exampleauth/lib/Auth/Source/External.php
+++ b/modules/exampleauth/lib/Auth/Source/External.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\exampleauth\Auth\Source;
+
 /**
  * Example external authentication source.
  *
@@ -20,253 +22,255 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_exampleauth_Auth_Source_External extends SimpleSAML_Auth_Source {
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		// Do any other configuration we need here
-	}
-
-
-	/**
-	 * Retrieve attributes for the user.
-	 *
-	 * @return array|NULL  The user's attributes, or NULL if the user isn't authenticated.
-	 */
-	private function getUser() {
-
-		/*
-		 * In this example we assume that the attributes are
-		 * stored in the users PHP session, but this could be replaced
-		 * with anything.
-		 */
-
-		if (!session_id()) {
-			/* session_start not called before. Do it here. */
-			session_start();
-		}
-
-		if (!isset($_SESSION['uid'])) {
-			/* The user isn't authenticated. */
-			return NULL;
-		}
-
-		/*
-		 * Find the attributes for the user.
-		 * Note that all attributes in SimpleSAMLphp are multivalued, so we need
-		 * to store them as arrays.
-		 */
-
-		$attributes = array(
-			'uid' => array($_SESSION['uid']),
-			'displayName' => array($_SESSION['name']),
-			'mail' => array($_SESSION['mail']),
-		);
-
-		/* Here we generate a multivalued attribute based on the account type. */
-		$attributes['eduPersonAffiliation'] = array(
-			$_SESSION['type'], /* In this example, either 'student' or 'employee'. */
-			'member',
-		);
-
-		return $attributes;
-	}
-
-
-	/**
-	 * Log in using an external authentication helper.
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		$attributes = $this->getUser();
-		if ($attributes !== NULL) {
-			/*
-			 * The user is already authenticated.
-			 *
-			 * Add the users attributes to the $state-array, and return control
-			 * to the authentication process.
-			 */
-			$state['Attributes'] = $attributes;
-			return;
-		}
-
-		/*
-		 * The user isn't authenticated. We therefore need to
-		 * send the user to the login page.
-		 */
-
-		/*
-		 * First we add the identifier of this authentication source
-		 * to the state array, so that we know where to resume.
-		 */
-		$state['exampleauth:AuthID'] = $this->authId;
-
-
-		/*
-		 * We need to save the $state-array, so that we can resume the
-		 * login process after authentication.
-		 *
-		 * Note the second parameter to the saveState-function. This is a
-		 * unique identifier for where the state was saved, and must be used
-		 * again when we retrieve the state.
-		 *
-		 * The reason for it is to prevent
-		 * attacks where the user takes a $state-array saved in one location
-		 * and restores it in another location, and thus bypasses steps in
-		 * the authentication process.
-		 */
-		$stateId = SimpleSAML_Auth_State::saveState($state, 'exampleauth:External');
-
-		/*
-		 * Now we generate a URL the user should return to after authentication.
-		 * We assume that whatever authentication page we send the user to has an
-		 * option to return the user to a specific page afterwards.
-		 */
-		$returnTo = SimpleSAML\Module::getModuleURL('exampleauth/resume.php', array(
-			'State' => $stateId,
-		));
-
-		/*
-		 * Get the URL of the authentication page.
-		 *
-		 * Here we use the getModuleURL function again, since the authentication page
-		 * is also part of this module, but in a real example, this would likely be
-		 * the absolute URL of the login page for the site.
-		 */
-		$authPage = SimpleSAML\Module::getModuleURL('exampleauth/authpage.php');
-
-		/*
-		 * The redirect to the authentication page.
-		 *
-		 * Note the 'ReturnTo' parameter. This must most likely be replaced with
-		 * the real name of the parameter for the login page.
-		 */
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($authPage, array(
-			'ReturnTo' => $returnTo,
-		));
-
-		/*
-		 * The redirect function never returns, so we never get this far.
-		 */
-		assert(false);
-	}
-
-
-	/**
-	 * Resume authentication process.
-	 *
-	 * This function resumes the authentication process after the user has
-	 * entered his or her credentials.
-	 *
-	 * @param array &$state  The authentication state.
-	 */
-	public static function resume() {
-
-		/*
-		 * First we need to restore the $state-array. We should have the identifier for
-		 * it in the 'State' request parameter.
-		 */
-		if (!isset($_REQUEST['State'])) {
-			throw new SimpleSAML_Error_BadRequest('Missing "State" parameter.');
-		}
-
-		/*
-		 * Once again, note the second parameter to the loadState function. This must
-		 * match the string we used in the saveState-call above.
-		 */
-		$state = SimpleSAML_Auth_State::loadState($_REQUEST['State'], 'exampleauth:External');
-
-		/*
-		 * Now we have the $state-array, and can use it to locate the authentication
-		 * source.
-		 */
-		$source = SimpleSAML_Auth_Source::getById($state['exampleauth:AuthID']);
-		if ($source === NULL) {
-			/*
-			 * The only way this should fail is if we remove or rename the authentication source
-			 * while the user is at the login page.
-			 */
-			throw new SimpleSAML_Error_Exception('Could not find authentication source with id ' . $state[self::AUTHID]);
-		}
-
-		/*
-		 * Make sure that we haven't switched the source type while the
-		 * user was at the authentication page. This can only happen if we
-		 * change config/authsources.php while an user is logging in.
-		 */
-		if (! ($source instanceof self)) {
-			throw new SimpleSAML_Error_Exception('Authentication source type changed.');
-		}
-
-
-		/*
-		 * OK, now we know that our current state is sane. Time to actually log the user in.
-		 *
-		 * First we check that the user is acutally logged in, and didn't simply skip the login page.
-		 */
-		$attributes = $source->getUser();
-		if ($attributes === NULL) {
-			/*
-			 * The user isn't authenticated.
-			 *
-			 * Here we simply throw an exception, but we could also redirect the user back to the
-			 * login page.
-			 */
-			throw new SimpleSAML_Error_Exception('User not authenticated after login page.');
-		}
-
-		/*
-		 * So, we have a valid user. Time to resume the authentication process where we
-		 * paused it in the authenticate()-function above.
-		 */
-
-		$state['Attributes'] = $attributes;
-		SimpleSAML_Auth_Source::completeAuth($state);
-
-		/*
-		 * The completeAuth-function never returns, so we never get this far.
-		 */
-		assert(false);
-	}
-
-
-	/**
-	 * This function is called when the user start a logout operation, for example
-	 * by logging out of a SP that supports single logout.
-	 *
-	 * @param array &$state  The logout state array.
-	 */
-	public function logout(&$state) {
-		assert(is_array($state));
-
-		if (!session_id()) {
-			/* session_start not called before. Do it here. */
-			session_start();
-		}
-
-		/*
-		 * In this example we simply remove the 'uid' from the session.
-		 */
-		unset($_SESSION['uid']);
-
-		/*
-		 * If we need to do a redirect to a different page, we could do this
-		 * here, but in this example we don't need to do this.
-		 */
-	}
 
+class External extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = 'SimpleSAML\Module\exampleautth\Auth\Sourc\External.AuthId';
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        // Do any other configuration we need here
+    }
+
+    /**
+     * Retrieve attributes for the user.
+     *
+     * @return array|NULL  The user's attributes, or NULL if the user isn't authenticated.
+     */
+    private function getUser()
+    {
+        /*
+         * In this example we assume that the attributes are
+         * stored in the users PHP session, but this could be replaced
+         * with anything.
+         */
+
+        if (!session_id()) {
+            // session_start not called before. Do it here
+            session_start();
+        }
+
+        if (!isset($_SESSION['uid'])) {
+            // The user isn't authenticated
+            return null;
+        }
+
+        /*
+         * Find the attributes for the user.
+         * Note that all attributes in SimpleSAMLphp are multivalued, so we need
+         * to store them as arrays.
+         */
+
+        $attributes = [
+            'uid' => [$_SESSION['uid']],
+            'displayName' => [$_SESSION['name']],
+            'mail' => [$_SESSION['mail']],
+        ];
+
+        // Here we generate a multivalued attribute based on the account type
+        $attributes['eduPersonAffiliation'] = [
+            $_SESSION['type'], /* In this example, either 'student' or 'employee'. */
+            'member',
+        ];
+
+        return $attributes;
+    }
+
+    /**
+     * Log in using an external authentication helper.
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+
+        $attributes = $this->getUser();
+        if ($attributes !== null) {
+            /*
+             * The user is already authenticated.
+             *
+             * Add the users attributes to the $state-array, and return control
+             * to the authentication process.
+             */
+            $state['Attributes'] = $attributes;
+            return;
+        }
+
+        /*
+         * The user isn't authenticated. We therefore need to
+         * send the user to the login page.
+         */
+
+        /*
+         * First we add the identifier of this authentication source
+         * to the state array, so that we know where to resume.
+         */
+        $state['exampleauth:AuthID'] = self::AUTHID;
+
+        /*
+         * We need to save the $state-array, so that we can resume the
+         * login process after authentication.
+         *
+         * Note the second parameter to the saveState-function. This is a
+         * unique identifier for where the state was saved, and must be used
+         * again when we retrieve the state.
+         *
+         * The reason for it is to prevent
+         * attacks where the user takes a $state-array saved in one location
+         * and restores it in another location, and thus bypasses steps in
+         * the authentication process.
+         */
+        $stateId = \SimpleSAML\Auth\State::saveState($state, 'exampleauth:External');
+
+        /*
+         * Now we generate a URL the user should return to after authentication.
+         * We assume that whatever authentication page we send the user to has an
+         * option to return the user to a specific page afterwards.
+         */
+        $returnTo = \SimpleSAML\Module::getModuleURL('exampleauth/resume.php', [
+            'State' => $stateId,
+        ]);
+
+        /*
+         * Get the URL of the authentication page.
+         *
+         * Here we use the getModuleURL function again, since the authentication page
+         * is also part of this module, but in a real example, this would likely be
+         * the absolute URL of the login page for the site.
+         */
+        $authPage = \SimpleSAML\Module::getModuleURL('exampleauth/authpage.php');
+
+        /*
+         * The redirect to the authentication page.
+         *
+         * Note the 'ReturnTo' parameter. This must most likely be replaced with
+         * the real name of the parameter for the login page.
+         */
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($authPage, [
+            'ReturnTo' => $returnTo,
+        ]);
+
+        /*
+         * The redirect function never returns, so we never get this far.
+         */
+        assert(false);
+    }
+
+    /**
+     * Resume authentication process.
+     *
+     * This function resumes the authentication process after the user has
+     * entered his or her credentials.
+     *
+     * @param array &$state  The authentication state.
+     */
+    public static function resume()
+    {
+        /*
+         * First we need to restore the $state-array. We should have the identifier for
+         * it in the 'State' request parameter.
+         */
+        if (!isset($_REQUEST['State'])) {
+            throw new \SimpleSAML\Error\BadRequest('Missing "State" parameter.');
+        }
+
+        /*
+         * Once again, note the second parameter to the loadState function. This must
+         * match the string we used in the saveState-call above.
+         */
+        $state = \SimpleSAML\Auth\State::loadState($_REQUEST['State'], 'exampleauth:External');
+
+        /*
+         * Now we have the $state-array, and can use it to locate the authentication
+         * source.
+         */
+        $source = \SimpleSAML\Auth\Source::getById($state['exampleauth:AuthID']);
+        if ($source === null) {
+            /*
+             * The only way this should fail is if we remove or rename the authentication source
+             * while the user is at the login page.
+             */
+            throw new \SimpleSAML\Error\Exception('Could not find authentication source with id '.$state[self::AUTHID]);
+        }
+
+        /*
+         * Make sure that we haven't switched the source type while the
+         * user was at the authentication page. This can only happen if we
+         * change config/authsources.php while an user is logging in.
+         */
+        if (!($source instanceof self)) {
+            throw new \SimpleSAML\Error\Exception('Authentication source type changed.');
+        }
+
+        /*
+         * OK, now we know that our current state is sane. Time to actually log the user in.
+         *
+         * First we check that the user is acutally logged in, and didn't simply skip the login page.
+         */
+        $attributes = $source->getUser();
+        if ($attributes === null) {
+            /*
+             * The user isn't authenticated.
+             *
+             * Here we simply throw an exception, but we could also redirect the user back to the
+             * login page.
+             */
+            throw new \SimpleSAML\Error\Exception('User not authenticated after login page.');
+        }
+
+        /*
+         * So, we have a valid user. Time to resume the authentication process where we
+         * paused it in the authenticate()-function above.
+         */
+
+        $state['Attributes'] = $attributes;
+        \SimpleSAML\Auth\Source::completeAuth($state);
+
+        /*
+         * The completeAuth-function never returns, so we never get this far.
+         */
+        assert(false);
+    }
+
+    /**
+     * This function is called when the user start a logout operation, for example
+     * by logging out of a SP that supports single logout.
+     *
+     * @param array &$state  The logout state array.
+     */
+    public function logout(&$state)
+    {
+        assert(is_array($state));
+
+        if (!session_id()) {
+            // session_start not called before. Do it here
+            session_start();
+        }
+
+        /*
+         * In this example we simply remove the 'uid' from the session.
+         */
+        unset($_SESSION['uid']);
+
+        /*
+         * If we need to do a redirect to a different page, we could do this
+         * here, but in this example we don't need to do this.
+         */
+    }
 }
diff --git a/modules/exampleauth/lib/Auth/Source/Static.php b/modules/exampleauth/lib/Auth/Source/Static.php
deleted file mode 100644
index 8c5eba05715bceea091c129b8ec79e56f8d722dd..0000000000000000000000000000000000000000
--- a/modules/exampleauth/lib/Auth/Source/Static.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-/**
- * Example authentication source.
- *
- * This class is an example authentication source which will always return a user with
- * a static set of attributes.
- *
- * @author Olav Morken, UNINETT AS.
- * @package SimpleSAMLphp
- */
-class sspmod_exampleauth_Auth_Source_Static extends SimpleSAML_Auth_Source {
-
-
-	/**
-	 * The attributes we return.
-	 */
-	private $attributes;
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-
-		// Parse attributes
-		try {
-			$this->attributes = SimpleSAML\Utils\Attributes::normalizeAttributesArray($config);
-		} catch(Exception $e) {
-			throw new Exception('Invalid attributes for authentication source ' .
-				$this->authId . ': ' . $e->getMessage());
-		}
-
-	}
-
-
-	/**
-	 * Log in using static attributes.
-	 *
-	 * @param array &$state  Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		$state['Attributes'] = $this->attributes;
-	}
-
-}
diff --git a/modules/exampleauth/lib/Auth/Source/StaticSource.php b/modules/exampleauth/lib/Auth/Source/StaticSource.php
new file mode 100644
index 0000000000000000000000000000000000000000..d81dd325638fe2c2e1f3e64d45ca329310115c54
--- /dev/null
+++ b/modules/exampleauth/lib/Auth/Source/StaticSource.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace SimpleSAML\Module\exampleauth\Auth\Source;
+
+/**
+ * Example authentication source.
+ *
+ * This class is an example authentication source which will always return a user with
+ * a static set of attributes.
+ *
+ * @author Olav Morken, UNINETT AS.
+ * @package SimpleSAMLphp
+ */
+
+class StaticSource extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The attributes we return.
+     */
+    private $attributes;
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        // Parse attributes
+        try {
+            $this->attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($config);
+        } catch (\Exception $e) {
+            throw new \Exception('Invalid attributes for authentication source '.
+                $this->authId.': '.$e->getMessage());
+        }
+    }
+
+    /**
+     * Log in using static attributes.
+     *
+     * @param array &$state  Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+        $state['Attributes'] = $this->attributes;
+    }
+}
diff --git a/modules/exampleauth/lib/Auth/Source/UserPass.php b/modules/exampleauth/lib/Auth/Source/UserPass.php
index 8582d1c7c989a28af3f233d18cb72c806f39d0b8..19da260bbdfa201c7bb86907da5a806e5002801b 100644
--- a/modules/exampleauth/lib/Auth/Source/UserPass.php
+++ b/modules/exampleauth/lib/Auth/Source/UserPass.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\exampleauth\Auth\Source;
+
 /**
  * Example authentication source - username & password.
  *
@@ -9,82 +11,81 @@
  * @author Olav Morken, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_exampleauth_Auth_Source_UserPass extends sspmod_core_Auth_UserPassBase {
-
-
-	/**
-	 * Our users, stored in an associative array. The key of the array is "<username>:<password>",
-	 * while the value of each element is a new array with the attributes for each user.
-	 */
-	private $users;
-
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info  Information about this authentication source.
-	 * @param array $config  Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		$this->users = array();
-
-		// Validate and parse our configuration
-		foreach ($config as $userpass => $attributes) {
-			if (!is_string($userpass)) {
-				throw new Exception('Invalid <username>:<password> for authentication source ' .
-					$this->authId . ': ' . $userpass);
-			}
-
-			$userpass = explode(':', $userpass, 2);
-			if (count($userpass) !== 2) {
-				throw new Exception('Invalid <username>:<password> for authentication source ' .
-					$this->authId . ': ' . $userpass[0]);
-			}
-			$username = $userpass[0];
-			$password = $userpass[1];
-
-			try {
-				$attributes = SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
-			} catch(Exception $e) {
-				throw new Exception('Invalid attributes for user ' . $username .
-					' in authentication source ' . $this->authId . ': ' .
-					$e->getMessage());
-			}
-
-			$this->users[$username . ':' . $password] = $attributes;
-		}
-	}
-
-
-	/**
-	 * Attempt to log in using the given username and password.
-	 *
-	 * On a successful login, this function should return the users attributes. On failure,
-	 * it should throw an exception. If the error was caused by the user entering the wrong
-	 * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
-	 *
-	 * Note that both the username and the password are UTF-8 encoded.
-	 *
-	 * @param string $username  The username the user wrote.
-	 * @param string $password  The password the user wrote.
-	 * @return array  Associative array with the users attributes.
-	 */
-	protected function login($username, $password) {
-		assert(is_string($username));
-		assert(is_string($password));
-
-		$userpass = $username . ':' . $password;
-		if (!array_key_exists($userpass, $this->users)) {
-			throw new SimpleSAML_Error_Error('WRONGUSERPASS');
-		}
-
-		return $this->users[$userpass];
-	}
 
+class UserPass extends \SimpleSAML\Module\core\Auth\UserPassBase
+{
+    /**
+     * Our users, stored in an associative array. The key of the array is "<username>:<password>",
+     * while the value of each element is a new array with the attributes for each user.
+     */
+    private $users;
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info  Information about this authentication source.
+     * @param array $config  Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        $this->users = [];
+
+        // Validate and parse our configuration
+        foreach ($config as $userpass => $attributes) {
+            if (!is_string($userpass)) {
+                throw new \Exception(
+                    'Invalid <username>:<password> for authentication source '.$this->authId.': '.$userpass
+                );
+            }
+
+            $userpass = explode(':', $userpass, 2);
+            if (count($userpass) !== 2) {
+                throw new \Exception(
+                    'Invalid <username>:<password> for authentication source '.$this->authId.': '.$userpass[0]
+                );
+            }
+            $username = $userpass[0];
+            $password = $userpass[1];
+
+            try {
+                $attributes = \SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes);
+            } catch (\Exception $e) {
+                throw new \Exception('Invalid attributes for user '.$username.
+                    ' in authentication source '.$this->authId.': '.$e->getMessage());
+            }
+            $this->users[$username.':'.$password] = $attributes;
+        }
+    }
+
+    /**
+     * Attempt to log in using the given username and password.
+     *
+     * On a successful login, this function should return the users attributes. On failure,
+     * it should throw an exception. If the error was caused by the user entering the wrong
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
+     *
+     * Note that both the username and the password are UTF-8 encoded.
+     *
+     * @param string $username  The username the user wrote.
+     * @param string $password  The password the user wrote.
+     * @return array  Associative array with the users attributes.
+     */
+    protected function login($username, $password)
+    {
+        assert(is_string($username));
+        assert(is_string($password));
+
+        $userpass = $username.':'.$password;
+        if (!array_key_exists($userpass, $this->users)) {
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
+        }
+
+        return $this->users[$userpass];
+    }
 }
diff --git a/modules/exampleauth/www/authpage.php b/modules/exampleauth/www/authpage.php
index 73fcb131ecd9df5ce0bd4b82a41ad5502e0e95a1..6c34995ec79627eb8e458e5aba5fe6eb858b8910 100644
--- a/modules/exampleauth/www/authpage.php
+++ b/modules/exampleauth/www/authpage.php
@@ -10,12 +10,11 @@
  */
 
 if (!isset($_REQUEST['ReturnTo'])) {
-	die('Missing ReturnTo parameter.');
+    die('Missing ReturnTo parameter.');
 }
 
 $returnTo = \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']);
 
-
 /*
  * The following piece of code would never be found in a real authentication page. Its
  * purpose in this example is to make this example safer in the case where the
@@ -27,9 +26,9 @@ $returnTo = \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['ReturnTo']);
  */
 
 if (!preg_match('@State=(.*)@', $returnTo, $matches)) {
-	die('Invalid ReturnTo URL for this example.');
+    die('Invalid ReturnTo URL for this example.');
 }
-SimpleSAML_Auth_State::loadState(urldecode($matches[1]), 'exampleauth:External');
+\SimpleSAML\Auth\State::loadState(urldecode($matches[1]), 'exampleauth:External');
 
 /*
  * The loadState-function will not return if the second parameter does not
@@ -37,59 +36,55 @@ SimpleSAML_Auth_State::loadState(urldecode($matches[1]), 'exampleauth:External')
  * through the exampleauth:External authentication page.
  */
 
-
 /*
  * Our list of users.
  */
-$users = array(
-	'student' => array(
-		'password' => 'student',
-		'uid' => 'student',
-		'name' => 'Student Name',
-		'mail' => 'somestudent@example.org',
-		'type' => 'student',
-	),
-	'admin' => array(
-		'password' => 'admin',
-		'uid' => 'admin',
-		'name' => 'Admin Name',
-		'mail' => 'someadmin@example.org',
-		'type' => 'employee',
-	),
-);
-
+$users = [
+    'student' => [
+        'password' => 'student',
+        'uid' => 'student',
+        'name' => 'Student Name',
+        'mail' => 'somestudent@example.org',
+        'type' => 'student',
+    ],
+    'admin' => [
+        'password' => 'admin',
+        'uid' => 'admin',
+        'name' => 'Admin Name',
+        'mail' => 'someadmin@example.org',
+        'type' => 'employee',
+    ],
+];
 
 /*
  * Time to handle login responses.
  * Since this is a dummy example, we accept any data.
  */
 
-$badUserPass = FALSE;
+$badUserPass = false;
 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-	$username = (string)$_REQUEST['username'];
-	$password = (string)$_REQUEST['password'];
-
-	if (!isset($users[$username]) || $users[$username]['password'] !== $password) {
-		$badUserPass = TRUE;
-	} else {
-
-		$user = $users[$username];
-
-		if (!session_id()) {
-			// session_start not called before. Do it here.
-			session_start();
-		}
-
-		$_SESSION['uid'] = $user['uid'];
-		$_SESSION['name'] = $user['name'];
-		$_SESSION['mail'] = $user['mail'];
-		$_SESSION['type'] = $user['type'];
-
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($returnTo);
-	}
+    $username = (string) $_REQUEST['username'];
+    $password = (string) $_REQUEST['password'];
+
+    if (!isset($users[$username]) || $users[$username]['password'] !== $password) {
+        $badUserPass = true;
+    } else {
+        $user = $users[$username];
+
+        if (!session_id()) {
+            // session_start not called before. Do it here.
+            session_start();
+        }
+
+        $_SESSION['uid'] = $user['uid'];
+        $_SESSION['name'] = $user['name'];
+        $_SESSION['mail'] = $user['mail'];
+        $_SESSION['type'] = $user['type'];
+
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($returnTo);
+    }
 }
 
-
 /*
  * If we get this far, we need to show the login page to the user.
  */
@@ -101,7 +96,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
 </head>
 <body>
 <h1>exampleauth login page</h1>
-<p>In this example you can log in with two accounts: <code>student</code> and <code>admin</code>. In both cases, the password is the same as the username.</p>
+<p>
+In this example you can log in with two accounts: <code>student</code> and <code>admin</code>.
+In both cases, the password is the same as the username.
+</p>
 <?php if ($badUserPass) { ?>
 <p>Bad username or password.</p>
 <?php } ?>
diff --git a/modules/exampleauth/www/redirecttest.php b/modules/exampleauth/www/redirecttest.php
index 96ff9a50f7bd3d229d9a32ca5f0fd48b9ed14ed0..9d605277d31a7f2c05508d1d01aa5e4bbf596d67 100644
--- a/modules/exampleauth/www/redirecttest.php
+++ b/modules/exampleauth/www/redirecttest.php
@@ -8,10 +8,10 @@
  */
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['StateId'], 'exampleauth:redirectfilter-test');
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['StateId'], 'exampleauth:redirectfilter-test');
 
-$state['Attributes']['RedirectTest2'] = array('OK');
+$state['Attributes']['RedirectTest2'] = ['OK'];
 
-SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+\SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
diff --git a/modules/exampleauth/www/resume.php b/modules/exampleauth/www/resume.php
index 08d66dd3f490d198e5467665d21204d8c6afd64b..192c13a20dceb45230de0044c7cf34a982f0864c 100644
--- a/modules/exampleauth/www/resume.php
+++ b/modules/exampleauth/www/resume.php
@@ -8,4 +8,7 @@
  *
  * @package SimpleSAMLphp
  */
-sspmod_exampleauth_Auth_Source_External::resume();
+
+namespace SimpleSAML\Module\exampleauth\Auth\Source;
+
+External::resume();
diff --git a/modules/expirycheck/lib/Auth/Process/ExpiryDate.php b/modules/expirycheck/lib/Auth/Process/ExpiryDate.php
index c315169fa97f29ec7079be03d925f06723de3332..ddd5befc1548c290914a389771a26f632087c33d 100644
--- a/modules/expirycheck/lib/Auth/Process/ExpiryDate.php
+++ b/modules/expirycheck/lib/Auth/Process/ExpiryDate.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\expirycheck\Auth\Process;
+
 /**
  * Filter which show "about to expire" warning or deny access if netid is expired.
  *
@@ -20,136 +22,139 @@
  * @package SimpleSAMLphp
  */
 
-class sspmod_expirycheck_Auth_Process_ExpiryDate extends SimpleSAML_Auth_ProcessingFilter {
-
-	private $warndaysbefore = 0;
-	private $netid_attr = NULL;
-	private $expirydate_attr = NULL;
-	private $date_format = 'd.m.Y';
-
-
-	/**
-	 * Initialize this filter.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
-
-		if (array_key_exists('warndaysbefore', $config)) {
-			$this->warndaysbefore = $config['warndaysbefore'];
-			if (!is_string($this->warndaysbefore)) {
-				throw new Exception('Invalid value for number of days given to expirycheck::ExpiryDate filter.');
-			}
-		}
-
-		if (array_key_exists('netid_attr', $config)) {
-			$this->netid_attr = $config['netid_attr'];
-			if (!is_string($this->netid_attr)) {
-				throw new Exception('Invalid attribute name given as eduPersonPrincipalName to expirycheck::ExpiryDate filter.');
-			}
-		}
-
-		if (array_key_exists('expirydate_attr', $config)) {
-			$this->expirydate_attr = $config['expirydate_attr'];
-			if (!is_string($this->expirydate_attr)) {
-				throw new Exception('Invalid attribute name given as schacExpiryDate to expirycheck::ExpiryDate filter.');
-			}
-		}
-
-		if (array_key_exists('date_format', $config)) {
-			$this->date_format = $config['date_format'];
-			if (!is_string($this->date_format)) {
-				throw new Exception('Invalid date format given to expirycheck::ExpiryDate filter.');
-			}
-		}
-	}
-
-	/**
-	 * Show expirational warning if remaining days is equal or under defined $warndaysbefore
-	 * @param integer $expireOnDate
-	 * @param integer $warndaysbefore
-	 * @return bool
-	 *
-	 */
-	public function shWarning(&$state, $expireOnDate, $warndaysbefore) {
-		$now = time();
-		$end = $expireOnDate;
-
-		if ($expireOnDate >= $now) {
-			$days = (int)(($end - $now) / (24*60*60));
-			if ($days <= $warndaysbefore) {
-				$state['daysleft'] = $days;
-				return true;
-			}
-		}
-		return false;
-	}
-
-	/**
-	 *  Check if given date is older than today
-	 *  @param integer $expireOnDate
-	 *  @return bool
-	 *
-	 */
-	public function checkDate($expireOnDate) {
-		$now = time();
-		$end = $expireOnDate;
-
-		if ($now <= $end) {
-			return true;
-		} else {
-			return false;
-		}
-
-	}
-
-	/**
-	 * Apply filter
-	 *
-	 * @param array &$state  The current state.
-	 */
-	public function process(&$state) {
-		/*
-		 * UTC format: 20090527080352Z
-		 */
-		$netId = $state['Attributes'][$this->netid_attr][0];
-		$expireOnDate = strtotime($state['Attributes'][$this->expirydate_attr][0]);
-
-		if (self::shWarning($state, $expireOnDate, $this->warndaysbefore)) {
-			assert(is_array($state));
-			if (isset($state['isPassive']) && $state['isPassive'] === TRUE) {
-				// We have a passive request. Skip the warning.
-				return;
-			}
-
-			SimpleSAML\Logger::warning('expirycheck: NetID ' . $netId .
-			                           ' is about to expire!');
-
-			// Save state and redirect
-			$state['expireOnDate'] = date($this->date_format, $expireOnDate);
-			$state['netId'] = $netId;
-			$id = SimpleSAML_Auth_State::saveState($state, 'expirywarning:about2expire');
-			$url = SimpleSAML\Module::getModuleURL('expirycheck/about2expire.php');
-			\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-		}
-
-		if (!self::checkDate($expireOnDate)) {
-			SimpleSAML\Logger::error('expirycheck: NetID ' . $netId .
-				' has expired [' . date($this->date_format, $expireOnDate) . ']. Access denied!');
-
-			/* Save state and redirect. */
-			$state['expireOnDate'] = date($this->date_format, $expireOnDate);
-			$state['netId'] = $netId;
-			$id = SimpleSAML_Auth_State::saveState($state, 'expirywarning:expired');
-			$url = SimpleSAML\Module::getModuleURL('expirycheck/expired.php');
-			\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-
-		}
-	}
-
-
+class ExpiryDate extends \SimpleSAML\Auth\ProcessingFilter
+{
+    private $warndaysbefore = 0;
+    private $netid_attr = null;
+    private $expirydate_attr = null;
+    private $date_format = 'd.m.Y';
+
+
+    /**
+     * Initialize this filter.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        if (array_key_exists('warndaysbefore', $config)) {
+            $this->warndaysbefore = $config['warndaysbefore'];
+            if (!is_string($this->warndaysbefore)) {
+                throw new \Exception('Invalid value for number of days given to expirycheck::ExpiryDate filter.');
+            }
+        }
+
+        if (array_key_exists('netid_attr', $config)) {
+            $this->netid_attr = $config['netid_attr'];
+            if (!is_string($this->netid_attr)) {
+                throw new \Exception(
+                    'Invalid attribute name given as eduPersonPrincipalName to expirycheck::ExpiryDate filter.'
+                );
+            }
+        }
+
+        if (array_key_exists('expirydate_attr', $config)) {
+            $this->expirydate_attr = $config['expirydate_attr'];
+            if (!is_string($this->expirydate_attr)) {
+                throw new \Exception(
+                    'Invalid attribute name given as schacExpiryDate to expirycheck::ExpiryDate filter.'
+                );
+            }
+        }
+
+        if (array_key_exists('date_format', $config)) {
+            $this->date_format = $config['date_format'];
+            if (!is_string($this->date_format)) {
+                throw new \Exception('Invalid date format given to expirycheck::ExpiryDate filter.');
+            }
+        }
+    }
+
+    /**
+     * Show expirational warning if remaining days is equal or under defined $warndaysbefore
+     * @param integer $expireOnDate
+     * @param integer $warndaysbefore
+     * @return bool
+     *
+     */
+    public function shWarning(&$state, $expireOnDate, $warndaysbefore)
+    {
+        $now = time();
+        $end = $expireOnDate;
+
+        if ($expireOnDate >= $now) {
+            $days = (int) (($end - $now) / 86400); //24*60*60=86400
+            if ($days <= $warndaysbefore) {
+                $state['daysleft'] = $days;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     *  Check if given date is older than today
+     *  @param integer $expireOnDate
+     *  @return bool
+     *
+     */
+    public function checkDate($expireOnDate)
+    {
+        $now = time();
+        $end = $expireOnDate;
+
+        if ($now <= $end) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Apply filter
+     *
+     * @param array &$state  The current state.
+     */
+    public function process(&$state)
+    {
+        /*
+         * UTC format: 20090527080352Z
+         */
+        $netId = $state['Attributes'][$this->netid_attr][0];
+        $expireOnDate = strtotime($state['Attributes'][$this->expirydate_attr][0]);
+
+        if ($this->shWarning($state, $expireOnDate, $this->warndaysbefore)) {
+            assert(is_array($state));
+            if (isset($state['isPassive']) && $state['isPassive'] === true) {
+                // We have a passive request. Skip the warning.
+                return;
+            }
+
+            \SimpleSAML\Logger::warning('expirycheck: NetID '.$netId.' is about to expire!');
+
+            // Save state and redirect
+            $state['expireOnDate'] = date($this->date_format, $expireOnDate);
+            $state['netId'] = $netId;
+            $id = \SimpleSAML\Auth\State::saveState($state, 'expirywarning:about2expire');
+            $url = \SimpleSAML\Module::getModuleURL('expirycheck/about2expire.php');
+            \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+        }
+
+        if (!$this->checkDate($expireOnDate)) {
+            \SimpleSAML\Logger::error('expirycheck: NetID '.$netId.
+                ' has expired ['.date($this->date_format, $expireOnDate).']. Access denied!');
+
+            /* Save state and redirect. */
+            $state['expireOnDate'] = date($this->date_format, $expireOnDate);
+            $state['netId'] = $netId;
+            $id = \SimpleSAML\Auth\State::saveState($state, 'expirywarning:expired');
+            $url = \SimpleSAML\Module::getModuleURL('expirycheck/expired.php');
+            \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+        }
+    }
 }
diff --git a/modules/expirycheck/templates/about2expire.php b/modules/expirycheck/templates/about2expire.php
index e2be96973a3344bac195bbc1ada897dcdede511c..6b135f807f5eb1e5332e136dda9280efa50f8bbd 100644
--- a/modules/expirycheck/templates/about2expire.php
+++ b/modules/expirycheck/templates/about2expire.php
@@ -16,72 +16,24 @@
  * @package SimpleSAMLphp
  */
 
-# netid will expire today
-if ($this->data['daysleft'] == 0) {
-	$this->data['header'] = $this->t('{expirycheck:expwarning:warning_header_today}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId'])
-			));
-
-	$warning = $this->t('{expirycheck:expwarning:warning_today}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId'])
-			));
-
-}
-# netid will expire in one day
-elseif ($this->data['daysleft'] == 1) {
-
-	$this->data['header'] = $this->t('{expirycheck:expwarning:warning_header}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId']),
-				'%DAYS%' => $this->t('{expirycheck:expwarning:day}'),
-				'%DAYSLEFT%' => htmlspecialchars($this->data['daysleft']),
-			));
-
-	$warning = $this->t('{expirycheck:expwarning:warning}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId']),
-				'%DAYS%' => $this->t('{expirycheck:expwarning:day}'),
-				'%DAYSLEFT%' => htmlspecialchars($this->data['daysleft']),
-			));
-
-}
-# netid will expire in next <daysleft> days
-else {
-	$this->data['header'] = $this->t('{expirycheck:expwarning:warning_header}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId']),
-				'%DAYS%' => $this->t('{expirycheck:expwarning:days}'),
-				'%DAYSLEFT%' => htmlspecialchars($this->data['daysleft']),
-			));
-
-	$warning = $this->t('{expirycheck:expwarning:warning}', array(
-				'%NETID%' => htmlspecialchars($this->data['netId']),
-				'%DAYS%' => $this->t('{expirycheck:expwarning:days}'),
-				'%DAYSLEFT%' => htmlspecialchars($this->data['daysleft']),
-			));
-
-
-}
-
 $this->data['autofocus'] = 'yesbutton';
-
 $this->includeAtTemplateBase('includes/header.php');
 
-?>
-
-<form style="display: inline; margin: 0px; padding: 0px" action="<?php echo htmlspecialchars($this->data['yesTarget']); ?>">
+$yesTarget = htmlspecialchars($this->data['yesTarget']);
+$buttonContinue = htmlspecialchars($this->t('{expirycheck:expwarning:btn_continue}'));
 
-	<?php
-		// Embed hidden fields...
-		foreach ($this->data['yesData'] as $name => $value) {
-			echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
-		}
-	?>
-	<h3><?php echo $warning; ?></h3>
-	<p><?php echo $this->t('{expirycheck:expwarning:expiry_date_text}') . " " . $this->data['expireOnDate']; ?></p>
-
-	<input type="submit" name="yes" id="yesbutton" value="<?php echo htmlspecialchars($this->t('{expirycheck:expwarning:btn_continue}')) ?>" />
+echo '<form style="display: inline; margin: 0px; padding: 0px" action="'.$yesTarget.'">';
+// Embed hidden fields...
+foreach ($this->data['yesData'] as $name => $value) {
+    echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
+}
+?>
 
+<h3><?php echo $warning; ?></h3>
+<p><?php echo $this->t('{expirycheck:expwarning:expiry_date_text}')." ".$this->data['expireOnDate']; ?></p>
+<input type="submit" name="yes" id="yesbutton" value="<?php echo $buttonContinue; ?>" />
 </form>
 
-
 <?php
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/expirycheck/templates/about2expire.twig b/modules/expirycheck/templates/about2expire.twig
new file mode 100644
index 0000000000000000000000000000000000000000..1e1d5d427323c00833c54872611c890ee309f485
--- /dev/null
+++ b/modules/expirycheck/templates/about2expire.twig
@@ -0,0 +1,13 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <form style="display: inline; margin: 0px; padding: 0px" action="{{ yesTarget|escape('html') }}">
+        {% for name, value in yesData %}
+        <input type="hidden" name="{{ name|escape('html') }}" value="{{ value|escape('html') }}">
+        {% endfor %}
+        <h3>{{ warning }}</h3>
+        <p>{{ '{expirycheck:expwarning:expiry_date_text}'|trans }} {{ expireOnDate }}</p>
+        <input type="submit" name="yes" id="yesbutton" value="{{ '{expirycheck:expwarning:btn_continue}'|trans }}" autofocus>
+    </form>
+{% endblock %}
diff --git a/modules/expirycheck/templates/expired.php b/modules/expirycheck/templates/expired.php
index 2095d809926fd1347c80ccb340fc9eb8a0bd72e3..2e0e660201ee09c97dcd1a40ff75f2d5012b2f6f 100644
--- a/modules/expirycheck/templates/expired.php
+++ b/modules/expirycheck/templates/expired.php
@@ -2,10 +2,19 @@
 $this->data['header'] = $this->t('{expirycheck:expwarning:access_denied}');
 $this->includeAtTemplateBase('includes/header.php');
 ?>
-
-		<h2><?php echo $this->t('{expirycheck:expwarning:access_denied}');?></h2>
-		<p><?php echo $this->t('{expirycheck:expwarning:no_access_to}', array('%NETID%' => htmlspecialchars($this->data['netId'])));?></p> 
-		<p><?php echo $this->t('{expirycheck:expwarning:expiry_date_text}');?> <b><?php echo htmlspecialchars($this->data['expireOnDate']);?></b></p>
-		<p><?php echo $this->t('{expirycheck:expwarning:contact_home}');?></p>
+        <h2><?php echo $this->t('{expirycheck:expwarning:access_denied}'); ?></h2>
+        <p>
+            <?php
+                echo $this->t(
+                    '{expirycheck:expwarning:no_access_to}',
+                    ['%NETID%' => htmlspecialchars($this->data['netId'])]
+                );
+            ?>
+        </p> 
+        <p>
+            <?php echo $this->t('{expirycheck:expwarning:expiry_date_text}'); ?>
+            <b><?php echo htmlspecialchars($this->data['expireOnDate']); ?></b>
+        </p>
+        <p><?php echo $this->t('{expirycheck:expwarning:contact_home}'); ?></p>
 <?php
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/expirycheck/templates/expired.twig b/modules/expirycheck/templates/expired.twig
new file mode 100644
index 0000000000000000000000000000000000000000..8c0cecbc116646505319812cd30ecb088c069ae7
--- /dev/null
+++ b/modules/expirycheck/templates/expired.twig
@@ -0,0 +1,9 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ '{expirycheck:expwarning:access_denied}'|trans }})</h2>
+    <p>{{ '{expirycheck:expwarning:no_access_to}'|trans({'%NETID%': netId}, "app") }}</p>
+    <p>{{ '{expirycheck:expwarning:expiry_date_text}'|trans }} <b>{{ expireOnDate }}</b></p>
+    <p>{{ '{expirycheck:expwarning:contact_home}'|trans }}</p>
+{% endblock %}
diff --git a/modules/expirycheck/www/about2expire.php b/modules/expirycheck/www/about2expire.php
index 089d82985956d9fdc2e94c4f632efc830bfeb041..1f1766c7e7ad14dbb10c8a8f3c2aebf02149e348 100644
--- a/modules/expirycheck/www/about2expire.php
+++ b/modules/expirycheck/www/about2expire.php
@@ -6,25 +6,64 @@
  * @package SimpleSAMLphp
  */
 
-SimpleSAML\Logger::info('expirycheck - User has been warned that NetID is near to expirational date.');
+\SimpleSAML\Logger::info('expirycheck - User has been warned that NetID is near to expirational date.');
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'expirywarning:about2expire');
+$state = \SimpleSAML\Auth\State::loadState($id, 'expirywarning:about2expire');
 
 if (array_key_exists('yes', $_REQUEST)) {
-	// The user has pressed the yes-button
-	SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+    // The user has pressed the yes-button
+    \SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'expirycheck:about2expire.php');
-$t->data['yesTarget'] = SimpleSAML\Module::getModuleURL('expirycheck/about2expire.php');
-$t->data['yesData'] = array('StateId' => $id);
-$t->data['daysleft'] = $state['daysleft'];
+$daysleft = $state['daysleft'];
+
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'expirycheck:about2expire.php');
+$t->data['autofocus'] = 'yesbutton';
+$t->data['yesTarget'] = \SimpleSAML\Module::getModuleURL('expirycheck/about2expire.php');
+$t->data['yesData'] = ['StateId' => $id];
+$t->data['warning'] = $warning;
 $t->data['expireOnDate'] = $state['expireOnDate'];
 $t->data['netId'] = $state['netId'];
+
+if ($daysleft == 0) {
+    # netid will expire today
+    $this->data['header'] = $this->t('{expirycheck:expwarning:warning_header_today}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId'])
+                        ]);
+    $this->data['warning'] = $this->t('{expirycheck:expwarning:warning_today}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId'])
+                        ]);
+} elseif ($daysleft == 1) {
+    # netid will expire in one day
+
+    $this->data['header'] = $this->t('{expirycheck:expwarning:warning_header}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId']),
+                                '%DAYS%' => $this->t('{expirycheck:expwarning:day}'),
+                                '%DAYSLEFT%' => htmlspecialchars($daysleft),
+                        ]);
+    $this->data['warning'] = $this->t('{expirycheck:expwarning:warning}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId']),
+                                '%DAYS%' => $this->t('{expirycheck:expwarning:day}'),
+                                '%DAYSLEFT%' => htmlspecialchars($daysleft),
+                        ]);
+} else {
+    # netid will expire in next <daysleft> days
+    $this->data['header'] = $this->t('{expirycheck:expwarning:warning_header}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId']),
+                                '%DAYS%' => $this->t('{expirycheck:expwarning:days}'),
+                                '%DAYSLEFT%' => htmlspecialchars($daysleft),
+                        ]);
+    $this->data['warning'] = $this->t('{expirycheck:expwarning:warning}', [
+                                '%NETID%' => htmlspecialchars($this->data['netId']),
+                                '%DAYS%' => $this->t('{expirycheck:expwarning:days}'),
+                                '%DAYSLEFT%' => htmlspecialchars($daysleft),
+                        ]);
+}
+
 $t->show();
diff --git a/modules/expirycheck/www/expired.php b/modules/expirycheck/www/expired.php
index 87eef83dadb4a5bb2a7db2bb0090d1c8bdda020a..2d3d3b3e8d2d1f63dd164b11349183cccf999dbc 100644
--- a/modules/expirycheck/www/expired.php
+++ b/modules/expirycheck/www/expired.php
@@ -6,16 +6,16 @@
  * @package SimpleSAMLphp
  */
 
-SimpleSAML\Logger::info('expirycheck - User has been warned that NetID is near to expirational date.');
+\SimpleSAML\Logger::info('expirycheck - User has been warned that NetID is near to expirational date.');
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['StateId'], 'expirywarning:expired');
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['StateId'], 'expirywarning:expired');
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'expirycheck:expired.php');
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'expirycheck:expired.php');
 $t->data['expireOnDate'] = $state['expireOnDate'];
 $t->data['netId'] = $state['netId'];
 $t->show();
diff --git a/modules/ldap/docs/ldap.md b/modules/ldap/docs/ldap.md
index fae1ca1c6ae30d51f946d48a3a8ba4088b38c510..1bad69582b69d30162c4b1b1a7aff9bba7a74919 100644
--- a/modules/ldap/docs/ldap.md
+++ b/modules/ldap/docs/ldap.md
@@ -63,6 +63,12 @@ authentication source:
 		 */
 		'search.base' => 'ou=people,dc=example,dc=org',
 
+                /*
+                 * The scope of the search. Valid values are 'subtree' and 'onelevel' and 'base',
+                 * first one being the default if no value is set.
+                 */
+                'search.scope' => 'subtree',
+
 		/*
 		 * The attribute(s) the username should match against.
 		 *
@@ -94,7 +100,7 @@ You also need to update the `hostname` and `dnpattern` options. The
 `hostname` should be the hostname of your LDAP server, and the
 `dnpattern` should be a pattern which can be used to generate the `dn`
 of a user with a given username.
-
+-
 All other options have default values, and are not required.
 
 ### Searching for a user ###
diff --git a/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php b/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
index e788d268906f944afddb984aa30d039c405d754a..a1062376d98df4ba15fcce8c74d0b4ccb005a5a7 100644
--- a/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
+++ b/modules/ldap/lib/Auth/Process/AttributeAddFromLDAP.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap\Auth\Process;
+
 /**
  * Filter to add attributes to the identity by executing a query against an LDAP directory
  *
@@ -32,9 +34,9 @@
  * @author Remy Blom <remy.blom@hku.nl>
  * @package SimpleSAMLphp
  */
-class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Process_BaseFilter
-{
 
+class AttributeAddFromLDAP extends BaseFilter
+{
     /**
      * LDAP attributes to add to the request attributes
      *
@@ -118,7 +120,7 @@ class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Pro
         parent::__construct($config, $reserved);
 
         // Get filter specific config options
-        $this->search_attributes = $this->config->getArrayize('attributes', array());
+        $this->search_attributes = $this->config->getArrayize('attributes', []);
         if (empty($this->search_attributes)) {
             $new_attribute = $this->config->getString('attribute.new', '');
             $this->search_attributes[$new_attribute] = $this->config->getString('search.attribute');
@@ -140,17 +142,17 @@ class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Pro
         assert(is_array($request));
         assert(array_key_exists('Attributes', $request));
 
-        $attributes =& $request['Attributes'];
+        $attributes = &$request['Attributes'];
 
         // perform a merge on the ldap_search_filter
         // loop over the attributes and build the search and replace arrays
-        $arrSearch = array();
-        $arrReplace = array();
+        $arrSearch = [];
+        $arrReplace = [];
         foreach ($attributes as $attr => $val) {
             $arrSearch[] = '%'.$attr.'%';
 
             if (strlen($val[0]) > 0) {
-                $arrReplace[] = SimpleSAML_Auth_LDAP::escape_filter_value($val[0]);
+                $arrReplace[] = \SimpleSAML\Auth\LDAP::escape_filter_value($val[0]);
             } else {
                 $arrReplace[] = '';
             }
@@ -160,23 +162,23 @@ class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Pro
         $filter = str_replace($arrSearch, $arrReplace, $this->search_filter);
 
         if (strpos($filter, '%') !== false) {
-            SimpleSAML\Logger::info('AttributeAddFromLDAP: There are non-existing attributes in the search filter. ('.
-                                    $this->search_filter.')');
+            \SimpleSAML\Logger::info('AttributeAddFromLDAP: There are non-existing attributes in the search filter. ('.
+                $this->search_filter.')');
             return;
         }
 
-        if (!in_array($this->attr_policy, array('merge', 'replace', 'add'), true)) {
-            SimpleSAML\Logger::warning("AttributeAddFromLDAP: 'attribute.policy' must be one of 'merge',".
-                                       "'replace' or 'add'.");
+        if (!in_array($this->attr_policy, ['merge', 'replace', 'add'], true)) {
+            \SimpleSAML\Logger::warning("AttributeAddFromLDAP: 'attribute.policy' must be one of 'merge',".
+                "'replace' or 'add'.");
             return;
         }
 
         // getLdap
         try {
             $ldap = $this->getLdap();
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             // Added this warning in case $this->getLdap() fails
-            SimpleSAML\Logger::warning("AttributeAddFromLDAP: exception = " . $e);
+            \SimpleSAML\Logger::warning("AttributeAddFromLDAP: exception = ".$e);
             return;
         }
         // search for matching entries
@@ -188,7 +190,7 @@ class sspmod_ldap_Auth_Process_AttributeAddFromLDAP extends sspmod_ldap_Auth_Pro
                 true,
                 false
             );
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             return; // silent fail, error is still logged by LDAP search
         }
 
diff --git a/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php b/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
index c263db0e66386f1ab3bf3585d5a47331f23d5fce..6101e7b162921c732d4db64baab3ca827f0c9eb1 100644
--- a/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
+++ b/modules/ldap/lib/Auth/Process/AttributeAddUsersGroups.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap\Auth\Process;
+
 /**
  * Does a reverse membership lookup on the logged in user,
  * looking for groups it is a member of and adds them to
@@ -8,7 +10,8 @@
  * @author Ryan Panning <panman@traileyes.com>
  * @package SimpleSAMLphp
  */
-class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_Process_BaseFilter
+
+class AttributeAddUsersGroups extends BaseFilter
 {
     /**
      * This is run when the filter is processed by SimpleSAML.
@@ -16,7 +19,7 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
      * the best method possible for the LDAP product. The groups
      * are then added to the request attributes.
      *
-     * @throws SimpleSAML_Error_Exception
+     * @throws \SimpleSAML\Error\Exception
      * @param $request
      */
     public function process(&$request)
@@ -25,39 +28,39 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
         assert(array_key_exists('Attributes', $request));
 
         // Log the process
-        SimpleSAML\Logger::debug(
-            $this->title . 'Attempting to get the users groups...'
+        \SimpleSAML\Logger::debug(
+            $this->title.'Attempting to get the users groups...'
         );
 
         // Reference the attributes, just to make the names shorter
-        $attributes =& $request['Attributes'];
-        $map =& $this->attribute_map;
+        $attributes = &$request['Attributes'];
+        $map = &$this->attribute_map;
 
         // Get the users groups from LDAP
         $groups = $this->getGroups($attributes);
 
         // Make the array if it is not set already
         if (!isset($attributes[$map['groups']])) {
-            $attributes[$map['groups']] = array();
+            $attributes[$map['groups']] = [];
         }
 
         // Must be an array, else cannot merge groups
         if (!is_array($attributes[$map['groups']])) {
-            throw new SimpleSAML_Error_Exception(
-                $this->title . 'The group attribute [' . $map['groups'] .
-                '] is not an array of group DNs. ' . $this->var_export($attributes[$map['groups']])
+            throw new \SimpleSAML\Error\Exception(
+                $this->title.'The group attribute ['.$map['groups'].
+                '] is not an array of group DNs. '.$this->var_export($attributes[$map['groups']])
             );
         }
 
         // Add the users group(s)
-        $group_attribute =& $attributes[$map['groups']];
+        $group_attribute = &$attributes[$map['groups']];
         $group_attribute = array_merge($group_attribute, $groups);
         $group_attribute = array_unique($group_attribute);
 
         // All done
-        SimpleSAML\Logger::debug(
-            $this->title . 'Added users groups to the group attribute [' .
-            $map['groups'] . ']: ' . implode('; ', $groups)
+        \SimpleSAML\Logger::debug(
+            $this->title.'Added users groups to the group attribute ['.
+            $map['groups'].']: '.implode('; ', $groups)
         );
     }
 
@@ -69,15 +72,15 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
      * using the required attribute values from the user to
      * get their group membership, recursively.
      *
-     * @throws SimpleSAML_Error_Exception
+     * @throws \SimpleSAML\Error\Exception
      * @param array $attributes
      * @return array
      */
     protected function getGroups($attributes)
     {
         // Log the request
-        SimpleSAML\Logger::debug(
-            $this->title . 'Checking for groups based on the best method for the LDAP product.'
+        \SimpleSAML\Logger::debug(
+            $this->title.'Checking for groups based on the best method for the LDAP product.'
         );
 
         // Based on the directory service, search LDAP for groups
@@ -91,25 +94,26 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
                 break;
             default:
                 // Reference the map, just to make the name shorter
-                $map =& $this->attribute_map;
+                $map = &$this->attribute_map;
 
                 // Log the general search
-                SimpleSAML\Logger::debug(
-                    $this->title . 'Searching LDAP using the default search method.'
+                \SimpleSAML\Logger::debug(
+                    $this->title.'Searching LDAP using the default search method.'
                 );
 
                 // Make sure the defined memberOf attribute exists
                 if (!isset($attributes[$map['memberof']])) {
-                    throw new SimpleSAML_Error_Exception(
-                        $this->title . 'The memberof attribute [' . $map['memberof'] .
-                        '] is not defined in the user\'s Attributes: ' . implode(', ', array_keys($attributes)));
+                    throw new \SimpleSAML\Error\Exception(
+                        $this->title.'The memberof attribute ['.$map['memberof'].
+                        '] is not defined in the user\'s Attributes: '.implode(', ', array_keys($attributes))
+                    );
                 }
 
                 // MemberOf must be an array of group DN's
                 if (!is_array($attributes[$map['memberof']])) {
-                    throw new SimpleSAML_Error_Exception(
-                        $this->title . 'The memberof attribute [' . $map['memberof'] .
-                        '] is not an array of group DNs. ' . $this->var_export($attributes[$map['memberof']])
+                    throw new \SimpleSAML\Error\Exception(
+                        $this->title.'The memberof attribute ['.$map['memberof'].
+                        '] is not an array of group DNs. '.$this->var_export($attributes[$map['memberof']])
                     );
                 }
 
@@ -118,8 +122,8 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
         }
 
         // All done
-        SimpleSAML\Logger::debug(
-            $this->title . 'User found to be a member of the groups:' . implode('; ', $groups)
+        \SimpleSAML\Logger::debug(
+            $this->title.'User found to be a member of the groups:'.implode('; ', $groups)
         );
         return $groups;
     }
@@ -130,31 +134,38 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
      * using the required attribute values from the user to
      * get their group membership, recursively.
      *
-     * @throws SimpleSAML_Error_Exception
+     * @throws \SimpleSAML\Error\Exception
      * @param array $attributes
      * @return array
      */
     protected function getGroupsOpenLdap($attributes)
     {
         // Log the OpenLDAP specific search
-        SimpleSAML\Logger::debug(
-            $this->title . 'Searching LDAP using OpenLDAP specific method.'
+        \SimpleSAML\Logger::debug(
+            $this->title.'Searching LDAP using OpenLDAP specific method.'
         );
 
         // Reference the map, just to make the name shorter
-        $map =& $this->attribute_map;
+        $map = &$this->attribute_map;
 
         // Print group search string and search for all group names
-        $openldap_base = $this->config->getString('ldap.basedn','ou=groups,dc=example,dc=com');
-        SimpleSAML\Logger::debug(
-            $this->title . "Searching for groups in ldap.basedn ".$openldap_base." with filter (".$map['memberof']."=".$attributes[$map['username']][0].") and attributes ".$map['member']
+        $openldap_base = $this->config->getString('ldap.basedn', 'ou=groups,dc=example,dc=com');
+        \SimpleSAML\Logger::debug(
+            $this->title."Searching for groups in ldap.basedn ".$openldap_base." with filter (".$map['memberof'].
+            "=".$attributes[$map['username']][0].") and attributes ".$map['member']
         );
 
-        $groups = array();
+        $groups = [];
         try {
-            // Intention is to filter in 'ou=groups,dc=example,dc=com' for '(memberUid = <value of attribute.username>)' and take only the attributes 'cn' (=name of the group)
-            $all_groups = $this->getLdap()->searchformultiple($openldap_base, array($map['memberof'] => $attributes[$map['username']][0]) , array($map['member']));
-        } catch (SimpleSAML_Error_UserNotFound $e) {
+            /* Intention is to filter in 'ou=groups,dc=example,dc=com' for
+             * '(memberUid = <value of attribute.username>)' and take only the attributes 'cn' (=name of the group)
+             */
+            $all_groups = $this->getLdap()->searchformultiple(
+                $openldap_base,
+                [$map['memberof'] => $attributes[$map['username']][0]],
+                [$map['member']]
+            );
+        } catch (\SimpleSAML\Error\UserNotFound $e) {
             return $groups; // if no groups found return with empty (still just initialized) groups array
         }
 
@@ -172,32 +183,33 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
      * using the required attribute values from the user to
      * get their group membership, recursively.
      *
-     * @throws SimpleSAML_Error_Exception
+     * @throws \SimpleSAML\Error\Exception
      * @param array $attributes
      * @return array
      */
     protected function getGroupsActiveDirectory($attributes)
     {
         // Log the AD specific search
-        SimpleSAML\Logger::debug(
-            $this->title . 'Searching LDAP using ActiveDirectory specific method.'
+        \SimpleSAML\Logger::debug(
+            $this->title.'Searching LDAP using ActiveDirectory specific method.'
         );
 
         // Reference the map, just to make the name shorter
-        $map =& $this->attribute_map;
+        $map = &$this->attribute_map;
 
         // Make sure the defined dn attribute exists
         if (!isset($attributes[$map['dn']])) {
-            throw new SimpleSAML_Error_Exception(
-                $this->title . 'The DN attribute [' . $map['dn'] .
-                '] is not defined in the user\'s Attributes: ' . implode(', ', array_keys($attributes)));
+            throw new \SimpleSAML\Error\Exception(
+                $this->title.'The DN attribute ['.$map['dn'].
+                '] is not defined in the user\'s Attributes: '.implode(', ', array_keys($attributes))
+            );
         }
 
         // DN attribute must have a value
         if (!isset($attributes[$map['dn']][0]) || !$attributes[$map['dn']][0]) {
-            throw new SimpleSAML_Error_Exception(
-                $this->title . 'The DN attribute [' . $map['dn'] .
-                '] does not have a [0] value defined. ' . $this->var_export($attributes[$map['dn']])
+            throw new \SimpleSAML\Error\Exception(
+                $this->title.'The DN attribute ['.$map['dn'].
+                '] does not have a [0] value defined. '.$this->var_export($attributes[$map['dn']])
             );
         }
 
@@ -219,38 +231,45 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
         assert(is_array($memberof));
 
         // Used to determine what DN's have already been searched
-        static $searched = array();
+        static $searched = [];
 
         // Init the groups variable
-        $groups = array();
+        $groups = [];
 
         // Shorten the variable name
-        $map =& $this->attribute_map;
+        $map = &$this->attribute_map;
 
         // Log the search
-        SimpleSAML\Logger::debug(
-            $this->title . 'Checking DNs for groups.' .
-            ' DNs: '. implode('; ', $memberof) .
-            ' Attributes: ' . $map['memberof'] . ', ' . $map['type'] .
-            ' Group Type: ' . $this->type_map['group']
+        \SimpleSAML\Logger::debug(
+            $this->title.'Checking DNs for groups.'.
+            ' DNs: '.implode('; ', $memberof).
+            ' Attributes: '.$map['memberof'].', '.$map['type'].
+            ' Group Type: '.$this->type_map['group']
         );
 
+        // Work out what attributes to get for a group
+        $use_group_name = false;
+        $get_attributes = [$map['memberof'], $map['type']];
+        if (isset($map['name']) && $map['name']) {
+            $get_attributes[] = $map['name'];
+            $use_group_name = false;
+        }
+
         // Check each DN of the passed memberOf
         foreach ($memberof as $dn) {
-
             // Avoid infinite loops, only need to check a DN once
             if (isset($searched[$dn])) {
                 continue;
             }
 
             // Track all DN's that are searched
-            // Use DN for key as well, isset() is faster than in_array()
+            // Use DN for key as well, isset() is faster than in_[]
             $searched[$dn] = $dn;
 
             // Query LDAP for the attribute values for the DN
             try {
-                $attributes = $this->getLdap()->getAttributes($dn, array($map['memberof'], $map['type']));
-            } catch (SimpleSAML_Error_AuthSource $e) {
+                $attributes = $this->getLdap()->getAttributes($dn, $get_attributes);
+            } catch (\SimpleSAML\Error\AuthSource $e) {
                 continue; // DN must not exist, just continue. Logged by the LDAP object
             }
 
@@ -260,10 +279,16 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
             }
 
             // Add to found groups array
-            $groups[] = $dn;
+            if ($use_group_name && isset($attributes[$map['name']]) && is_array($attributes[$map['name']])) {
+                $groups[] = $attributes[$map['name']][0];
+            } else {
+                $groups[] = $dn;
+            }
 
             // Recursively search "sub" groups
-            $groups = array_merge($groups, $this->search($attributes[$map['memberof']]));
+            if (!empty($attributes[$map['memberof']])) {
+                $groups = array_merge($groups, $this->search($attributes[$map['memberof']]));
+            }
         }
 
         // Return only the unique group names
@@ -284,17 +309,17 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
         assert(is_string($dn) && $dn != '');
 
         // Shorten the variable name
-        $map =& $this->attribute_map;
+        $map = &$this->attribute_map;
 
         // Log the search
-        SimpleSAML\Logger::debug(
-            $this->title . 'Searching ActiveDirectory group membership.' .
-            ' DN: ' . $dn .
-            ' DN Attribute: ' . $map['dn'] .
-            ' Member Attribute: ' . $map['member'] .
-            ' Type Attribute: ' . $map['type'] .
-            ' Type Value: ' . $this->type_map['group'] .
-            ' Base: ' . implode('; ', $this->base_dn)
+        \SimpleSAML\Logger::debug(
+            $this->title.'Searching ActiveDirectory group membership.'.
+            ' DN: '.$dn.
+            ' DN Attribute: '.$map['dn'].
+            ' Member Attribute: '.$map['member'].
+            ' Type Attribute: '.$map['type'].
+            ' Type Value: '.$this->type_map['group'].
+            ' Base: '.implode('; ', $this->base_dn)
         );
 
         // AD connections should have this set
@@ -304,18 +329,18 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
         try {
             $entries = $this->getLdap()->searchformultiple(
                 $this->base_dn,
-                array($map['type'] => $this->type_map['group'], $map['member'] . ':1.2.840.113556.1.4.1941:' => $dn),
-                array($map['dn'])
+                [$map['type'] => $this->type_map['group'], $map['member'].':1.2.840.113556.1.4.1941:' => $dn],
+                [$map['dn']]
             );
 
         // The search may throw an exception if no entries
         // are found, unlikely but possible.
-        } catch (SimpleSAML_Error_UserNotFound $e) {
-            return array();
+        } catch (\SimpleSAML\Error\UserNotFound $e) {
+            return [];
         }
 
         //Init the groups
-        $groups = array();
+        $groups = [];
 
         // Check each entry..
         foreach ($entries as $entry) {
@@ -338,10 +363,10 @@ class sspmod_ldap_Auth_Process_AttributeAddUsersGroups extends sspmod_ldap_Auth_
             }
 
             // Could not find DN, log and continue
-            SimpleSAML\Logger::notice(
-                $this->title . 'The DN attribute [' .
-                implode(', ', array($map['dn'], strtolower($map['dn']), 'dn')) .
-                '] could not be found in the entry. ' . $this->var_export($entry)
+            \SimpleSAML\Logger::notice(
+                $this->title.'The DN attribute ['.
+                implode(', ', [$map['dn'], strtolower($map['dn']), 'dn']).
+                '] could not be found in the entry. '.$this->var_export($entry)
             );
         }
 
diff --git a/modules/ldap/lib/Auth/Process/BaseFilter.php b/modules/ldap/lib/Auth/Process/BaseFilter.php
index c1da79255aebfd83d0e58a0b047b9013839902e1..f7de0656fc8da7e7b090737fc0e2f5d8ec5fb916 100644
--- a/modules/ldap/lib/Auth/Process/BaseFilter.php
+++ b/modules/ldap/lib/Auth/Process/BaseFilter.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap\Auth\Process;
+
 /**
  * This base LDAP filter class can be extended to enable real
  * filter classes direct access to the authsource ldap config
@@ -12,9 +14,9 @@
  * @author Remy Blom <remy.blom@hku.nl>
  * @package SimpleSAMLphp
  */
-abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_ProcessingFilter
-{
 
+abstract class BaseFilter extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * List of attribute "alias's" linked to the real attribute
      * name. Used for abstraction / configuration of the LDAP
@@ -36,10 +38,10 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
 
     /**
      * The construct method will change the filter config into
-     * a SimpleSAML_Configuration object and store it here for
+     * a \SimpleSAML\Configuration object and store it here for
      * later use, if needed.
      *
-     * @var SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     protected $config;
 
@@ -48,7 +50,7 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
      * Instance, object of the ldap connection. Stored here to
      * be access later during processing.
      *
-     * @var sspmod_ldap_LdapConnection
+     * @var \SimpleSAML\Auth\Ldap
      */
     private $ldap;
 
@@ -87,7 +89,7 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
      * to the LDAP server. Then sets up the LDAP connection for the
      * instance/object and stores everything in class members.
      *
-     * @throws SimpleSAML_Error_Exception
+     * @throws \SimpleSAML\Error\Exception
      * @param array $config
      * @param $reserved
      */
@@ -99,29 +101,28 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
         // This way if the class is extended the proper name is used
         $classname = get_class($this);
         $classname = explode('_', $classname);
-        $this->title = 'ldap:' . end($classname) . ' : ';
+        $this->title = 'ldap:'.end($classname).' : ';
 
         // Log the construction
-        SimpleSAML\Logger::debug(
-            $this->title . 'Creating and configuring the filter.'
+        \SimpleSAML\Logger::debug(
+            $this->title.'Creating and configuring the filter.'
         );
 
         // If an authsource was defined (an not empty string)...
         if (isset($config['authsource']) && $config['authsource']) {
-
             // Log the authsource request
-            SimpleSAML\Logger::debug(
-                $this->title . 'Attempting to get configuration values from authsource [' .
-                $config['authsource'] . ']'
+            \SimpleSAML\Logger::debug(
+                $this->title.'Attempting to get configuration values from authsource ['.
+                $config['authsource'].']'
             );
 
             // Get the authsources file, which should contain the config
-            $authsource = SimpleSAML_Configuration::getConfig('authsources.php');
+            $authsource = \SimpleSAML\Configuration::getConfig('authsources.php');
 
             // Verify that the authsource config exists
             if (!$authsource->hasValue($config['authsource'])) {
-                throw new SimpleSAML_Error_Exception(
-                    $this->title . 'Authsource [' . $config['authsource'] .
+                throw new \SimpleSAML\Error\Exception(
+                    $this->title.'Authsource ['.$config['authsource'].
                     '] defined in filter parameters not found in authsources.php'
                 );
             }
@@ -133,14 +134,14 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
             // Make sure it is an ldap source
             // TODO: Support ldap:LDAPMulti, if possible
             if (@$authsource[0] != 'ldap:LDAP') {
-                throw new SimpleSAML_Error_Exception(
-                    $this->title . 'Authsource [' . $config['authsource'] .
+                throw new \SimpleSAML\Error\Exception(
+                    $this->title.'Authsource ['.$config['authsource'].
                     '] specified in filter parameters is not an ldap:LDAP type'
                 );
             }
 
             // Build the authsource config
-            $authconfig = array();
+            $authconfig = [];
             if (isset($authsource['hostname'])) {
                 $authconfig['ldap.hostname']   = $authsource['hostname'];
             }
@@ -162,7 +163,10 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
             // only set when search.enabled = true
             if (isset($authsource['search.enable']) && $authsource['search.enable']) {
                 if (isset($authsource['search.base'])) {
-                    $authconfig['ldap.basedn']     = $authsource['search.base'];
+                    $authconfig['ldap.basedn'] = $authsource['search.base'];
+                }
+                if (isset($authsource['search.scope'])) {
+                    $authconfig['ldap.scope'] = $authsource['search.scope'];
                 }
                 if (isset($authsource['search.username'])) {
                     $authconfig['ldap.username']   = $authsource['search.username'];
@@ -191,16 +195,16 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
             $config = array_merge($authconfig, $config);
 
             // Authsource complete
-            SimpleSAML\Logger::debug(
-                $this->title . 'Retrieved authsource [' . $config['authsource'] .
-                '] configuration values: ' . $this->var_export($authconfig)
+            \SimpleSAML\Logger::debug(
+                $this->title.'Retrieved authsource ['.$config['authsource'].
+                '] configuration values: '.$this->var_export($authconfig)
             );
         }
 
         // Convert the config array to a config class,
         // that way we can verify type and define defaults.
         // Store in the instance in-case needed later, by a child class.
-        $this->config = SimpleSAML_Configuration::loadFromArray($config, 'ldap:AuthProcess');
+        $this->config = \SimpleSAML\Configuration::loadFromArray($config, 'ldap:AuthProcess');
 
         // Set all the filter values, setting defaults if needed
         $this->base_dn = $this->config->getArrayizeString('ldap.basedn', '');
@@ -212,14 +216,14 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
         $this->product = strtoupper($this->product);
 
         // Log the member values retrieved above
-        SimpleSAML\Logger::debug(
-            $this->title . 'Configuration values retrieved;' .
-            ' BaseDN: ' . $this->var_export($this->base_dn) .
-            ' Product: ' . $this->var_export($this->product)
+        \SimpleSAML\Logger::debug(
+            $this->title.'Configuration values retrieved;'.
+            ' BaseDN: '.$this->var_export($this->base_dn).
+            ' Product: '.$this->var_export($this->product)
         );
 
         // Setup the attribute map which will be used to search LDAP
-        $this->attribute_map = array(
+        $this->attribute_map = [
             'dn'       => $this->config->getString('attribute.dn', 'distinguishedName'),
             'groups'   => $this->config->getString('attribute.groups', 'groups'),
             'member'   => $this->config->getString('attribute.member', 'member'),
@@ -227,22 +231,22 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
             'name'     => $this->config->getString('attribute.groupname', 'name'),
             'type'     => $this->config->getString('attribute.type', 'objectClass'),
             'username' => $this->config->getString('attribute.username', 'sAMAccountName')
-        );
+        ];
 
         // Log the attribute map
-        SimpleSAML\Logger::debug(
-            $this->title . 'Attribute map created: ' . $this->var_export($this->attribute_map)
+        \SimpleSAML\Logger::debug(
+            $this->title.'Attribute map created: '.$this->var_export($this->attribute_map)
         );
 
         // Setup the object type map which is used to determine a DNs' type
-        $this->type_map = array(
+        $this->type_map = [
             'group' => $this->config->getString('type.group', 'group'),
             'user'  => $this->config->getString('type.user', 'user')
-        );
+        ];
 
         // Log the type map
-        SimpleSAML\Logger::debug(
-            $this->title . 'Type map created: ' . $this->var_export($this->type_map)
+        \SimpleSAML\Logger::debug(
+            $this->title.'Type map created: '.$this->var_export($this->type_map)
         );
     }
 
@@ -251,7 +255,7 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
      * rather than setting in the constructor to avoid unnecessarily
      * connecting to LDAP when it might not be needed.
      *
-     * @return sspmod_ldap_LdapConnection
+     * @return \SimpleSAML\Auth\Ldap
      */
     protected function getLdap()
     {
@@ -271,20 +275,20 @@ abstract class sspmod_ldap_Auth_Process_BaseFilter extends SimpleSAML_Auth_Proce
         $password   = $this->config->getString('ldap.password', null);
 
         // Log the LDAP connection
-        SimpleSAML\Logger::debug(
-            $this->title . 'Connecting to LDAP server;' .
-            ' Hostname: ' . $hostname .
-            ' Port: ' . $port .
-            ' Enable TLS: ' . ($enable_tls ? 'Yes' : 'No') .
-            ' Debug: ' . ($debug ? 'Yes' : 'No') .
-            ' Referrals: ' . ($referrals ? 'Yes' : 'No') .
-            ' Timeout: ' . $timeout .
-            ' Username: ' . $username .
-            ' Password: ' . (empty($password) ? '' : '********')
+        \SimpleSAML\Logger::debug(
+            $this->title.'Connecting to LDAP server;'.
+            ' Hostname: '.$hostname.
+            ' Port: '.$port.
+            ' Enable TLS: '.($enable_tls ? 'Yes' : 'No').
+            ' Debug: '.($debug ? 'Yes' : 'No').
+            ' Referrals: '.($referrals ? 'Yes' : 'No').
+            ' Timeout: '.$timeout.
+            ' Username: '.$username.
+            ' Password: '.(empty($password) ? '' : '********')
         );
 
         // Connect to the LDAP server to be queried during processing
-        $this->ldap = new SimpleSAML_Auth_LDAP($hostname, $enable_tls, $debug, $timeout, $port, $referrals);
+        $this->ldap = new \SimpleSAML\Auth\LDAP($hostname, $enable_tls, $debug, $timeout, $port, $referrals);
         $this->ldap->bind($username, $password);
 
         // All done
diff --git a/modules/ldap/lib/Auth/Source/LDAP.php b/modules/ldap/lib/Auth/Source/LDAP.php
index 2e2144b8f54351dc56585460db44c528cb8beef6..4757a3bb2502c999fd2927f89f7f300224aa402a 100644
--- a/modules/ldap/lib/Auth/Source/LDAP.php
+++ b/modules/ldap/lib/Auth/Source/LDAP.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap\Auth\Source;
+
 /**
  * LDAP authentication source.
  *
@@ -10,9 +12,9 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_ldap_Auth_Source_LDAP extends sspmod_core_Auth_UserPassBase
-{
 
+class LDAP extends \SimpleSAML\Module\core\Auth\UserPassBase
+{
     /**
      * A LDAP configuration object.
      */
@@ -33,8 +35,10 @@ class sspmod_ldap_Auth_Source_LDAP extends sspmod_core_Auth_UserPassBase
         // Call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        $this->ldapConfig = new sspmod_ldap_ConfigHelper($config,
-            'Authentication source ' . var_export($this->authId, true));
+        $this->ldapConfig = new \SimpleSAML\Module\ldap\ConfigHelper(
+            $config,
+            'Authentication source '.var_export($this->authId, true)
+        );
     }
 
 
@@ -53,5 +57,4 @@ class sspmod_ldap_Auth_Source_LDAP extends sspmod_core_Auth_UserPassBase
 
         return $this->ldapConfig->login($username, $password, $sasl_args);
     }
-
 }
diff --git a/modules/ldap/lib/Auth/Source/LDAPMulti.php b/modules/ldap/lib/Auth/Source/LDAPMulti.php
index c11a43e469f0b9145d02051361a7e29618a6e7fd..c923e984623980b5f9aec01c5bcee82453e65b40 100644
--- a/modules/ldap/lib/Auth/Source/LDAPMulti.php
+++ b/modules/ldap/lib/Auth/Source/LDAPMulti.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap\Auth\Source;
+
 /**
  * LDAP authentication source.
  *
@@ -10,9 +12,9 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_ldap_Auth_Source_LDAPMulti extends sspmod_core_Auth_UserPassOrgBase
-{
 
+class LDAPMulti extends \SimpleSAML\Module\core\Auth\UserPassOrgBase
+{
     /**
      * An array with descriptions for organizations.
      */
@@ -43,25 +45,29 @@ class sspmod_ldap_Auth_Source_LDAPMulti extends sspmod_core_Auth_UserPassOrgBase
         // Call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        $cfgHelper = SimpleSAML_Configuration::loadFromArray($config,
-            'Authentication source ' . var_export($this->authId, true));
+        $cfgHelper = \SimpleSAML\Configuration::loadFromArray(
+            $config,
+            'Authentication source '.var_export($this->authId, true)
+        );
 
 
-        $this->orgs = array();
-        $this->ldapOrgs = array();
+        $this->orgs = [];
+        $this->ldapOrgs = [];
         foreach ($config as $name => $value) {
-
             if ($name === 'username_organization_method') {
                 $usernameOrgMethod = $cfgHelper->getValueValidate(
                     'username_organization_method',
-                    array('none', 'allow', 'force'));
+                    ['none', 'allow', 'force']
+                );
                 $this->setUsernameOrgMethod($usernameOrgMethod);
                 continue;
             }
 
             if ($name === 'include_organization_in_username') {
                 $this->includeOrgInUsername = $cfgHelper->getBoolean(
-                    'include_organization_in_username', false);
+                    'include_organization_in_username',
+                    false
+                );
                 continue;
             }
 
@@ -74,9 +80,10 @@ class sspmod_ldap_Auth_Source_LDAPMulti extends sspmod_core_Auth_UserPassOrgBase
                 $this->orgs[$orgId] = $orgId;
             }
 
-            $orgCfg = new sspmod_ldap_ConfigHelper($orgCfg,
-                'Authentication source ' . var_export($this->authId, true) .
-                ', organization ' . var_export($orgId, true));
+            $orgCfg = new \SimpleSAML\Module\ldap\ConfigHelper(
+                $orgCfg,
+                'Authentication source '.var_export($this->authId, true).', organization '.var_export($orgId, true)
+            );
             $this->ldapOrgs[$orgId] = $orgCfg;
         }
     }
@@ -98,14 +105,14 @@ class sspmod_ldap_Auth_Source_LDAPMulti extends sspmod_core_Auth_UserPassOrgBase
 
         if (!array_key_exists($org, $this->ldapOrgs)) {
             // The user has selected an organization which doesn't exist anymore.
-            SimpleSAML\Logger::warning('Authentication source ' . var_export($this->authId, true) .
-                ': Organization seems to have disappeared while the user logged in.' .
-                ' Organization was ' . var_export($org, true));
-            throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+            \SimpleSAML\Logger::warning('Authentication source '.var_export($this->authId, true).
+                ': Organization seems to have disappeared while the user logged in.'.
+                ' Organization was '.var_export($org, true));
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
         }
 
         if ($this->includeOrgInUsername) {
-            $username = $username . '@' . $org;
+            $username = $username.'@'.$org;
         }
 
         return $this->ldapOrgs[$org]->login($username, $password, $sasl_args);
diff --git a/modules/ldap/lib/ConfigHelper.php b/modules/ldap/lib/ConfigHelper.php
index d76684bb8026d7721891f8409d527dbbff53595e..d4dcff33ad5084d1f8fdd08cca9bc1734cff91bf 100644
--- a/modules/ldap/lib/ConfigHelper.php
+++ b/modules/ldap/lib/ConfigHelper.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\ldap;
+
 /**
  * LDAP authentication source configuration parser.
  *
@@ -8,7 +10,8 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_ldap_ConfigHelper
+
+class ConfigHelper
 {
     /**
      * String with the location of this configuration.
@@ -16,19 +19,16 @@ class sspmod_ldap_ConfigHelper
      */
     private $location;
 
-
     /**
      * The hostname of the LDAP server.
      */
     private $hostname;
 
-
     /**
      * Whether we should use TLS/SSL when contacting the LDAP server.
      */
     private $enableTLS;
 
-
     /**
      * Whether debug output is enabled.
      *
@@ -36,7 +36,6 @@ class sspmod_ldap_ConfigHelper
      */
     private $debug;
 
-
     /**
      * The timeout for accessing the LDAP server.
      *
@@ -56,30 +55,31 @@ class sspmod_ldap_ConfigHelper
      */
     private $referrals;
 
-
     /**
      * Whether we need to search for the users DN.
      */
     private $searchEnable;
 
-
     /**
      * The username we should bind with before we can search for the user.
      */
     private $searchUsername;
 
-
     /**
      * The password we should bind with before we can search for the user.
      */
     private $searchPassword;
 
-
     /**
      * Array with the base DN(s) for the search.
      */
     private $searchBase;
 
+    /**
+     * The scope of the search.
+     */
+    private $searchScope;
+
     /**
      * Additional LDAP filter fields for the search
      */
@@ -90,31 +90,26 @@ class sspmod_ldap_ConfigHelper
      */
     private $searchAttributes;
 
-
     /**
      * The DN pattern we should use to create the DN from the username.
      */
     private $dnPattern;
 
-
     /**
      * The attributes we should fetch. Can be NULL in which case we will fetch all attributes.
      */
     private $attributes;
 
-
     /**
      * The user cannot get all attributes, privileged reader required
      */
     private $privRead;
 
-
     /**
      * The DN we should bind with before we can get the attributes.
      */
     private $privUsername;
 
-
     /**
      * The password we should bind with before we can get the attributes.
      */
@@ -135,7 +130,7 @@ class sspmod_ldap_ConfigHelper
         $this->location = $location;
 
         // Parse configuration
-        $config = SimpleSAML_Configuration::loadFromArray($config, $location);
+        $config = \SimpleSAML\Configuration::loadFromArray($config, $location);
 
         $this->hostname = $config->getString('hostname');
         $this->enableTLS = $config->getBoolean('enable_tls', false);
@@ -153,9 +148,9 @@ class sspmod_ldap_ConfigHelper
             }
 
             $this->searchBase = $config->getArrayizeString('search.base');
+            $this->searchScope = $config->getString('search.scope', 'subtree');
             $this->searchFilter = $config->getString('search.filter', null);
             $this->searchAttributes = $config->getArray('search.attributes');
-
         } else {
             $this->dnPattern = $config->getString('dnpattern');
         }
@@ -173,12 +168,12 @@ class sspmod_ldap_ConfigHelper
     /**
      * Attempt to log in using the given username and password.
      *
-     * Will throw a SimpleSAML_Error_Error('WRONGUSERPASS') if the username or password is wrong.
+     * Will throw a \SimpleSAML\Error\Error('WRONGUSERPASS') if the username or password is wrong.
      * If there is a configuration problem, an Exception will be thrown.
      *
      * @param string $username  The username the user wrote.
      * @param string $password  The password the user wrote.
-     * @param arrray $sasl_args  Array of SASL options for LDAP bind.
+     * @param array $sasl_args  Array of SASL options for LDAP bind.
      * @return array  Associative array with the users attributes.
      */
     public function login($username, $password, array $sasl_args = null)
@@ -187,11 +182,18 @@ class sspmod_ldap_ConfigHelper
         assert(is_string($password));
 
         if (empty($password)) {
-            SimpleSAML\Logger::info($this->location . ': Login with empty password disallowed.');
-            throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+            \SimpleSAML\Logger::info($this->location.': Login with empty password disallowed.');
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
         }
 
-        $ldap = new SimpleSAML_Auth_LDAP($this->hostname, $this->enableTLS, $this->debug, $this->timeout, $this->port, $this->referrals);
+        $ldap = new \SimpleSAML\Auth\LDAP(
+            $this->hostname,
+            $this->enableTLS,
+            $this->debug,
+            $this->timeout,
+            $this->port,
+            $this->referrals
+        );
 
         if (!$this->searchEnable) {
             $ldapusername = addcslashes($username, ',+"\\<>;*');
@@ -199,33 +201,40 @@ class sspmod_ldap_ConfigHelper
         } else {
             if ($this->searchUsername !== null) {
                 if (!$ldap->bind($this->searchUsername, $this->searchPassword)) {
-                    throw new Exception('Error authenticating using search username & password.');
+                    throw new \Exception('Error authenticating using search username & password.');
                 }
             }
 
-            $dn = $ldap->searchfordn($this->searchBase, $this->searchAttributes, $username, true, $this->searchFilter);
+            $dn = $ldap->searchfordn(
+                $this->searchBase,
+                $this->searchAttributes,
+                $username,
+                true,
+                $this->searchFilter,
+                $this->searchScope
+            );
             if ($dn === null) {
                 /* User not found with search. */
-                SimpleSAML\Logger::info($this->location . ': Unable to find users DN. username=\'' . $username . '\'');
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+                \SimpleSAML\Logger::info($this->location.': Unable to find users DN. username=\''.$username.'\'');
+                throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
             }
         }
 
         if (!$ldap->bind($dn, $password, $sasl_args)) {
-            SimpleSAML\Logger::info($this->location . ': '. $username . ' failed to authenticate. DN=' . $dn);
-            throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+            \SimpleSAML\Logger::info($this->location.': '.$username.' failed to authenticate. DN='.$dn);
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
         }
 
-        /* In case of SASL bind, authenticated and authorized DN may differ */
+        // In case of SASL bind, authenticated and authorized DN may differ
         if (isset($sasl_args)) {
             $dn = $ldap->whoami($this->searchBase, $this->searchAttributes);
         }
 
-        /* Are privs needed to get the attributes? */
+        // Are privs needed to get the attributes?
         if ($this->privRead) {
-            /* Yes, rebind with privs */
+            // Yes, rebind with privs
             if (!$ldap->bind($this->privUsername, $this->privPassword)) {
-                throw new Exception('Error authenticating using privileged DN & password.');
+                throw new \Exception('Error authenticating using privileged DN & password.');
             }
         }
 
@@ -248,21 +257,23 @@ class sspmod_ldap_ConfigHelper
      * The DN of the matching element, if found. If no element was
      * found and $allowZeroHits is set to FALSE, an exception will
      * be thrown; otherwise NULL will be returned.
-     * @throws SimpleSAML_Error_AuthSource if:
+     * @throws \SimpleSAML\Error\AuthSource if:
      * - LDAP search encounter some problems when searching cataloge
      * - Not able to connect to LDAP server
-     * @throws SimpleSAML_Error_UserNotFound if:
+     * @throws \SimpleSAML\Error\UserNotFound if:
      * - $allowZeroHits is FALSE and no result is found
      *
      */
     public function searchfordn($attribute, $value, $allowZeroHits)
     {
-        $ldap = new SimpleSAML_Auth_LDAP($this->hostname,
+        $ldap = new \SimpleSAML\Auth\LDAP(
+            $this->hostname,
             $this->enableTLS,
             $this->debug,
             $this->timeout,
             $this->port,
-            $this->referrals);
+            $this->referrals
+        );
 
         if ($attribute == null) {
             $attribute = $this->searchAttributes;
@@ -270,12 +281,18 @@ class sspmod_ldap_ConfigHelper
 
         if ($this->searchUsername !== null) {
             if (!$ldap->bind($this->searchUsername, $this->searchPassword)) {
-                throw new Exception('Error authenticating using search username & password.');
+                throw new \Exception('Error authenticating using search username & password.');
             }
         }
 
-        return $ldap->searchfordn($this->searchBase, $attribute,
-            $value, $allowZeroHits, $this->searchFilter);
+        return $ldap->searchfordn(
+            $this->searchBase,
+            $attribute,
+            $value,
+            $allowZeroHits,
+            $this->searchFilter,
+            $this->searchScope
+        );
     }
 
     public function getAttributes($dn, $attributes = null)
@@ -284,21 +301,22 @@ class sspmod_ldap_ConfigHelper
             $attributes = $this->attributes;
         }
 
-        $ldap = new SimpleSAML_Auth_LDAP($this->hostname,
+        $ldap = new \SimpleSAML\Auth\LDAP(
+            $this->hostname,
             $this->enableTLS,
             $this->debug,
             $this->timeout,
             $this->port,
-            $this->referrals);
+            $this->referrals
+        );
 
-        /* Are privs needed to get the attributes? */
+        // Are privs needed to get the attributes?
         if ($this->privRead) {
-            /* Yes, rebind with privs */
+            // Yes, rebind with privs
             if (!$ldap->bind($this->privUsername, $this->privPassword)) {
-                throw new Exception('Error authenticating using privileged DN & password.');
+                throw new \Exception('Error authenticating using privileged DN & password.');
             }
         }
         return $ldap->getAttributes($dn, $attributes);
     }
-
 }
diff --git a/modules/memcacheMonitor/hooks/hook_frontpage.php b/modules/memcacheMonitor/hooks/hook_frontpage.php
index fa0d4503809806c67683ae1418fc5c7a511d1194..9329d55317391c1db6c4e7e665185bf35ecc1bc8 100644
--- a/modules/memcacheMonitor/hooks/hook_frontpage.php
+++ b/modules/memcacheMonitor/hooks/hook_frontpage.php
@@ -4,13 +4,14 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function memcacheMonitor_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
 
-	$links['config'][] = array(
-		'href' => SimpleSAML\Module::getModuleURL('memcacheMonitor/memcachestat.php'),
-		'text' => array('en' => 'MemCache Statistics'),
-	);
-	
+function memcacheMonitor_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
+
+    $links['config'][] = [
+        'href' => SimpleSAML\Module::getModuleURL('memcacheMonitor/memcachestat.php'),
+        'text' => '{core:frontpage:link_memcacheMonitor}',
+    ];
 }
diff --git a/modules/memcacheMonitor/hooks/hook_sanitycheck.php b/modules/memcacheMonitor/hooks/hook_sanitycheck.php
index 1513981245f27998b51b20a5ddd73f60e6934bff..a7a36c415dbdbbe7d1fec858040d650cdd5db5cd 100644
--- a/modules/memcacheMonitor/hooks/hook_sanitycheck.php
+++ b/modules/memcacheMonitor/hooks/hook_sanitycheck.php
@@ -7,29 +7,31 @@
  *
  * @param array &$hookinfo  hookinfo
  */
-function memcacheMonitor_hook_sanitycheck(&$hookinfo) {
-	assert(is_array($hookinfo));
-	assert(array_key_exists('errors', $hookinfo));
-	assert(array_key_exists('info', $hookinfo));
 
-	try {
-		$servers = SimpleSAML_Memcache::getRawStats();
-	} catch (Exception $e) {
-		$hookinfo['errors'][] = '[memcacheMonitor] Error parsing memcache configuration: ' . $e->getMessage();
-		return;
-	}
+function memcacheMonitor_hook_sanitycheck(&$hookinfo)
+{
+    assert(is_array($hookinfo));
+    assert(array_key_exists('errors', $hookinfo));
+    assert(array_key_exists('info', $hookinfo));
 
-	$allOK = TRUE;
-	foreach ($servers as $group) {
-		foreach ($group as $server => $status) {
-			if ($status === FALSE) {
-				$hookinfo['errors'][] = '[memcacheMonitor] No response from server: ' . $server;
-				$allOK = FALSE;
-			}
-		}
-	}
+    try {
+        $servers = \SimpleSAML\Memcache::getRawStats();
+    } catch (\Exception $e) {
+        $hookinfo['errors'][] = '[memcacheMonitor] Error parsing memcache configuration: '.$e->getMessage();
+        return;
+    }
 
-	if ($allOK) {
-		$hookinfo['info'][] = '[memcacheMonitor] All servers responding.';
-	}
+    $allOK = true;
+    foreach ($servers as $group) {
+        foreach ($group as $server => $status) {
+            if ($status === false) {
+                $hookinfo['errors'][] = '[memcacheMonitor] No response from server: '.$server;
+                $allOK = false;
+            }
+        }
+    }
+
+    if ($allOK) {
+        $hookinfo['info'][] = '[memcacheMonitor] All servers responding.';
+    }
 }
diff --git a/modules/memcacheMonitor/templates/memcachestat.tpl.php b/modules/memcacheMonitor/templates/memcachestat.tpl.php
index 9a9a3399d313d69f9331ac08a7903cc42e9ed9b0..02505ed2d36dac5f4720e9fb4013caf23de90e11 100644
--- a/modules/memcacheMonitor/templates/memcachestat.tpl.php
+++ b/modules/memcacheMonitor/templates/memcachestat.tpl.php
@@ -1,42 +1,19 @@
 <?php
 
-$this->data['head'] = '<style type="text/css">
-	table.statustable td, table.statustable th { 
-		border: 1px solid #eee;
-		padding: 2px 6px;
-	}
-	table.statustable {
-		border-collapse: collapse;
-	}
-	.bmax {
-		border: 1px solid #555;
-		background: #eee;
-	}
-	.bused {
-		border-right: 1px solid #555;
-		border-bottom: 1px solid #555;
-		color: white;
-		background: #833;
-	}
-</style>
-';
-
-
-
+$this->data['head'] = '<link href="'.$this->data['baseurlpath'].'assets/css/memcacheMonitor.css" rel="stylesheet" />';
 $this->includeAtTemplateBase('includes/header.php');
 
 $title = $this->data['title'];
 $table = $this->data['table'];
 
-
 // Identify column headings
-$column_titles = array();
-foreach($table as $row_title => $row_data) {
-	foreach($row_data as $ct => $foo) {
-		if(!in_array($ct, $column_titles, true)) {
-			$column_titles[] = $ct;
-		}
-	}
+$column_titles = [];
+foreach ($table as $row_title => $row_data) {
+    foreach ($row_data as $ct => $foo) {
+        if (!in_array($ct, $column_titles, true)) {
+            $column_titles[] = $ct;
+        }
+    }
 }
 
 ?>
@@ -48,28 +25,28 @@ foreach($table as $row_title => $row_data) {
 <tr>
 <th></th>
 <?php
-foreach($column_titles as $ct) {
-	echo '<th>' . htmlspecialchars($ct) . '</th>' . "\n";
+foreach ($column_titles as $ct) {
+    echo '<th>'.htmlspecialchars($ct).'</th>'."\n";
 }
 ?>
 </tr>
 
 <?php
-foreach($table as $row_title => $row_data) {
-	echo '<tr>' . "\n";
-	echo '<th class="rowtitle" style="text-align: right">' . $this->t($this->data['rowtitles'][$row_title]) . '</th>' . "\n";
+foreach ($table as $row_title => $row_data) {
+    echo '<tr>' . "\n";
+    echo '<th class="rowtitle" style="text-align: right">'.$this->t($this->data['rowtitles'][$row_title]).'</th>'."\n";
 
-	foreach($column_titles as $ct) {
-		echo '<td>';
+    foreach ($column_titles as $ct) {
+        echo '<td>';
 
-		if(array_key_exists($ct, $row_data)) {
-			echo htmlspecialchars($row_data[$ct]);
-		}
+        if (array_key_exists($ct, $row_data)) {
+            echo htmlspecialchars($row_data[$ct]);
+        }
 
-		echo '</td>' . "\n";
-	}
+        echo '</td>' . "\n";
+    }
 
-	echo '</tr>' . "\n";
+    echo '</tr>' . "\n";
 }
 ?>
 
@@ -77,15 +54,14 @@ foreach($table as $row_title => $row_data) {
 
 <?php
 if (array_key_exists('bytes', $this->data['statsraw']) && array_key_exists('limit_maxbytes', $this->data['statsraw'])) {
-	foreach($this->data['statsraw']['bytes'] as $key => $row_data) {
-		echo ('<h3>Storage usage on [' . $key . ']</h3>');
-		$maxpix = 400;
-		$pix = floor($this->data['statsraw']['bytes'][$key]*$maxpix / $this->data['statsraw']['limit_maxbytes'][$key]);
-		
-		echo('<div class="bmax" style="width: ' .  $maxpix. 'px"><div class="bused" style="width: ' . $pix . 'px">
-		Used: ' . $table['bytes'][$key] . '
-		</div>Total available: ' . $table['limit_maxbytes'][$key] . '</div>');
-	}
+    foreach ($this->data['statsraw']['bytes'] as $key => $row_data) {
+        echo ('<h3>Storage usage on ['.$key.']</h3>');
+        $maxpix = 400;
+        $pix = floor($this->data['statsraw']['bytes'][$key]*$maxpix / $this->data['statsraw']['limit_maxbytes'][$key]);
+
+        echo '<div class="bmax" style="width: '.$maxpix.'px"><div class="bused" style="width: '.$pix.'px">Used: '.
+            $table['bytes'][$key].'</div>Total available: '.$table['limit_maxbytes'][$key].'</div>';
+    }
 }
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/memcacheMonitor/templates/memcachestat.twig b/modules/memcacheMonitor/templates/memcachestat.twig
new file mode 100644
index 0000000000000000000000000000000000000000..fdc4af4bd03a307ad28974a4c4463185ec4ab749
--- /dev/null
+++ b/modules/memcacheMonitor/templates/memcachestat.twig
@@ -0,0 +1,38 @@
+{% set pagetitle = 'SimpleSAMLphp Memcache Monitor'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}assets/css/memcacheMonitor.css" rel="stylesheet" />
+{% endblock %}
+
+{% block content %}
+    <h2>{{ title }}</h2>
+    <table class="statustable">
+        <tr>
+            <th>&nbsp;</th>
+            {% for key, title in colTitles %}
+            <th>{{ title|escape('html') }}</th>
+            {% endfor %}
+        </tr>
+        {% for rowTitle, rowData in table %}
+        <tr>
+            <th class="rowtitle" style="text-align: right">{{ rowTitles[rowTitle]|trans }}</th>
+            {% for key, colTitle in colTitles %}
+            {% if rowData[colTitle] is defined %}
+            <td>{{ rowData[colTitle]|escape('html') }}</td>
+            {% else %}
+            <td>&nbsp;</td>
+            {% endif %}
+            {% endfor %}
+        </tr>
+        {% endfor %}
+    </table>
+
+    {% if usage is defined %}
+    {% for key, value in usage %}
+    <h3>Storage usage on [{{ key }}]</h3>
+        <div class="bmax" style="width: {{ maxpix }}">
+            <div class="bused" style="width: {{ usage[key] }}">Used: {{ table.bytes[key] }}</div>Total available: {{ table.limit_maxbytes[key] }}</div>
+    {% endfor %}
+    {% endif %}
+{% endblock %}
diff --git a/modules/memcacheMonitor/www/assets/css/memcacheMonitor.css b/modules/memcacheMonitor/www/assets/css/memcacheMonitor.css
new file mode 100644
index 0000000000000000000000000000000000000000..b57c376543bd555804df4394a9453a9d318cfacc
--- /dev/null
+++ b/modules/memcacheMonitor/www/assets/css/memcacheMonitor.css
@@ -0,0 +1,20 @@
+table.statustable td, table.statustable th {
+    border: 1px solid #eee;
+    padding: 2px 6px;
+}
+
+table.statustable {
+    border-collapse: collapse;
+}
+
+.bmax {
+    border: 1px solid #555;
+    background: #eee;
+}
+
+.bused {
+    border-right: 1px solid #555;
+    border-bottom: 1px solid #555;
+    color: white;
+    background: #833;
+}
diff --git a/modules/memcacheMonitor/www/memcachestat.php b/modules/memcacheMonitor/www/memcachestat.php
index 1410b8b9e5e8ee5a9cb52c493cb7b7c9324e2e7c..a5cb0d20211e83a12768d0d058f2272f7fe6a967 100644
--- a/modules/memcacheMonitor/www/memcachestat.php
+++ b/modules/memcacheMonitor/www/memcachestat.php
@@ -1,108 +1,101 @@
 <?php
 
-function tdate($input) {
-	return date(DATE_RFC822, $input); 
+function tdate($input)
+{
+    return date(DATE_RFC822, $input);
 }
 
-function hours($input) {
-	if ($input < 60) return number_format($input, 2) . ' sec';
-	if ($input < 60*60) return number_format(($input/60),2) . ' min';
-	if ($input < 24*60*60) return number_format(($input/(60*60)),2) . ' hours';
-	return number_format($input/(24*60*60),2) . ' days';
-	
+function hours($input)
+{
+    if ($input < 60) {
+        return number_format($input, 2).' sec';
+    }
+    if ($input < 60 * 60) {
+        return number_format(($input / 60), 2).' min';
+    }
+    if ($input < 24 * 60 * 60) {
+        return number_format(($input / (60 * 60)), 2).' hours';
+    }
+    return number_format($input / (24 * 60 * 60), 2).' days';
 }
 
-
-function humanreadable($input) {
-	 
-	$output = "";
-	$input = abs($input);
-	
-	if ($input >= (1024*1024*1024*1024*1024*1024*1024*100)) {
-		$output = sprintf("%5ldEi", $input / (1024*1024*1024*1024*1024*1024) );		
-	} else if ($input >= (1024*1024*1024*1024*1024*1024*10)) {
-		$output = sprintf("%5.1fEi", $input / (1024.0*1024.0*1024.0*1024.0*1024.0*1024.0) );		
-	} else if ($input >= (1024*1024*1024*1024*1024*1024)) {
-		$output = sprintf("%5.2fEi", $input / (1024.0*1024.0*1024.0*1024.0*1024.0*1024.0) );	
-
-
-	} else if ($input >= (1024*1024*1024*1024*1024*100)) {
-		$output = sprintf("%5ldPi", $input / (1024*1024*1024*1024*1024) );		
-	} else if ($input >= (1024*1024*1024*1024*1024*10)) {
-		$output = sprintf("%5.1fPi", $input / (1024.0*1024.0*1024.0*1024.0*1024.0) );		
-	} else if ($input >= (1024*1024*1024*1024*1024)) {
-		$output = sprintf("%5.2fPi", $input / (1024.0*1024.0*1024.0*1024.0*1024.0) );	
-		
-	} else if ($input >= (1024*1024*1024*1024*100)) {
-		$output = sprintf("%5ldTi", $input / (1024*1024*1024*1024) );
-	} else if ($input >= (1024*1024*1024*1024*10)) {
-		$output = sprintf("%5.1fTi", $input / (1024.0*1024.0*1024.0*1024.0) );	
-	} else if ($input >= (1024*1024*1024*1024)) {
-		$output = sprintf("%5.2fTi", $input / (1024.0*1024.0*1024.0*1024.0) );
-
-
-	} else if ($input >= (1024*1024*1024*100)) {
-		$output = sprintf("%5ldGi", $input / (1024*1024*1024) );		
-	} else if ($input >= (1024*1024*1024*10)) {
-		$output = sprintf("%5.1fGi", $input / (1024.0*1024.0*1024.0) );		
-	} else if ($input >= (1024*1024*1024)) {
-		$output = sprintf("%5.2fGi", $input / (1024.0*1024.0*1024.0) );	
-		
-	} else if ($input >= (1024*1024*100)) {
-		$output = sprintf("%5ldMi", $input / (1024*1024) );
-	} else if ($input >= (1024*1024*10)) {
-		$output = sprintf("%5.1fM", $input / (1024.0*1024.0) );	
-	} else if ($input >= (1024*1024)) {
-		$output = sprintf("%5.2fMi", $input / (1024.0*1024.0) );		
-		
-	} else if ($input >= (1024 * 100)) {
-		$output = sprintf("%5ldKi", $input / (1024) );
-	} else if ($input >= (1024 * 10)) {
-		$output = sprintf("%5.1fKi", $input / 1024.0 );
-	} else if ($input >= (1024)) {
-		$output = sprintf("%5.2fKi", $input / 1024.0 );
-		
-	} else {
-		$output = sprintf("%5ld", $input );
-	}
-
-	return $output;
+function humanreadable($input)
+{
+    $output = "";
+    $input = abs($input);
+
+    if ($input >= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 100)) {
+        $output = sprintf("%5ldEi", $input / (1024 * 1024 * 1024 * 1024 * 1024 * 1024));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 10)) {
+        $output = sprintf("%5.1fEi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 1024 * 1024)) {
+        $output = sprintf("%5.2fEi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 1024 * 100)) {
+        $output = sprintf("%5ldPi", $input / (1024 * 1024 * 1024 * 1024 * 1024));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 1024 * 10)) {
+        $output = sprintf("%5.1fPi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 1024)) {
+        $output = sprintf("%5.2fPi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 100)) {
+        $output = sprintf("%5ldTi", $input / (1024 * 1024 * 1024 * 1024));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024 * 10)) {
+        $output = sprintf("%5.1fTi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 1024)) {
+        $output = sprintf("%5.2fTi", $input / (1024.0 * 1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024 * 100)) {
+        $output = sprintf("%5ldGi", $input / (1024 * 1024 * 1024));
+    } elseif ($input >= (1024 * 1024 * 1024 * 10)) {
+        $output = sprintf("%5.1fGi", $input / (1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 1024)) {
+        $output = sprintf("%5.2fGi", $input / (1024.0 * 1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024 * 100)) {
+        $output = sprintf("%5ldMi", $input / (1024 * 1024));
+    } elseif ($input >= (1024 * 1024 * 10)) {
+        $output = sprintf("%5.1fM", $input / (1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 1024)) {
+        $output = sprintf("%5.2fMi", $input / (1024.0 * 1024.0));
+    } elseif ($input >= (1024 * 100)) {
+        $output = sprintf("%5ldKi", $input / 1024);
+    } elseif ($input >= (1024 * 10)) {
+        $output = sprintf("%5.1fKi", $input / 1024.0);
+    } elseif ($input >= (1024)) {
+        $output = sprintf("%5.2fKi", $input / 1024.0);
+    } else {
+        $output = sprintf("%5ld", $input);
+    }
+
+    return $output;
 }
 
-
-
-
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
 // Make sure that the user has admin access rights
-SimpleSAML\Utils\Auth::requireAdmin();
-
+\SimpleSAML\Utils\Auth::requireAdmin();
 
-$formats = array(
-	'bytes' => 'humanreadable',
-	'bytes_read' => 'humanreadable',
-	'bytes_written' => 'humanreadable',
-	'limit_maxbytes' => 'humanreadable',
-	'time' => 'tdate',
-	'uptime' => 'hours',
-);
+$formats = [
+    'bytes' => 'humanreadable',
+    'bytes_read' => 'humanreadable',
+    'bytes_written' => 'humanreadable',
+    'limit_maxbytes' => 'humanreadable',
+    'time' => 'tdate',
+    'uptime' => 'hours',
+];
 
-$statsraw = SimpleSAML_Memcache::getStats();
+$statsraw = \SimpleSAML\Memcache::getStats();
 
 $stats = $statsraw;
 
-foreach($stats AS $key => &$entry) {
-	if (array_key_exists($key, $formats)) {
-		$func = $formats[$key];
-		foreach($entry AS $k => $val) {
-			$entry[$k] = $func($val);
-		}
-	}
-
+foreach ($stats as $key => &$entry) {
+    if (array_key_exists($key, $formats)) {
+        $func = $formats[$key];
+        foreach ($entry as $k => $val) {
+            $entry[$k] = $func($val);
+        }
+    }
 }
 
-$t = new SimpleSAML_XHTML_Template($config, 'memcacheMonitor:memcachestat.tpl.php');
-$rowTitles = array(
+$t = new \SimpleSAML\XHTML\Template($config, 'memcacheMonitor:memcachestat.tpl.php');
+$rowTitles = [
     'accepting_conns' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:accepting_conns}'),
     'auth_cmds' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:auth_cmds}'),
     'auth_errors' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:auth_errors}'),
@@ -116,7 +109,9 @@ $rowTitles = array(
     'cmd_get' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:cmd_get}'),
     'cmd_set' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:cmd_set}'),
     'cmd_touch' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:cmd_touch}'),
-    'connection_structures' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:connection_structures}'),
+    'connection_structures' => \SimpleSAML\Locale\Translate::noop(
+        '{memcacheMonitor:memcachestat:connection_structures}'
+    ),
     'conn_yields' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:conn_yields}'),
     'curr_connections' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:curr_connections}'),
     'curr_items' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:curr_items}'),
@@ -151,9 +146,31 @@ $rowTitles = array(
     'touch_misses' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:touch_misses}'),
     'uptime' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:uptime}'),
     'version' => \SimpleSAML\Locale\Translate::noop('{memcacheMonitor:memcachestat:version}'),
-);
+];
+
+// Identify column headings
+$colTitles = [];
+foreach ($stats as $rowTitle => $rowData) {
+    foreach ($rowData as $colTitle => $foo) {
+        if (!in_array($colTitle, $colTitles, true)) {
+            $colTitles[] = $colTitle;
+        }
+    }
+}
+
+if (array_key_exists('bytes', $statsraw) && array_key_exists('limit_maxbytes', $statsraw)) {
+    $usage = [];
+    $maxpix = 400;
+    foreach ($statsraw['bytes'] as $key => $row_data) {
+        $pix = floor($statsraw['bytes'][$key] * $maxpix / $statsraw['limit_maxbytes'][$key]);
+        $usage[$key] = $pix.'px';
+    }
+    $t->data['maxpix'] = $maxpix.'px';
+    $t->data['usage'] = $usage;
+}
+
 $t->data['title'] = 'Memcache stats';
-$t->data['rowtitles'] = $rowTitles;
+$t->data['rowTitles'] = $rowTitles;
+$t->data['colTitles'] = $colTitles;
 $t->data['table'] = $stats;
-$t->data['statsraw'] = $statsraw;
 $t->show();
diff --git a/modules/metarefresh/bin/metarefresh.php b/modules/metarefresh/bin/metarefresh.php
index bad5c37a06088ed244689f2371a6005396e78e9d..b02fb75a6a2385eba494f4a41d060e52ff35ce60 100755
--- a/modules/metarefresh/bin/metarefresh.php
+++ b/modules/metarefresh/bin/metarefresh.php
@@ -11,167 +11,168 @@
 $baseDir = dirname(dirname(dirname(dirname(__FILE__))));
 
 // Add library autoloader.
-require_once($baseDir . '/lib/_autoload.php');
+require_once($baseDir.'/lib/_autoload.php');
 
-if(!SimpleSAML\Module::isModuleEnabled('metarefresh')) {
-	echo("You need to enable the metarefresh module before this script can be used.\n");
-	echo("You can enable it by running the following command:\n");
-	echo('  echo >"' . $baseDir . '/modules/metarefresh/enable' . "\"\n");
-	exit(1);
+if (!\SimpleSAML\Module::isModuleEnabled('metarefresh')) {
+    echo "You need to enable the metarefresh module before this script can be used.\n";
+    echo "You can enable it by running the following command:\n";
+    echo '  echo >"'.$baseDir.'/modules/metarefresh/enable'."\"\n";
+    exit(1);
 }
 
-/* Initialize the configuration. */
-$configdir = SimpleSAML\Utils\Config::getConfigDir();
-SimpleSAML_Configuration::setConfigDir($configdir);
+// Initialize the configuration
+$configdir = \SimpleSAML\Utils\Config::getConfigDir();
+\SimpleSAML\Configuration::setConfigDir($configdir);
 
-/* $outputDir contains the directory we will store the generated metadata in. */
-$outputDir = $baseDir . '/metadata-generated';
+// $outputDir contains the directory we will store the generated metadata in
+$outputDir = $baseDir.'/metadata-generated';
 
 
 /* $toStdOut is a boolean telling us wheter we will print the output to stdout instead
  * of writing it to files in $outputDir.
  */
-$toStdOut = FALSE;
+$toStdOut = false;
 
 /* $certificates contains the certificates which should be used to check the signature of the signed
  * EntityDescriptor in the metadata, or NULL if signature verification shouldn't be done.
  */
-$certificates = NULL;
+$certificates = null;
 
 /* $validateFingerprint contains the fingerprint of the certificate which should have been used
  * to sign the EntityDescriptor in the metadata, or NULL if fingerprint validation shouldn't be
  * done.
  */
-$validateFingerprint = NULL;
+$validateFingerprint = null;
 
+// This variable contains the files we will parse
+$files = [];
 
-/* This variable contains the files we will parse. */
-$files = array();
-
-/* Parse arguments. */
+// Parse arguments
 
 $progName = array_shift($argv);
 
-foreach($argv as $a) {
-	if(strlen($a) === 0) {
-		continue;
-	}
-
-	if($a[0] !== '-') {
-		/* Not an option. Assume that it is a file we should parse. */
-		$files[] = $a;
-		continue;
-	}
-
-	if(strpos($a, '=') !== FALSE) {
-		$p = strpos($a, '=');
-		$v = substr($a, $p + 1);
-		$a = substr($a, 0, $p);
-	} else {
-		$v = NULL;
-	}
-
-	/* Map short options to long options. */
-	$shortOptMap = array(
-		'-h' => '--help',
-		'-o' => '--out-dir',
-		'-s' => '--stdout',
-		);
-	if(array_key_exists($a, $shortOptMap)) {
-		$a = $shortOptMap[$a];
-	}
-
-	switch($a) {
-	case '--certificate':
-		if($v === NULL || strlen($v) === 0) {
-			echo('The --certficate option requires an parameter.' . "\n");
-			echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
-			exit(1);
-		}
-		$certificates[] = $v;
-		break;
-	case '--validate-fingerprint':
-		if($v === NULL || strlen($v) === 0) {
-			echo('The --validate-fingerprint option requires an parameter.' . "\n");
-			echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
-			exit(1);
-		}
-		$validateFingerprint = $v;
-		break;
-	case '--help':
-		printHelp();
-		exit(0);
-	case '--out-dir':
-		if($v === NULL || strlen($v) === 0) {
-			echo('The --out-dir option requires an parameter.' . "\n");
-			echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
-			exit(1);
-		}
-		$outputDir =   $baseDir . ($v[0] == '/' ? $v : '/' .  $v);
-		break;
-	case '--stdout':
-		$toStdOut = TRUE;
-		break;
-	default:
-		echo('Unknown option: ' . $a . "\n");
-		echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
-		exit(1);
-	}
+foreach ($argv as $a) {
+    if (strlen($a) === 0) {
+        continue;
+    }
+
+    if ($a[0] !== '-') {
+        // Not an option. Assume that it is a file we should parse
+        $files[] = $a;
+        continue;
+    }
+
+    if (strpos($a, '=') !== false) {
+        $p = strpos($a, '=');
+        $v = substr($a, $p + 1);
+        $a = substr($a, 0, $p);
+    } else {
+        $v = null;
+    }
+
+    // Map short options to long options
+    $shortOptMap = [
+        '-h' => '--help',
+        '-o' => '--out-dir',
+        '-s' => '--stdout',
+    ];
+    if (array_key_exists($a, $shortOptMap)) {
+        $a = $shortOptMap[$a];
+    }
+
+    switch ($a) {
+        case '--certificate':
+            if ($v === null || strlen($v) === 0) {
+                echo 'The --certficate option requires an parameter.'."\n";
+                echo 'Please run `'.$progName.' --help` for usage information.'."\n";
+                exit(1);
+            }
+            $certificates[] = $v;
+            break;
+        case '--validate-fingerprint':
+            if ($v === null || strlen($v) === 0) {
+                echo 'The --validate-fingerprint option requires an parameter.'."\n";
+                echo 'Please run `'.$progName.' --help` for usage information.'."\n";
+                exit(1);
+            }
+            $validateFingerprint = $v;
+            break;
+        case '--help':
+            printHelp();
+            exit(0);
+        case '--out-dir':
+            if ($v === null || strlen($v) === 0) {
+                echo 'The --out-dir option requires an parameter.'."\n";
+                echo 'Please run `'.$progName.' --help` for usage information.'."\n";
+                exit(1);
+            }
+            $outputDir = $baseDir.($v[0] == '/' ? $v : '/'.$v);
+            break;
+        case '--stdout':
+            $toStdOut = true;
+            break;
+        default:
+            echo 'Unknown option: '.$a."\n";
+            echo 'Please run `'.$progName.' --help` for usage information.'."\n";
+            exit(1);
+    }
 }
 
-if(count($files) === 0) {
-	echo($progName . ': Missing input files. Please run `' . $progName . ' --help` for usage information.' . "\n");
-	exit(1);
+if (count($files) === 0) {
+    echo $progName.': Missing input files. Please run `'.$progName.' --help` for usage information.'."\n";
+    exit(1);
 }
 
-
-
-
-/* The metadata global variable will be filled with the metadata we extract. */
-$metaloader = new sspmod_metarefresh_MetaLoader();
-
-foreach($files as $f) {
-	$source = array('src' => $f);
-	if (isset($certificates)) $source['certificates'] = $certificates;
-	if (isset($validateFingerprint)) $source['validateFingerprint'] = $validateFingerprint;
-	$metaloader->loadSource($source);
+// The metadata global variable will be filled with the metadata we extract
+$metaloader = new \SimpleSAML\Module\metarefresh\MetaLoader();
+
+foreach ($files as $f) {
+    $source = ['src' => $f];
+    if (isset($certificates)) {
+        $source['certificates'] = $certificates;
+    }
+    if (isset($validateFingerprint)) {
+        $source['validateFingerprint'] = $validateFingerprint;
+    }
+    $metaloader->loadSource($source);
 }
 
-if($toStdOut) {
-	$metaloader->dumpMetadataStdOut();
+if ($toStdOut) {
+    $metaloader->dumpMetadataStdOut();
 } else {
-	$metaloader->writeMetadataFiles($outputDir);
+    $metaloader->writeMetadataFiles($outputDir);
 }
 
 /**
  * This function prints the help output.
  */
-function printHelp() {
-	global $progName;
-
-	/*   '======================================================================' */
-	echo('Usage: ' . $progName . ' [options] [files]' . "\n");
-	echo("\n");
-	echo('This program parses a SAML metadata files and output pieces that can' . "\n");
-	echo('be added to the metadata files in metadata/.' . "\n");
-	echo("\n");
-	echo('Options:' . "\n");
-	echo(' --certificate=<FILE>         The certificate which should be used' . "\n");
-	echo('                              to check the signature of the metadata.' . "\n");
-	echo('                              The file are stored in the cert dir.' . "\n");
-	echo('                              It is possibility to add multiple' . "\n");
-	echo('                              --certificate options to handle' . "\n");
-	echo('                              key rollover.' . "\n");
-	echo(' --validate-fingerprint=<FINGERPRINT>' . "\n");
-	echo('                              Check the signature of the metadata,' . "\n");
-	echo('                              and check the fingerprint of the' . "\n");
-	echo('                              certificate against <FINGERPRINT>.' . "\n");
-	echo(' -h, --help                   Print this help.' . "\n");
-	echo(' -o=<DIR>, --out-dir=<DIR>    Write the output to this directory. The' . "\n");
-	echo('                              default directory is metadata-generated/.' . "\n");
-	echo('                              Path will be relative to the SimpleSAMLphp' . "\n");
-	echo('                              base directory.' . "\n");
-	echo(' -s, --stdout                 Write the output to stdout instead of' . "\n");
-	echo('                              seperate files in the output directory.' . "\n");
-	echo("\n");
+function printHelp()
+{
+    global $progName;
+
+    /*   '======================================================================' */
+    echo 'Usage: '.$progName.' [options] [files]'."\n";
+    echo "\n";
+    echo 'This program parses a SAML metadata files and output pieces that can'."\n";
+    echo 'be added to the metadata files in metadata/.'."\n";
+    echo "\n";
+    echo 'Options:'."\n";
+    echo ' --certificate=<FILE>         The certificate which should be used'."\n";
+    echo '                              to check the signature of the metadata.'."\n";
+    echo '                              The file are stored in the cert dir.'."\n";
+    echo '                              It is possibility to add multiple'."\n";
+    echo '                              --certificate options to handle'."\n";
+    echo '                              key rollover.'."\n";
+    echo ' --validate-fingerprint=<FINGERPRINT>'."\n";
+    echo '                              Check the signature of the metadata,'."\n";
+    echo '                              and check the fingerprint of the'."\n";
+    echo '                              certificate against <FINGERPRINT>.'."\n";
+    echo ' -h, --help                   Print this help.'."\n";
+    echo ' -o=<DIR>, --out-dir=<DIR>    Write the output to this directory. The'."\n";
+    echo '                              default directory is metadata-generated/.'."\n";
+    echo '                              Path will be relative to the SimpleSAMLphp'."\n";
+    echo '                              base directory.'."\n";
+    echo ' -s, --stdout                 Write the output to stdout instead of'."\n";
+    echo '                              seperate files in the output directory.'."\n";
+    echo "\n";
 }
diff --git a/modules/metarefresh/config-templates/config-metarefresh.php b/modules/metarefresh/config-templates/config-metarefresh.php
index 0147b1850763e5d258728bbf3191ded5340de1d2..c8009d4c2756ced568d6507b286e833431040f46 100644
--- a/modules/metarefresh/config-templates/config-metarefresh.php
+++ b/modules/metarefresh/config-templates/config-metarefresh.php
@@ -1,96 +1,92 @@
 <?php
 
-$config = array(
+$config = [
+    /*
+     * Global blacklist: entityIDs that should be excluded from ALL sets.
+     */
+    #'blacklist' = array(
+    #    'http://my.own.uni/idp'
+    #),
 
-	/*
-	 * Global blacklist: entityIDs that should be excluded from ALL sets.
-	 */
-	#'blacklist' = array(
-	#	'http://my.own.uni/idp'
-	#),
-	
-	/*
-	 * Conditional GET requests
-	 * Efficient downloading so polling can be done more frequently.
-	 * Works for sources that send 'Last-Modified' or 'Etag' headers.
-	 * Note that the 'data' directory needs to be writable for this to work.
-	 */
-	#'conditionalGET'	=> TRUE,
+    /*
+     * Conditional GET requests
+     * Efficient downloading so polling can be done more frequently.
+     * Works for sources that send 'Last-Modified' or 'Etag' headers.
+     * Note that the 'data' directory needs to be writable for this to work.
+     */
+    #'conditionalGET' => true,
 
-	'sets' => array(
+    'sets' => [
 
-		'kalmar' => array(
-			'cron'		=> array('hourly'),
-			'sources'	=> array(
-				array(
-					/*
-					 * entityIDs that should be excluded from this src.
-					 */
-					#'blacklist' => array(
-					#	'http://some.other.uni/idp',
-					#),
+        'kalmar' => [
+            'cron' => ['hourly'],
+            'sources' => [
+                [
+                    /*
+                     * entityIDs that should be excluded from this src.
+                     */
+                    #'blacklist' => array(
+                    #    'http://some.other.uni/idp',
+                    #),
 
-					/*
-					 * Whitelist: only keep these EntityIDs.
-					 */
-					#'whitelist' => array(
-					#	'http://some.uni/idp',
-					#	'http://some.other.uni/idp',
-					#),
+                    /*
+                     * Whitelist: only keep these EntityIDs.
+                     */
+                    #'whitelist' => array(
+                    #    'http://some.uni/idp',
+                    #    'http://some.other.uni/idp',
+                    #),
 
-					#'conditionalGET' => TRUE,
-					'src' => 'https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral&set=saml2&exclude=norway',
-					'certificates' => array(
-						'current.crt',
-						'rollover.crt',
-					),
-					'validateFingerprint' => '59:1D:4B:46:70:46:3E:ED:A9:1F:CC:81:6D:C0:AF:2A:09:2A:A8:01',
-					'template' => array(
-						'tags'	=> array('kalmar'),
-						'authproc' => array(
-							51 => array('class' => 'core:AttributeMap', 'oid2name'),
-						),
-					),
+                    #'conditionalGET' => true,
+                    'src' => 'https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral&set=saml2&exclude=norway',
+                    'certificates' => [
+                        'current.crt',
+                        'rollover.crt',
+                    ],
+                    'validateFingerprint' => '59:1D:4B:46:70:46:3E:ED:A9:1F:CC:81:6D:C0:AF:2A:09:2A:A8:01',
+                    'template' => [
+                        'tags' => ['kalmar'],
+                        'authproc' => [
+                            51 => ['class' => 'core:AttributeMap', 'oid2name'],
+                        ],
+                    ],
 
-					/*
-					 * The sets of entities to load, any combination of:
-					 *  - 'saml20-idp-remote'
-					 *  - 'saml20-sp-remote'
-					 *  - 'shib13-idp-remote'
-					 *  - 'shib13-sp-remote'
-					 *  - 'attributeauthority-remote'
-					 *
-					 * All of them will be used by default.
-					 *
-					 * This option takes precedence over the same option per metadata set.
-					 */
-					//'types' => array(),
-				),
-			),
-			'expireAfter' 		=> 60*60*24*4, // Maximum 4 days cache time
-			'outputDir' 	=> 'metadata/metadata-kalmar-consuming/',
-
-			/*
-			 * Which output format the metadata should be saved as.
-			 * Can be 'flatfile' or 'serialize'. 'flatfile' is the default.
-			 */
-			'outputFormat' => 'flatfile',
-
-
-			/*
-			 * The sets of entities to load, any combination of:
-			 *  - 'saml20-idp-remote'
-			 *  - 'saml20-sp-remote'
-			 *  - 'shib13-idp-remote'
-			 *  - 'shib13-sp-remote'
-			 *  - 'attributeauthority-remote'
-			 *
-			 * All of them will be used by default.
-			 */
-			//'types' => array(),
-		),
-	),
-);
+                    /*
+                     * The sets of entities to load, any combination of:
+                     *  - 'saml20-idp-remote'
+                     *  - 'saml20-sp-remote'
+                     *  - 'shib13-idp-remote'
+                     *  - 'shib13-sp-remote'
+                     *  - 'attributeauthority-remote'
+                     *
+                     * All of them will be used by default.
+                     *
+                     * This option takes precedence over the same option per metadata set.
+                     */
+                    //'types' => [],
+                ],
+            ],
 
+            'expireAfter' => 34560060, // Maximum 4 days cache time (3600*24*4)
+            'outputDir' => 'metadata/metadata-kalmar-consuming/',
 
+            /*
+             * Which output format the metadata should be saved as.
+             * Can be 'flatfile' or 'serialize'. 'flatfile' is the default.
+             */
+            'outputFormat' => 'flatfile',
 
+            /*
+             * The sets of entities to load, any combination of:
+             *  - 'saml20-idp-remote'
+             *  - 'saml20-sp-remote'
+             *  - 'shib13-idp-remote'
+             *  - 'shib13-sp-remote'
+             *  - 'attributeauthority-remote'
+             *
+             * All of them will be used by default.
+             */
+            //'types' => [],
+        ],
+    ],
+];
diff --git a/modules/metarefresh/dictionaries/metarefresh.definition.json b/modules/metarefresh/dictionaries/metarefresh.definition.json
new file mode 100644
index 0000000000000000000000000000000000000000..8bfb51c4af39570be0a83c43531693df4caa64c1
--- /dev/null
+++ b/modules/metarefresh/dictionaries/metarefresh.definition.json
@@ -0,0 +1,12 @@
+{
+    "frontpage_link": {
+        "en": "Metarefresh: fetch metadata"
+    },
+    "metarefresh_header": {
+        "en": "Metarefresh fetch"
+    },
+    "no_output": {
+        "en": "No output from metarefresh."
+    }
+}
+
diff --git a/modules/metarefresh/dictionaries/metarefresh.translation.json b/modules/metarefresh/dictionaries/metarefresh.translation.json
new file mode 100644
index 0000000000000000000000000000000000000000..2023ecba4f39e60385911c6708ac187bf2db6c8e
--- /dev/null
+++ b/modules/metarefresh/dictionaries/metarefresh.translation.json
@@ -0,0 +1,9 @@
+{
+    "frontpage_link": {
+    },
+    "metarefresh_header": {
+    },
+    "no_output": {
+    }
+}
+
diff --git a/modules/metarefresh/hooks/hook_cron.php b/modules/metarefresh/hooks/hook_cron.php
index a845396012e2bdb154bb55061cb0596531220e02..4ab82e2272d8eaf4fa9ed4b8f7d5016bf8bbbdad 100644
--- a/modules/metarefresh/hooks/hook_cron.php
+++ b/modules/metarefresh/hooks/hook_cron.php
@@ -1,114 +1,118 @@
 <?php
+
+use \SimpleSAML\Logger;
+
 /**
  * Hook to run a cron job.
  *
  * @param array &$croninfo  Output
  */
-function metarefresh_hook_cron(&$croninfo) {
-	assert(is_array($croninfo));
-	assert(array_key_exists('summary', $croninfo));
-	assert(array_key_exists('tag', $croninfo));
-
-	SimpleSAML\Logger::info('cron [metarefresh]: Running cron in cron tag [' . $croninfo['tag'] . '] ');
-
-	try {
-		$config = SimpleSAML_Configuration::getInstance();
-		$mconfig = SimpleSAML_Configuration::getOptionalConfig('config-metarefresh.php');
-
-		$sets = $mconfig->getConfigList('sets', array());
-		$stateFile = $config->getPathValue('datadir', 'data/') . 'metarefresh-state.php';
-
-		foreach ($sets AS $setkey => $set) {
-			// Only process sets where cron matches the current cron tag
-			$cronTags = $set->getArray('cron');
-			if (!in_array($croninfo['tag'], $cronTags, true)) continue;
-
-			SimpleSAML\Logger::info('cron [metarefresh]: Executing set [' . $setkey . ']');
-
-			$expireAfter = $set->getInteger('expireAfter', NULL);
-			if ($expireAfter !== NULL) {
-				$expire = time() + $expireAfter;
-			} else {
-				$expire = NULL;
-			}
-
-			$outputDir = $set->getString('outputDir');
-			$outputDir = $config->resolvePath($outputDir);
-			$outputFormat = $set->getValueValidate('outputFormat', array('flatfile', 'serialize'), 'flatfile');
-
-			$oldMetadataSrc = SimpleSAML_Metadata_MetaDataStorageSource::getSource(array(
-				'type' => $outputFormat,
-				'directory' => $outputDir,
-			));
-
-			$metaloader = new sspmod_metarefresh_MetaLoader($expire, $stateFile, $oldMetadataSrc);
-
-			# Get global blacklist, whitelist and caching info
-			$blacklist = $mconfig->getArray('blacklist', array());
-			$whitelist = $mconfig->getArray('whitelist', array());
-			$conditionalGET = $mconfig->getBoolean('conditionalGET', FALSE);
-
-			// get global type filters
-			$available_types = array(
-				'saml20-idp-remote',
-				'saml20-sp-remote',
-				'shib13-idp-remote',
-				'shib13-sp-remote',
-				'attributeauthority-remote'
-			);
-			$set_types = $set->getArrayize('types', $available_types);
-
-			foreach($set->getArray('sources') AS $source) {
-
-				// filter metadata by type of entity
-				if (isset($source['types'])) {
-					$metaloader->setTypes($source['types']);
-				} else {
-					$metaloader->setTypes($set_types);
-				}
-
-				# Merge global and src specific blacklists
-				if(isset($source['blacklist'])) {
-					$source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
-				} else {
-					$source['blacklist'] = $blacklist;
-				}
-
-				# Merge global and src specific whitelists
-				if(isset($source['whitelist'])) {
-					$source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
-				} else {
-					$source['whitelist'] = $whitelist;
-				}
-
-				# Let src specific conditionalGET override global one
-				if(!isset($source['conditionalGET'])) {
-					$source['conditionalGET'] = $conditionalGET;
-				}
-
-				SimpleSAML\Logger::debug('cron [metarefresh]: In set [' . $setkey . '] loading source ['  . $source['src'] . ']');
-				$metaloader->loadSource($source);
-			}
-
-			// Write state information back to disk
-			$metaloader->writeState();
-
-			switch ($outputFormat) {
-				case 'flatfile':
-					$metaloader->writeMetadataFiles($outputDir);
-					break;
-				case 'serialize':
-					$metaloader->writeMetadataSerialize($outputDir);
-					break;
-			}
-
-			if ($set->hasValue('arp')) {
-				$arpconfig = SimpleSAML_Configuration::loadFromArray($set->getValue('arp'));
-				$metaloader->writeARPfile($arpconfig);
-			}
-		}
-
-	} catch (Exception $e) {
-		$croninfo['summary'][] = 'Error during metarefresh: ' . $e->getMessage();
-	}
+function metarefresh_hook_cron(&$croninfo)
+{
+    assert(is_array($croninfo));
+    assert(array_key_exists('summary', $croninfo));
+    assert(array_key_exists('tag', $croninfo));
+
+    Logger::info('cron [metarefresh]: Running cron in cron tag ['.$croninfo['tag'].'] ');
+
+    try {
+        $config = \SimpleSAML\Configuration::getInstance();
+        $mconfig = \SimpleSAML\Configuration::getOptionalConfig('config-metarefresh.php');
+
+        $sets = $mconfig->getConfigList('sets', []);
+        $stateFile = $config->getPathValue('datadir', 'data/').'metarefresh-state.php';
+
+        foreach ($sets as $setkey => $set) {
+            // Only process sets where cron matches the current cron tag
+            $cronTags = $set->getArray('cron');
+            if (!in_array($croninfo['tag'], $cronTags, true)) {
+                continue;
+            }
+
+            Logger::info('cron [metarefresh]: Executing set ['.$setkey.']');
+
+            $expireAfter = $set->getInteger('expireAfter', null);
+            if ($expireAfter !== null) {
+                $expire = time() + $expireAfter;
+            } else {
+                $expire = null;
+            }
+
+            $outputDir = $set->getString('outputDir');
+            $outputDir = $config->resolvePath($outputDir);
+            $outputFormat = $set->getValueValidate('outputFormat', ['flatfile', 'serialize'], 'flatfile');
+
+            $oldMetadataSrc = \SimpleSAML\Metadata\MetaDataStorageSource::getSource([
+                'type' => $outputFormat,
+                'directory' => $outputDir,
+            ]);
+
+            $metaloader = new \SimpleSAML\Module\metarefresh\MetaLoader($expire, $stateFile, $oldMetadataSrc);
+
+            // Get global blacklist, whitelist and caching info
+            $blacklist = $mconfig->getArray('blacklist', []);
+            $whitelist = $mconfig->getArray('whitelist', []);
+            $conditionalGET = $mconfig->getBoolean('conditionalGET', false);
+
+            // get global type filters
+            $available_types = [
+                'saml20-idp-remote',
+                'saml20-sp-remote',
+                'shib13-idp-remote',
+                'shib13-sp-remote',
+                'attributeauthority-remote'
+            ];
+            $set_types = $set->getArrayize('types', $available_types);
+
+            foreach ($set->getArray('sources') as $source) {
+                // filter metadata by type of entity
+                if (isset($source['types'])) {
+                    $metaloader->setTypes($source['types']);
+                } else {
+                    $metaloader->setTypes($set_types);
+                }
+
+                // Merge global and src specific blacklists
+                if (isset($source['blacklist'])) {
+                    $source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
+                } else {
+                    $source['blacklist'] = $blacklist;
+                }
+
+                // Merge global and src specific whitelists
+                if (isset($source['whitelist'])) {
+                    $source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
+                } else {
+                    $source['whitelist'] = $whitelist;
+                }
+
+                // Let src specific conditionalGET override global one
+                if (!isset($source['conditionalGET'])) {
+                    $source['conditionalGET'] = $conditionalGET;
+                }
+
+                Logger::debug('cron [metarefresh]: In set ['.$setkey.'] loading source ['.$source['src'].']');
+                $metaloader->loadSource($source);
+            }
+
+            // Write state information back to disk
+            $metaloader->writeState();
+
+            switch ($outputFormat) {
+                case 'flatfile':
+                    $metaloader->writeMetadataFiles($outputDir);
+                    break;
+                case 'serialize':
+                    $metaloader->writeMetadataSerialize($outputDir);
+                    break;
+            }
+
+            if ($set->hasValue('arp')) {
+                $arpconfig = \SimpleSAML\Configuration::loadFromArray($set->getValue('arp'));
+                $metaloader->writeARPfile($arpconfig);
+            }
+        }
+    } catch (\Exception $e) {
+        $croninfo['summary'][] = 'Error during metarefresh: '.$e->getMessage();
+    }
 }
diff --git a/modules/metarefresh/hooks/hook_frontpage.php b/modules/metarefresh/hooks/hook_frontpage.php
index 60e7aef5e002c1b218ec9c5c5c336d57e7ed1d2f..e66c583f29758151ea05e792c06f0809340e85e9 100644
--- a/modules/metarefresh/hooks/hook_frontpage.php
+++ b/modules/metarefresh/hooks/hook_frontpage.php
@@ -4,13 +4,14 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function metarefresh_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
 
-	$links['federation'][] = array(
-		'href' => SimpleSAML\Module::getModuleURL('metarefresh/fetch.php'),
-		'text' => array('en' => 'Metarefresh: fetch metadata'),
-	);
+function metarefresh_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
 
+    $links['federation'][] = [
+        'href' => SimpleSAML\Module::getModuleURL('metarefresh/fetch.php'),
+        'text' => '{metarefresh:metarefresh:frontpage_link}',
+    ];
 }
diff --git a/modules/metarefresh/lib/ARP.php b/modules/metarefresh/lib/ARP.php
index 2af8e7680e2e3c9a6f2d5223803abe5797ca8229..c64ff3463f593c0ed0565b578e069eb70e7c43be 100644
--- a/modules/metarefresh/lib/ARP.php
+++ b/modules/metarefresh/lib/ARP.php
@@ -1,10 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\metarefresh;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
 
-class sspmod_metarefresh_ARP
+class ARP
 {
     /**
      * @var array
@@ -26,37 +29,37 @@ class sspmod_metarefresh_ARP
      */
     private $suffix;
 
-	/**
-	 * Constructor
-	 *
-	 * @param array $metadata
-     * @param string $attributemap
+    /**
+     * Constructor
+     *
+     * @param array $metadata
+     * @param string $attributemap_filename
      * @param string $prefix
      * @param string $suffix
-	 */
-    public function __construct($metadata, $attributemap, $prefix, $suffix)
+     */
+    public function __construct($metadata, $attributemap_filename, $prefix, $suffix)
     {
         $this->metadata = $metadata;
         $this->prefix = $prefix;
         $this->suffix = $suffix;
 
-        if (isset($attributemap)) {
-            $this->loadAttributeMap($attributemap);
+        if (isset($attributemap_filename)) {
+            $this->loadAttributeMap($attributemap_filename);
         }
     }
-	
+
     /**
-     * @param string $attributemap
+     * @param string $attributemap_filename
      *
      * @return void
      */
-    private function loadAttributeMap($attributemap)
+    private function loadAttributeMap($attributemap_filename)
     {
-        $config = SimpleSAML_Configuration::getInstance();
-        include($config->getPathValue('attributemap', 'attributemap/') . $attributemap . '.php');
-        // Note that $attributemap was a string before the call to include() and is now an array!
+        $config = \SimpleSAML\Configuration::getInstance();
+        include($config->getPathValue('attributemap', 'attributemap/').$attributemap_filename.'.php');
+        // Note that $attributemap is defined in the included attributemap-file!
         $this->attributes = $attributemap;
-	}
+    }
 
     /**
      * @param string $name
@@ -123,9 +126,9 @@ MSG;
     private function getEntryXML($entry)
     {
         $entityid = $entry['entityid'];
-        return '    <AttributeFilterPolicy id="' . $entityid .
-            '"><PolicyRequirementRule xsi:type="basic:AttributeRequesterString" value="' . $entityid .
-            '" />' . $this->getEntryXMLcontent($entry) . '</AttributeFilterPolicy>';
+        return '    <AttributeFilterPolicy id="'.$entityid.
+            '"><PolicyRequirementRule xsi:type="basic:AttributeRequesterString" value="'.$entityid.
+            '" />'.$this->getEntryXMLcontent($entry).'</AttributeFilterPolicy>';
     }
 
     /**
@@ -141,7 +144,7 @@ MSG;
 
         $ret = '';
         foreach ($entry['attributes'] as $a) {
-            $ret .= '            <AttributeRule attributeID="' . $this->getAttributeID($a) .
+            $ret .= '            <AttributeRule attributeID="'.$this->getAttributeID($a).
                 '"><PermitValueRule xsi:type="basic:ANY" /></AttributeRule>';
         }
         return $ret;
diff --git a/modules/metarefresh/lib/MetaLoader.php b/modules/metarefresh/lib/MetaLoader.php
index 800d6f20301a8c8256651ca8c42de4f2cc696c1e..b13e8a3c735681205b4b3b598a722ada949dbbc8 100644
--- a/modules/metarefresh/lib/MetaLoader.php
+++ b/modules/metarefresh/lib/MetaLoader.php
@@ -1,482 +1,508 @@
 <?php
-/*
- * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
+
+namespace SimpleSAML\Module\metarefresh;
+
+use SimpleSAML\Logger;
+
+/**
  * @package SimpleSAMLphp
+ * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  */
-class sspmod_metarefresh_MetaLoader
+
+class MetaLoader
 {
-	private $expire;
-	private $metadata;
-	private $oldMetadataSrc;
-	private $stateFile;
-	private $changed;
+    private $expire;
+    private $metadata;
+    private $oldMetadataSrc;
+    private $stateFile;
+    private $changed;
     private $state;
-	private $types = array(
-		'saml20-idp-remote',
-		'saml20-sp-remote',
-		'shib13-idp-remote',
-		'shib13-sp-remote',
-		'attributeauthority-remote'
-	);
-
-
-	/**
-	 * Constructor
-	 *
-	 * @param 
-	 */
-	public function __construct($expire = null, $stateFile = null, $oldMetadataSrc = null)
+    private $types = [
+        'saml20-idp-remote',
+        'saml20-sp-remote',
+        'shib13-idp-remote',
+        'shib13-sp-remote',
+        'attributeauthority-remote'
+    ];
+
+    /**
+     * Constructor
+     *
+     * @param integer $expire
+     * @param string  $stateFile
+     * @param object  $oldMetadataSrc
+     */
+    public function __construct($expire = null, $stateFile = null, $oldMetadataSrc = null)
     {
-		$this->expire = $expire;
-		$this->metadata = array();
-		$this->oldMetadataSrc = $oldMetadataSrc;
-		$this->stateFile = $stateFile;
-		$this->changed = false;
-
-		// Read file containing $state from disk
-		if(is_readable($stateFile)) {
-			require($stateFile);
-		}
-
-		$this->state = array();
-
-	}
-
-
-	/**
-	 * Get the types of entities that will be loaded.
-	 *
-	 * @return array The entity types allowed.
-	 */
-	public function getTypes()
-	{
-		return $this->types;
-	}
-
-
-	/**
-	 * Set the types of entities that will be loaded.
-	 *
-	 * @param string|array $types Either a string with the name of one single type allowed, or an array with a list of
-	 * types. Pass an empty array to reset to all types of entities.
-	 */
-	public function setTypes($types)
-	{
-		if (!is_array($types)) {
-			$types = array($types);
-		}
-		$this->types = $types;
-	}
-
-
-	/**
-	 * This function processes a SAML metadata file.
-	 *
-	 * @param $source
-	 */
-	public function loadSource($source)
+        $this->expire = $expire;
+        $this->metadata = [];
+        $this->oldMetadataSrc = $oldMetadataSrc;
+        $this->stateFile = $stateFile;
+        $this->changed = false;
+
+        // Read file containing $state from disk
+        if (is_readable($stateFile)) {
+            include $stateFile;
+        }
+
+        $this->state = [];
+    }
+
+    /**
+     * Get the types of entities that will be loaded.
+     *
+     * @return array The entity types allowed.
+     */
+    public function getTypes()
     {
-		if (preg_match('@^https?://@i', $source['src'])) {
-			// Build new HTTP context
-			$context = $this->createContext($source);
-
-			// GET!
-			try {
-				list($data, $responseHeaders) = \SimpleSAML\Utils\HTTP::fetch($source['src'], $context, true);
-			} catch(Exception $e) {
-				SimpleSAML\Logger::warning('metarefresh: ' . $e->getMessage());
-			}
-
-			// We have response headers, so the request succeeded
-			if (!isset($responseHeaders)) {
-				// No response headers, this means the request failed in some way, so re-use old data
-				SimpleSAML\Logger::debug('No response from ' . $source['src'] . ' - attempting to re-use cached metadata');
-				$this->addCachedMetadata($source);
-				return;
-			} elseif (preg_match('@^HTTP/1\.[01]\s304\s@', $responseHeaders[0])) {
-				// 304 response
-				SimpleSAML\Logger::debug('Received HTTP 304 (Not Modified) - attempting to re-use cached metadata');
-				$this->addCachedMetadata($source);
-				return;
-			} elseif (!preg_match('@^HTTP/1\.[01]\s200\s@', $responseHeaders[0])) {
-				// Other error
-				SimpleSAML\Logger::debug('Error from ' . $source['src'] . ' - attempting to re-use cached metadata');
-				$this->addCachedMetadata($source);
-				return;
-			}
-		} else {
-			// Local file.
-			$data = file_get_contents($source['src']);
-			$responseHeaders = null;
-		}
-
-		// Everything OK. Proceed.
-		if (isset($source['conditionalGET']) && $source['conditionalGET']) {
-			// Stale or no metadata, so a fresh copy
-			SimpleSAML\Logger::debug('Downloaded fresh copy');
-		}
-
-		try {
-			$entities = $this->loadXML($data, $source);
-		} catch(Exception $e) {
-			SimpleSAML\Logger::debug('XML parser error when parsing ' . $source['src'] . ' - attempting to re-use cached metadata');
-			$this->addCachedMetadata($source);
-			return;
-		}
-
-		foreach ($entities as $entity) {
-
-			if (isset($source['blacklist'])) {
-				if (!empty($source['blacklist']) && in_array($entity->getEntityID(), $source['blacklist'], true)) {
-					SimpleSAML\Logger::info('Skipping "' .  $entity->getEntityID() . '" - blacklisted.' . "\n");
-					continue;
-				}
-			}
-
-			if (isset($source['whitelist'])) {
-				if (!empty($source['whitelist']) && !in_array($entity->getEntityID(), $source['whitelist'], true)) {
-					SimpleSAML\Logger::info('Skipping "' .  $entity->getEntityID() . '" - not in the whitelist.' . "\n");
-					continue;
-				}
-			}
-
-			if (array_key_exists('certificates', $source) && $source['certificates'] !== null) {
-				if (!$entity->validateSignature($source['certificates'])) {
-					SimpleSAML\Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature using certificate.' . "\n");
-					continue;
-				}
-			}
-
-			if (array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== null) {
-				if (!array_key_exists('certificates', $source) || $source['certificates'] == null) {
-					if (!$entity->validateFingerprint($source['validateFingerprint'])) {
-						SimpleSAML\Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature using fingerprint.' . "\n");
-						continue;
-					}
-				} else {
-					SimpleSAML\Logger::info('Skipping validation with fingerprint since option certificate is set.' . "\n");
-				}
-			}
-
-			$template = null;
-			if (array_key_exists('template', $source)) $template = $source['template'];
-
-			$this->addMetadata($source['src'], $entity->getMetadata1xSP(), 'shib13-sp-remote', $template);
-			$this->addMetadata($source['src'], $entity->getMetadata1xIdP(), 'shib13-idp-remote', $template);
-			$this->addMetadata($source['src'], $entity->getMetadata20SP(), 'saml20-sp-remote', $template);
-			$this->addMetadata($source['src'], $entity->getMetadata20IdP(), 'saml20-idp-remote', $template);
-			$attributeAuthorities = $entity->getAttributeAuthorities();
-			if (!empty($attributeAuthorities)) {
-				$this->addMetadata($source['src'], $attributeAuthorities[0], 'attributeauthority-remote', $template);
-			}
-		}
-
-		$this->saveState($source, $responseHeaders);
-	}
-
-	/**
-	 * Create HTTP context, with any available caches taken into account
-	 */
-	private function createContext($source)
+        return $this->types;
+    }
+
+    /**
+     * Set the types of entities that will be loaded.
+     *
+     * @param string|array $types Either a string with the name of one single type allowed, or an array with a list of
+     * types. Pass an empty array to reset to all types of entities.
+     */
+    public function setTypes($types)
     {
-		$config = SimpleSAML_Configuration::getInstance();
-		$name = $config->getString('technicalcontact_name', null);
-		$mail = $config->getString('technicalcontact_email', null);
-
-		$rawheader = "User-Agent: SimpleSAMLphp metarefresh, run by $name <$mail>\r\n";
+        if (!is_array($types)) {
+            $types = [$types];
+        }
+        $this->types = $types;
+    }
+
+    /**
+     * This function processes a SAML metadata file.
+     *
+     * @param $source
+     */
+    public function loadSource($source)
+    {
+        if (preg_match('@^https?://@i', $source['src'])) {
+            // Build new HTTP context
+            $context = $this->createContext($source);
+
+            // GET!
+            try {
+                list($data, $responseHeaders) = \SimpleSAML\Utils\HTTP::fetch($source['src'], $context, true);
+            } catch (\Exception $e) {
+                Logger::warning('metarefresh: '.$e->getMessage());
+            }
+
+            // We have response headers, so the request succeeded
+            if (!isset($responseHeaders)) {
+                // No response headers, this means the request failed in some way, so re-use old data
+                Logger::debug('No response from '.$source['src'].' - attempting to re-use cached metadata');
+                $this->addCachedMetadata($source);
+                return;
+            } elseif (preg_match('@^HTTP/1\.[01]\s304\s@', $responseHeaders[0])) {
+                // 304 response
+                Logger::debug('Received HTTP 304 (Not Modified) - attempting to re-use cached metadata');
+                $this->addCachedMetadata($source);
+                return;
+            } elseif (!preg_match('@^HTTP/1\.[01]\s200\s@', $responseHeaders[0])) {
+                // Other error
+                Logger::debug('Error from '.$source['src'].' - attempting to re-use cached metadata');
+                $this->addCachedMetadata($source);
+                return;
+            }
+        } else {
+            // Local file.
+            $data = file_get_contents($source['src']);
+            $responseHeaders = null;
+        }
+
+        // Everything OK. Proceed.
+        if (isset($source['conditionalGET']) && $source['conditionalGET']) {
+            // Stale or no metadata, so a fresh copy
+            Logger::debug('Downloaded fresh copy');
+        }
+
+        try {
+            $entities = $this->loadXML($data, $source);
+        } catch (\Exception $e) {
+            Logger::debug('XML parser error when parsing '.$source['src'].' - attempting to re-use cached metadata');
+            Logger::debug('XML parser returned: '.$e->getMessage());
+            $this->addCachedMetadata($source);
+            return;
+        }
+
+        foreach ($entities as $entity) {
+            if (isset($source['blacklist'])) {
+                if (!empty($source['blacklist']) && in_array($entity->getEntityId(), $source['blacklist'], true)) {
+                    Logger::info('Skipping "'.$entity->getEntityId().'" - blacklisted.'."\n");
+                    continue;
+                }
+            }
+
+            if (isset($source['whitelist'])) {
+                if (!empty($source['whitelist']) && !in_array($entity->getEntityId(), $source['whitelist'], true)) {
+                    Logger::info('Skipping "'.$entity->getEntityId().'" - not in the whitelist.'."\n");
+                    continue;
+                }
+            }
+
+            if (array_key_exists('certificates', $source) && $source['certificates'] !== null) {
+                if (!$entity->validateSignature($source['certificates'])) {
+                    Logger::info(
+                        'Skipping "'.$entity->getEntityId().'" - could not verify signature using certificate.'."\n"
+                    );
+                    continue;
+                }
+            }
+
+            if (array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== null) {
+                if (!array_key_exists('certificates', $source) || $source['certificates'] == null) {
+                    if (!$entity->validateFingerprint($source['validateFingerprint'])) {
+                        Logger::info(
+                            'Skipping "'.$entity->getEntityId().'" - could not verify signature using fingerprint.'."\n"
+                        );
+                        continue;
+                    }
+                } else {
+                    Logger::info('Skipping validation with fingerprint since option certificate is set.'."\n");
+                }
+            }
+
+            $template = null;
+            if (array_key_exists('template', $source)) {
+                $template = $source['template'];
+            }
+
+            if (in_array('shib13-sp-remote', $this->types, true)) {
+                $this->addMetadata($source['src'], $entity->getMetadata1xSP(), 'shib13-sp-remote', $template);
+            }
+            if (in_array('shib13-idp-remote', $this->types, true)) {
+                $this->addMetadata($source['src'], $entity->getMetadata1xIdP(), 'shib13-idp-remote', $template);
+            }
+            if (in_array('saml20-sp-remote', $this->types, true)) {
+                $this->addMetadata($source['src'], $entity->getMetadata20SP(), 'saml20-sp-remote', $template);
+            }
+            if (in_array('saml20-idp-remote', $this->types, true)) {
+                $this->addMetadata($source['src'], $entity->getMetadata20IdP(), 'saml20-idp-remote', $template);
+            }
+            if (in_array('attributeauthority-remote', $this->types, true)) {
+                $attributeAuthorities = $entity->getAttributeAuthorities();
+                if (!empty($attributeAuthorities)) {
+                    $this->addMetadata(
+                        $source['src'],
+                        $attributeAuthorities[0],
+                        'attributeauthority-remote',
+                        $template
+                    );
+                }
+            }
+        }
+
+        $this->saveState($source, $responseHeaders);
+    }
+
+    /**
+     * Create HTTP context, with any available caches taken into account
+     */
+    private function createContext($source)
+    {
+        $config = \SimpleSAML\Configuration::getInstance();
+        $name = $config->getString('technicalcontact_name', null);
+        $mail = $config->getString('technicalcontact_email', null);
 
-		if (isset($source['conditionalGET']) && $source['conditionalGET']) {
-			if (array_key_exists($source['src'], $this->state)) {
+        $rawheader = "User-Agent: SimpleSAMLphp metarefresh, run by $name <$mail>\r\n";
 
-				$sourceState = $this->state[$source['src']];
+        if (isset($source['conditionalGET']) && $source['conditionalGET']) {
+            if (array_key_exists($source['src'], $this->state)) {
+                $sourceState = $this->state[$source['src']];
 
-				if (isset($sourceState['last-modified'])) {
-					$rawheader .= 'If-Modified-Since: ' . $sourceState['last-modified'] . "\r\n";
-				}
+                if (isset($sourceState['last-modified'])) {
+                    $rawheader .= 'If-Modified-Since: '.$sourceState['last-modified']."\r\n";
+                }
 
-				if (isset($sourceState['etag'])) {
-					$rawheader .= 'If-None-Match: ' . $sourceState['etag'] . "\r\n";
-				}
-			}
-		}
+                if (isset($sourceState['etag'])) {
+                    $rawheader .= 'If-None-Match: '.$sourceState['etag']."\r\n";
+                }
+            }
+        }
 
-		return array('http' => array('header' => $rawheader));
-	}
+        return ['http' => ['header' => $rawheader]];
+    }
 
 
-	private function addCachedMetadata($source)
+    private function addCachedMetadata($source)
     {
-		if (isset($this->oldMetadataSrc)) {
-			foreach ($this->types as $type) {
-				foreach ($this->oldMetadataSrc->getMetadataSet($type) as $entity) {
-					if (array_key_exists('metarefresh:src', $entity)) {
-						if ($entity['metarefresh:src'] == $source['src']) {
-							$this->addMetadata($source['src'], $entity, $type);
-						}
-					}
-				}
-			}
-		}
-	}
-
-
-	/**
-	 * Store caching state data for a source
-	 */
-	private function saveState($source, $responseHeaders)
+        if (isset($this->oldMetadataSrc)) {
+            foreach ($this->types as $type) {
+                foreach ($this->oldMetadataSrc->getMetadataSet($type) as $entity) {
+                    if (array_key_exists('metarefresh:src', $entity)) {
+                        if ($entity['metarefresh:src'] == $source['src']) {
+                            $this->addMetadata($source['src'], $entity, $type);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Store caching state data for a source
+     */
+    private function saveState($source, $responseHeaders)
     {
-		if (isset($source['conditionalGET']) && $source['conditionalGET']) {
-			// Headers section
-			$candidates = array('last-modified', 'etag');
-
-			foreach ($candidates as $candidate) {
-				if (array_key_exists($candidate, $responseHeaders)) {
-					$this->state[$source['src']][$candidate] = $responseHeaders[$candidate];
-				}
-			}
-
-			if (!empty($this->state[$source['src']])) {
-				// Timestamp when this src was requested.
-				$this->state[$source['src']]['requested_at'] = $this->getTime();
-
-				$this->changed = true;
-			}
-		}
-	}
-
-
-	/**
-	 * Parse XML metadata and return entities
-	 */
-	private function loadXML($data, $source)
+        if (isset($source['conditionalGET']) && $source['conditionalGET']) {
+            // Headers section
+            if ($responseHeaders !== null) {
+                $candidates = ['last-modified', 'etag'];
+
+                foreach ($candidates as $candidate) {
+                    if (array_key_exists($candidate, $responseHeaders)) {
+                        $this->state[$source['src']][$candidate] = $responseHeaders[$candidate];
+                    }
+                }
+            }
+
+            if (!empty($this->state[$source['src']])) {
+                // Timestamp when this src was requested.
+                $this->state[$source['src']]['requested_at'] = $this->getTime();
+                $this->changed = true;
+            }
+        }
+    }
+
+    /**
+     * Parse XML metadata and return entities
+     */
+    private function loadXML($data, $source)
     {
-		try {
-			$doc = \SAML2\DOMDocumentFactory::fromString($data);
-		} catch (Exception $e) {
-			throw new Exception('Failed to read XML from ' . $source['src']);
-		}
-		if ($doc->documentElement === null) {
-			throw new Exception('Opened file is not an XML document: ' . $source['src']);
-		}
-		return SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($doc->documentElement);
-	}
-
-
-	/**
-	 * This function writes the state array back to disk
-	 */
-	public function writeState()
+        try {
+            $doc = \SAML2\DOMDocumentFactory::fromString($data);
+        } catch (\Exception $e) {
+            throw new \Exception('Failed to read XML from '.$source['src']);
+        }
+        if ($doc->documentElement === null) {
+            throw new \Exception('Opened file is not an XML document: '.$source['src']);
+        }
+        return \SimpleSAML\Metadata\SAMLParser::parseDescriptorsElement($doc->documentElement);
+    }
+
+
+    /**
+     * This function writes the state array back to disk
+     */
+    public function writeState()
     {
-		if ($this->changed) {
-			SimpleSAML\Logger::debug('Writing: ' . $this->stateFile);
-            SimpleSAML\Utils\System::writeFile(
-				$this->stateFile,
-				"<?php\n/* This file was generated by the metarefresh module at ".$this->getTime() . ".\n".
-				" Do not update it manually as it will get overwritten. */\n".
-				'$state = ' . var_export($this->state, true) . ";\n?>\n",
-				0644
-			);
-		}
-	}
-
-
-	/**
-	 * This function writes the metadata to stdout.
-	 */
-	public function dumpMetadataStdOut()
+        if ($this->changed) {
+            Logger::debug('Writing: '.$this->stateFile);
+            \SimpleSAML\Utils\System::writeFile(
+                $this->stateFile,
+                "<?php\n/* This file was generated by the metarefresh module at ".$this->getTime().".\n".
+                " Do not update it manually as it will get overwritten. */\n".
+                '$state = '.var_export($this->state, true).";\n?>\n",
+                0644
+            );
+        }
+    }
+
+
+    /**
+     * This function writes the metadata to stdout.
+     */
+    public function dumpMetadataStdOut()
     {
-		foreach ($this->metadata as $category => $elements) {
-	
-			echo '/* The following data should be added to metadata/' . $category . '.php. */' . "\n";
-	
-	
-			foreach ($elements as $m) {
-				$filename = $m['filename'];
-				$entityID = $m['metadata']['entityid'];
-	
-				echo "\n";
-				echo '/* The following metadata was generated from ' . $filename . ' on ' . $this->getTime() . '. */' . "\n";
-				echo '$metadata[\'' . addslashes($entityID) . '\'] = ' . var_export($m['metadata'], true) . ';' . "\n";
-			}
-	
-	
-			echo "\n";
-			echo '/* End of data which should be added to metadata/' . $category . '.php. */' . "\n";
-			echo "\n";
-		}
-	}
-
-	
-	/**
-	 * This function adds metadata from the specified file to the list of metadata.
-	 * This function will return without making any changes if $metadata is NULL.
-	 *
-	 * @param $filename The filename the metadata comes from.
-	 * @param $metadata The metadata.
-	 * @param $type The metadata type.
-	 */
-	private function addMetadata($filename, $metadata, $type, $template = null)
+        foreach ($this->metadata as $category => $elements) {
+            echo '/* The following data should be added to metadata/'.$category.'.php. */'."\n";
+
+            foreach ($elements as $m) {
+                $filename = $m['filename'];
+                $entityID = $m['metadata']['entityid'];
+
+                echo "\n";
+                echo '/* The following metadata was generated from '.$filename.' on '.$this->getTime().'. */'."\n";
+                echo '$metadata[\''.addslashes($entityID).'\'] = '.var_export($m['metadata'], true).';'."\n";
+            }
+
+            echo "\n";
+            echo '/* End of data which should be added to metadata/'.$category.'.php. */'."\n";
+            echo "\n";
+        }
+    }
+
+
+    /**
+     * This function adds metadata from the specified file to the list of metadata.
+     * This function will return without making any changes if $metadata is NULL.
+     *
+     * @param string $filename The filename the metadata comes from.
+     * @param array  $metadata The metadata.
+     * @param string $type The metadata type.
+     */
+    private function addMetadata($filename, $metadata, $type, $template = null)
     {
-		if ($metadata === null) {
-			return;
-		}
-	
-		if (isset($template)) {
-			$metadata = array_merge($metadata, $template);
-		}
-	
-		$metadata['metarefresh:src'] = $filename;
-		if (!array_key_exists($type, $this->metadata)) {
-			$this->metadata[$type] = array();
-		}
-		
-		// If expire is defined in constructor...
-		if (!empty($this->expire)) {
-			
-			// If expire is already in metadata
-			if (array_key_exists('expire', $metadata)) {
-			
-				// Override metadata expire with more restrictive global config-
-				if ($this->expire < $metadata['expire'])
-					$metadata['expire'] = $this->expire;
-					
-			// If expire is not already in metadata use global config
-			} else {
-				$metadata['expire'] = $this->expire;
-			}
-		}
-		
-
-	
-		$this->metadata[$type][] = array('filename' => $filename, 'metadata' => $metadata);
-	}
-
-
-	/**
-	 * This function writes the metadata to an ARP file
-	 */
-	public function writeARPfile($config)
+        if ($metadata === null) {
+            return;
+        }
+
+        if (isset($template)) {
+            $metadata = array_merge($metadata, $template);
+        }
+
+        $metadata['metarefresh:src'] = $filename;
+        if (!array_key_exists($type, $this->metadata)) {
+            $this->metadata[$type] = [];
+        }
+
+        // If expire is defined in constructor...
+        if (!empty($this->expire)) {
+            // If expire is already in metadata
+            if (array_key_exists('expire', $metadata)) {
+                // Override metadata expire with more restrictive global config
+                if ($this->expire < $metadata['expire']) {
+                    $metadata['expire'] = $this->expire;
+                }
+
+                // If expire is not already in metadata use global config
+            } else {
+                $metadata['expire'] = $this->expire;
+            }
+        }
+        $this->metadata[$type][] = ['filename' => $filename, 'metadata' => $metadata];
+    }
+
+
+    /**
+     * This function writes the metadata to an ARP file
+     */
+    public function writeARPfile($config)
     {
-		assert($config instanceof SimpleSAML_Configuration);
-		
-		$arpfile = $config->getValue('arpfile');
-		$types = array('saml20-sp-remote');
-		
-		$md = array();
-		foreach ($this->metadata as $category => $elements) {
-			if (!in_array($category, $types, true)) continue;
-			$md = array_merge($md, $elements);
-		}
-		
-		// $metadata, $attributemap, $prefix, $suffix
-		$arp = new sspmod_metarefresh_ARP($md, 
-			$config->getValue('attributemap', ''),  
-			$config->getValue('prefix', ''),  
-			$config->getValue('suffix', '')
-		);
-		
-		
-		$arpxml = $arp->getXML();
-
-		SimpleSAML\Logger::info('Writing ARP file: ' . $arpfile . "\n");
-		file_put_contents($arpfile, $arpxml);
-	}
-	
-	
-	/**
-	 * This function writes the metadata to to separate files in the output directory.
-	 */
-	public function writeMetadataFiles($outputDir)
+        assert($config instanceof \SimpleSAML\Configuration);
+
+        $arpfile = $config->getValue('arpfile');
+        $types = ['saml20-sp-remote'];
+
+        $md = [];
+        foreach ($this->metadata as $category => $elements) {
+            if (!in_array($category, $types, true)) {
+                continue;
+            }
+            $md = array_merge($md, $elements);
+        }
+
+        // $metadata, $attributemap, $prefix, $suffix
+        $arp = new \SimpleSAML\Module\metarefresh\ARP(
+            $md,
+            $config->getValue('attributemap', ''),
+            $config->getValue('prefix', ''),
+            $config->getValue('suffix', '')
+        );
+
+
+        $arpxml = $arp->getXML();
+
+        Logger::info('Writing ARP file: '.$arpfile."\n");
+        file_put_contents($arpfile, $arpxml);
+    }
+
+
+    /**
+     * This function writes the metadata to to separate files in the output directory.
+     */
+    public function writeMetadataFiles($outputDir)
     {
-		while (strlen($outputDir) > 0 && $outputDir[strlen($outputDir) - 1] === '/') {
-			$outputDir = substr($outputDir, 0, strlen($outputDir) - 1);
-		}
-	
-		if (!file_exists($outputDir)) {
-			SimpleSAML\Logger::info('Creating directory: ' . $outputDir . "\n");
-			$res = @mkdir($outputDir, 0777, true);
-			if ($res === false) {
-				throw new Exception('Error creating directory: ' . $outputDir);
-			}
-		}
-	
-		foreach ($this->types as $type) {
-			$filename = $outputDir . '/' . $type . '.php';
-
-			if (array_key_exists($type, $this->metadata)) {
-				$elements = $this->metadata[$type];
-				SimpleSAML\Logger::debug('Writing: ' . $filename);
-
-				$content  = '<?php' . "\n" . '/* This file was generated by the metarefresh module at '. $this->getTime() . "\n";
-				$content .= ' Do not update it manually as it will get overwritten' . "\n" . '*/' . "\n";
-
-				foreach ($elements as $m) {
-					$entityID = $m['metadata']['entityid'];
-					$content .= "\n";
-					$content .= '$metadata[\'' . addslashes($entityID) . '\'] = ' . var_export($m['metadata'], TRUE) . ';' . "\n";
-				}
-
-				$content .= "\n" . '?>';
-
-                SimpleSAML\Utils\System::writeFile($filename, $content, 0644);
-			} elseif (is_file($filename)) {
-				if (unlink($filename)) {
-					SimpleSAML\Logger::debug('Deleting stale metadata file: ' . $filename);
-				} else {
-					SimpleSAML\Logger::warning('Could not delete stale metadata file: ' . $filename);
-				}
-			}
-		}
-	}
-
-
-	/**
-	 * Save metadata for loading with the 'serialize' metadata loader.
-	 *
-	 * @param string $outputDir  The directory we should save the metadata to.
-	 */
-	public function writeMetadataSerialize($outputDir)
+        while (strlen($outputDir) > 0 && $outputDir[strlen($outputDir) - 1] === '/') {
+            $outputDir = substr($outputDir, 0, strlen($outputDir) - 1);
+        }
+
+        if (!file_exists($outputDir)) {
+            Logger::info('Creating directory: '.$outputDir."\n");
+            $res = @mkdir($outputDir, 0777, true);
+            if ($res === false) {
+                throw new \Exception('Error creating directory: '.$outputDir);
+            }
+        }
+
+        foreach ($this->types as $type) {
+            $filename = $outputDir.'/'.$type.'.php';
+
+            if (array_key_exists($type, $this->metadata)) {
+                $elements = $this->metadata[$type];
+                Logger::debug('Writing: '.$filename);
+
+                $content  = '<?php'."\n".'/* This file was generated by the metarefresh module at ';
+                $content .= $this->getTime()."\nDo not update it manually as it will get overwritten\n".'*/'."\n";
+
+                foreach ($elements as $m) {
+                    $entityID = $m['metadata']['entityid'];
+                    $content .= "\n".'$metadata[\''.
+                    $content .= addslashes($entityID).'\'] = '.var_export($m['metadata'], true).';'."\n";
+                }
+
+                $content .= "\n".'?>';
+
+                \SimpleSAML\Utils\System::writeFile($filename, $content, 0644);
+            } elseif (is_file($filename)) {
+                if (unlink($filename)) {
+                    Logger::debug('Deleting stale metadata file: '.$filename);
+                } else {
+                    Logger::warning('Could not delete stale metadata file: '.$filename);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Save metadata for loading with the 'serialize' metadata loader.
+     *
+     * @param string $outputDir  The directory we should save the metadata to.
+     */
+    public function writeMetadataSerialize($outputDir)
     {
-		assert(is_string($outputDir));
-
-		$metaHandler = new SimpleSAML_Metadata_MetaDataStorageHandlerSerialize(array('directory' => $outputDir));
-
-		/* First we add all the metadata entries to the metadata handler. */
-		foreach ($this->metadata as $set => $elements) {
-			foreach ($elements as $m) {
-				$entityId = $m['metadata']['entityid'];
-
-				SimpleSAML\Logger::debug('metarefresh: Add metadata entry ' .
-					var_export($entityId, true) . ' in set ' . var_export($set, true) . '.');
-				$metaHandler->saveMetadata($entityId, $set, $m['metadata']);
-			}
-		}
-
-		/* Then we delete old entries which should no longer exist. */
-		$ct = time();
-		foreach ($metaHandler->getMetadataSets() as $set) {
-			foreach ($metaHandler->getMetadataSet($set) as $entityId => $metadata) {
-				if (!array_key_exists('expire', $metadata)) {
-					SimpleSAML\Logger::warning('metarefresh: Metadata entry without expire timestamp: ' . var_export($entityId, true) .
-						' in set ' . var_export($set, true) . '.');
-					continue;
-				}
-				if ($metadata['expire'] > $ct) {
-					continue;
-				}
-				SimpleSAML\Logger::debug('metarefresh: ' . $entityId . ' expired ' . date('l jS \of F Y h:i:s A', $metadata['expire']) );
-				SimpleSAML\Logger::debug('metarefresh: Delete expired metadata entry ' .
-					var_export($entityId, true) . ' in set ' . var_export($set, true) . '. (' . ($ct - $metadata['expire']) . ' sec)');
-				$metaHandler->deleteMetadata($entityId, $set);
-			}
-		}
-	}
-
-
-	private function getTime()
+        assert(is_string($outputDir));
+
+        $metaHandler = new \SimpleSAML\Metadata\MetaDataStorageHandlerSerialize(['directory' => $outputDir]);
+
+        // First we add all the metadata entries to the metadata handler
+        foreach ($this->metadata as $set => $elements) {
+            foreach ($elements as $m) {
+                $entityId = $m['metadata']['entityid'];
+
+                Logger::debug(
+                    'metarefresh: Add metadata entry '.
+                    var_export($entityId, true).' in set '.var_export($set, true).'.'
+                );
+                $metaHandler->saveMetadata($entityId, $set, $m['metadata']);
+            }
+        }
+
+        // Then we delete old entries which should no longer exist
+        $ct = time();
+        foreach ($metaHandler->getMetadataSets() as $set) {
+            foreach ($metaHandler->getMetadataSet($set) as $entityId => $metadata) {
+                if (!array_key_exists('expire', $metadata)) {
+                    Logger::warning(
+                        'metarefresh: Metadata entry without expire timestamp: '.var_export($entityId, true).
+                        ' in set '.var_export($set, true).'.'
+                    );
+                    continue;
+                }
+                if ($metadata['expire'] > $ct) {
+                    continue;
+                }
+                Logger::debug('metarefresh: '.$entityId.' expired '.date('l jS \of F Y h:i:s A', $metadata['expire']));
+                Logger::debug(
+                    'metarefresh: Delete expired metadata entry '.
+                    var_export($entityId, true).' in set '.var_export($set, true).
+                    '. ('.($ct - $metadata['expire']).' sec)'
+                );
+                $metaHandler->deleteMetadata($entityId, $set);
+            }
+        }
+    }
+
+
+    private function getTime()
     {
-		/* The current date, as a string. */
-		date_default_timezone_set('UTC');
-		return date('Y-m-d\\TH:i:s\\Z');
-	}
+        // The current date, as a string
+        date_default_timezone_set('UTC');
+        return date('Y-m-d\\TH:i:s\\Z');
+    }
 }
diff --git a/modules/metarefresh/locales/en/LC_MESSAGES/metarefresh.po b/modules/metarefresh/locales/en/LC_MESSAGES/metarefresh.po
new file mode 100644
index 0000000000000000000000000000000000000000..483051bab4f733daa6bc6892c06e9cc43b5a73b4
--- /dev/null
+++ b/modules/metarefresh/locales/en/LC_MESSAGES/metarefresh.po
@@ -0,0 +1,25 @@
+
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: SimpleSAMLphp 1.15\n"
+"Report-Msgid-Bugs-To: simplesamlphp-translation@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-06 09:23+0200\n"
+"PO-Revision-Date: 2017-12-06 12:14+0200\n"
+"Last-Translator: \n"
+"Language: en\n"
+"Language-Team: \n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.3.4\n"
+
+msgid "metarefresh_header"
+msgstr "Metarefresh"
+
+msgid "metarefresh_no_output"
+msgstr "No output from metarefresh."
+
+msgid "metarefresh_fetched"
+msgstr "Fetched metadata"
diff --git a/modules/metarefresh/templates/fetch.tpl.php b/modules/metarefresh/templates/fetch.tpl.php
index 512f6f429f3cc6b937ee5e38a062ca66d61d98da..5a988ce74c1b4c3d03c188dc8956890a59a6e8b8 100644
--- a/modules/metarefresh/templates/fetch.tpl.php
+++ b/modules/metarefresh/templates/fetch.tpl.php
@@ -1,22 +1,17 @@
 <?php
-$this->data['header'] = $this->t('{aggregator:aggregator:aggregator_header}');
+$this->data['header'] = $this->t('{metarefresh:metarefresh:metarefresh_header}');
 $this->includeAtTemplateBase('includes/header.php');
 
-echo('<h1>Metarefresh fetch</h1>');
-
+echo '<h1>'.$this->data['header'].'</h1>';
 
 if (!empty($this->data['logentries'])) {
-	
-	echo '<pre style="border: 1px solid #aaa; padding: .5em; overflow: scroll">';
-	foreach($this->data['logentries'] AS $l) {
-		echo $l . "\n";		
-	}
-	echo '</pre>';
-	
+    echo '<pre style="border: 1px solid #aaa; padding: .5em; overflow: scroll">';
+    foreach ($this->data['logentries'] as $l) {
+        echo $l."\n";
+    }
+    echo '</pre>';
 } else {
-	echo 'No output from metarefresh.';
+    echo $this->t('{metarefresh:metarefresh:no_output}');
 }
 
-
-
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/metarefresh/templates/fetch.twig b/modules/metarefresh/templates/fetch.twig
new file mode 100644
index 0000000000000000000000000000000000000000..d8765ab3dd1e345a453196ac5d5350e870affb6c
--- /dev/null
+++ b/modules/metarefresh/templates/fetch.twig
@@ -0,0 +1,18 @@
+{% set pagetitle = "metarefresh_header" | trans %}
+
+{% extends "base.twig" %}
+
+{% block content %}
+
+{% if logentries %}
+        <h1>{{ "metarefresh_fetched" | trans }}</h1>
+        <ul>
+            {% for logentry in logentries %}
+            <li>{{ logentry }}</li>
+            {% endfor %}
+        </ul>
+{% else %}
+{{ "metarefresh_no_output" | trans }}
+{% endif %}
+
+{% endblock content %}
diff --git a/modules/metarefresh/www/fetch.php b/modules/metarefresh/www/fetch.php
index 097fb85c062ddb8aa42d6113e65b12d850bd7e9d..a715886fa035cc9d8f4103c141be87d3bb0e90d6 100644
--- a/modules/metarefresh/www/fetch.php
+++ b/modules/metarefresh/www/fetch.php
@@ -1,94 +1,86 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
-$mconfig = SimpleSAML_Configuration::getOptionalConfig('config-metarefresh.php');
-
-SimpleSAML\Utils\Auth::requireAdmin();
-
-SimpleSAML\Logger::setCaptureLog(TRUE);
-
-
-$sets = $mconfig->getConfigList('sets', array());
-
-foreach ($sets AS $setkey => $set) {
-
-	SimpleSAML\Logger::info('[metarefresh]: Executing set [' . $setkey . ']');
-
-	try {
-		
-
-		$expireAfter = $set->getInteger('expireAfter', NULL);
-		if ($expireAfter !== NULL) {
-			$expire = time() + $expireAfter;
-		} else {
-			$expire = NULL;
-		}
-
-		$metaloader = new sspmod_metarefresh_MetaLoader($expire);
-
-		# Get global black/whitelists
-		$blacklist = $mconfig->getArray('blacklist', array());
-		$whitelist = $mconfig->getArray('whitelist', array());
-
-		// get global type filters
-		$available_types = array(
-			'saml20-idp-remote',
-			'saml20-sp-remote',
-			'shib13-idp-remote',
-			'shib13-sp-remote',
-			'attributeauthority-remote'
-		);
-		$set_types = $set->getArrayize('types', $available_types);
-
-		foreach($set->getArray('sources') AS $source) {
-
-			// filter metadata by type of entity
-			if (isset($source['types'])) {
-				$metaloader->setTypes($source['types']);
-			} else {
-				$metaloader->setTypes($set_types);
-			}
-
-			# Merge global and src specific blacklists
-			if(isset($source['blacklist'])) {
-				$source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
-			} else {
-				$source['blacklist'] = $blacklist;
-			}
-
-			# Merge global and src specific whitelists
-			if(isset($source['whitelist'])) {
-				$source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
-			} else {
-				$source['whitelist'] = $whitelist;
-			}
-
-			SimpleSAML\Logger::debug('[metarefresh]: In set [' . $setkey . '] loading source ['  . $source['src'] . ']');
-			$metaloader->loadSource($source);
-		}
-
-		$outputDir = $set->getString('outputDir');
-		$outputDir = $config->resolvePath($outputDir);
-
-		$outputFormat = $set->getValueValidate('outputFormat', array('flatfile', 'serialize'), 'flatfile');
-		switch ($outputFormat) {
-			case 'flatfile':
-				$metaloader->writeMetadataFiles($outputDir);
-				break;
-			case 'serialize':
-				$metaloader->writeMetadataSerialize($outputDir);
-				break;
-		}
-	} catch (Exception $e) {
-		$e = SimpleSAML_Error_Exception::fromException($e);
-		$e->logWarning();
-	}
-	
-
+$config = \SimpleSAML\Configuration::getInstance();
+$mconfig = \SimpleSAML\Configuration::getOptionalConfig('config-metarefresh.php');
+
+\SimpleSAML\Utils\Auth::requireAdmin();
+
+\SimpleSAML\Logger::setCaptureLog(true);
+
+$sets = $mconfig->getConfigList('sets', []);
+
+foreach ($sets as $setkey => $set) {
+    \SimpleSAML\Logger::info('[metarefresh]: Executing set ['.$setkey.']');
+
+    try {
+        $expireAfter = $set->getInteger('expireAfter', null);
+        if ($expireAfter !== null) {
+            $expire = time() + $expireAfter;
+        } else {
+            $expire = null;
+        }
+        $metaloader = new \SimpleSAML\Module\metarefresh\MetaLoader($expire);
+
+        # Get global black/whitelists
+        $blacklist = $mconfig->getArray('blacklist', []);
+        $whitelist = $mconfig->getArray('whitelist', []);
+
+        // get global type filters
+        $available_types = [
+            'saml20-idp-remote',
+            'saml20-sp-remote',
+            'shib13-idp-remote',
+            'shib13-sp-remote',
+            'attributeauthority-remote'
+        ];
+        $set_types = $set->getArrayize('types', $available_types);
+
+        foreach ($set->getArray('sources') as $source) {
+            // filter metadata by type of entity
+            if (isset($source['types'])) {
+                $metaloader->setTypes($source['types']);
+            } else {
+                $metaloader->setTypes($set_types);
+            }
+
+            # Merge global and src specific blacklists
+            if (isset($source['blacklist'])) {
+                $source['blacklist'] = array_unique(array_merge($source['blacklist'], $blacklist));
+            } else {
+                $source['blacklist'] = $blacklist;
+            }
+
+            # Merge global and src specific whitelists
+            if (isset($source['whitelist'])) {
+                $source['whitelist'] = array_unique(array_merge($source['whitelist'], $whitelist));
+            } else {
+                $source['whitelist'] = $whitelist;
+            }
+
+            \SimpleSAML\Logger::debug('[metarefresh]: In set ['.$setkey.'] loading source ['.$source['src'].']');
+            $metaloader->loadSource($source);
+        }
+
+        $outputDir = $set->getString('outputDir');
+        $outputDir = $config->resolvePath($outputDir);
+
+        $outputFormat = $set->getValueValidate('outputFormat', ['flatfile', 'serialize'], 'flatfile');
+        switch ($outputFormat) {
+            case 'flatfile':
+                $metaloader->writeMetadataFiles($outputDir);
+                break;
+            case 'serialize':
+                $metaloader->writeMetadataSerialize($outputDir);
+                break;
+        }
+    } catch (\Exception $e) {
+        $e = \SimpleSAML\Error\Exception::fromException($e);
+        $e->logWarning();
+    }
 }
 
-$logentries = SimpleSAML\Logger::getCapturedLog();
+$logentries = \SimpleSAML\Logger::getCapturedLog();
 
-$t = new SimpleSAML_XHTML_Template($config, 'metarefresh:fetch.tpl.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'metarefresh:fetch.tpl.php');
 $t->data['logentries'] = $logentries;
-$t->show();
\ No newline at end of file
+$t->show();
diff --git a/modules/multiauth/lib/Auth/Source/MultiAuth.php b/modules/multiauth/lib/Auth/Source/MultiAuth.php
index f63bcce9d4c26e1d7b61548e320e777a89551a10..4fa78625242794485ee5838a07730674e3b8fd91 100644
--- a/modules/multiauth/lib/Auth/Source/MultiAuth.php
+++ b/modules/multiauth/lib/Auth/Source/MultiAuth.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\multiauth\Auth\Source;
+
 /**
  * Authentication source which let the user chooses among a list of
  * other authentication sources
@@ -8,227 +10,241 @@
  * @package SimpleSAMLphp
  */
 
-class sspmod_multiauth_Auth_Source_MultiAuth extends SimpleSAML_Auth_Source {
-
-	/**
-	 * The key of the AuthId field in the state.
-	 */
-	const AUTHID = 'sspmod_multiauth_Auth_Source_MultiAuth.AuthId';
-
-	/**
-	 * The string used to identify our states.
-	 */
-	const STAGEID = 'sspmod_multiauth_Auth_Source_MultiAuth.StageId';
-
-	/**
-	 * The key where the sources is saved in the state.
-	 */
-	const SOURCESID = 'sspmod_multiauth_Auth_Source_MultiAuth.SourceId';
-
-	/**
-	 * The key where the selected source is saved in the session.
-	 */
-	const SESSION_SOURCE = 'multiauth:selectedSource';
-
-	/**
-	 * Array of sources we let the user chooses among.
-	 */
-	private $sources;
-
-	/**
-	 * Constructor for this authentication source.
-	 *
-	 * @param array $info	 Information about this authentication source.
-	 * @param array $config	 Configuration.
-	 */
-	public function __construct($info, $config) {
-		assert(is_array($info));
-		assert(is_array($config));
-
-		// Call the parent constructor first, as required by the interface
-		parent::__construct($info, $config);
-
-		if (!array_key_exists('sources', $config)) {
-			throw new Exception('The required "sources" config option was not found');
-		}
-
-		$globalConfiguration = SimpleSAML_Configuration::getInstance();
-		$defaultLanguage = $globalConfiguration->getString('language.default', 'en');
-		$authsources = SimpleSAML_Configuration::getConfig('authsources.php');
-		$this->sources = array();
-		foreach($config['sources'] as $source => $info) {
-
-			if (is_int($source)) { // Backwards compatibility 
-				$source = $info;
-				$info = array();
-			}
-
-			if (array_key_exists('text', $info)) {
-				$text = $info['text'];
-			} else {
-				$text = array($defaultLanguage => $source);
-			}
-
-			if (array_key_exists('css-class', $info)) {
-				$css_class = $info['css-class'];
-			} else {
-				// Use the authtype as the css class
-				$authconfig = $authsources->getArray($source, NULL);
-				if (!array_key_exists(0, $authconfig) || !is_string($authconfig[0])) {
-					$css_class = "";
-				} else {
-					$css_class = str_replace(":", "-", $authconfig[0]);
-				}
-			}
-
-			$this->sources[] = array(
-				'source' => $source,
-				'text' => $text,
-				'css_class' => $css_class,
-			);
-		}
-	}
-
-	/**
-	 * Prompt the user with a list of authentication sources.
-	 *
-	 * This method saves the information about the configured sources,
-	 * and redirects to a page where the user must select one of these
-	 * authentication sources.
-	 *
-	 * This method never return. The authentication process is finished
-	 * in the delegateAuthentication method.
-	 *
-	 * @param array &$state	 Information about the current authentication.
-	 */
-	public function authenticate(&$state) {
-		assert(is_array($state));
-
-		$state[self::AUTHID] = $this->authId;
-		$state[self::SOURCESID] = $this->sources;
-
-		/* Save the $state array, so that we can restore if after a redirect */
-		$id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
-
-		/* Redirect to the select source page. We include the identifier of the
-		saved state array as a parameter to the login form */
-		$url = SimpleSAML\Module::getModuleURL('multiauth/selectsource.php');
-		$params = array('AuthState' => $id);
-
-		// Allowes the user to specify the auth souce to be used
-		if(isset($_GET['source'])) {
-			$params['source'] = $_GET['source'];
-		}
-
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
-
-		/* The previous function never returns, so this code is never
-		executed */
-		assert(false);
-	}
-
-	/**
-	 * Delegate authentication.
-	 *
-	 * This method is called once the user has choosen one authentication
-	 * source. It saves the selected authentication source in the session
-	 * to be able to logout properly. Then it calls the authenticate method
-	 * on such selected authentication source.
-	 *
-	 * @param string $authId	Selected authentication source
-	 * @param array	 $state	 Information about the current authentication.
-	 */
-	public static function delegateAuthentication($authId, $state) {
-		assert(is_string($authId));
-		assert(is_array($state));
-
-		$as = SimpleSAML_Auth_Source::getById($authId);
-		$valid_sources = array_map(
-			function($src) {
-				return $src['source'];
-			},
-			$state[self::SOURCESID]
+class MultiAuth extends \SimpleSAML\Auth\Source
+{
+    /**
+     * The key of the AuthId field in the state.
+     */
+    const AUTHID = '\SimpleSAML\Module\multiauth\Auth\Source\MultiAuth.AuthId';
+
+    /**
+     * The string used to identify our states.
+     */
+    const STAGEID = '\SimpleSAML\Module\multiauth\Auth\Source\MultiAuth.StageId';
+
+    /**
+     * The key where the sources is saved in the state.
+     */
+    const SOURCESID = '\SimpleSAML\Module\multiauth\Auth\Source\MultiAuth.SourceId';
+
+    /**
+     * The key where the selected source is saved in the session.
+     */
+    const SESSION_SOURCE = 'multiauth:selectedSource';
+
+    /**
+     * Array of sources we let the user chooses among.
+     */
+    private $sources;
+
+    /**
+     * Constructor for this authentication source.
+     *
+     * @param array $info Information about this authentication source.
+     * @param array $config Configuration.
+     */
+    public function __construct($info, $config)
+    {
+        assert(is_array($info));
+        assert(is_array($config));
+
+        // Call the parent constructor first, as required by the interface
+        parent::__construct($info, $config);
+
+        if (!array_key_exists('sources', $config)) {
+            throw new \Exception('The required "sources" config option was not found');
+        }
+
+        $globalConfiguration = \SimpleSAML\Configuration::getInstance();
+        $defaultLanguage = $globalConfiguration->getString('language.default', 'en');
+        $authsources = \SimpleSAML\Configuration::getConfig('authsources.php');
+        $this->sources = [];
+        foreach ($config['sources'] as $source => $info) {
+            if (is_int($source)) {
+                // Backwards compatibility
+                $source = $info;
+                $info = [];
+            }
+
+            if (array_key_exists('text', $info)) {
+                $text = $info['text'];
+            } else {
+                $text = [$defaultLanguage => $source];
+            }
+
+            if (array_key_exists('help', $info)) {
+                $help = $info['help'];
+            }
+            if (array_key_exists('css-class', $info)) {
+                $css_class = $info['css-class'];
+            } else {
+                // Use the authtype as the css class
+                $authconfig = $authsources->getArray($source, null);
+                if (!array_key_exists(0, $authconfig) || !is_string($authconfig[0])) {
+                    $css_class = "";
+                } else {
+                    $css_class = str_replace(":", "-", $authconfig[0]);
+                }
+            }
+
+            $this->sources[] = [
+                'source' => $source,
+                'text' => $text,
+                'help' => $help,
+                'css_class' => $css_class,
+            ];
+        }
+    }
+
+    /**
+     * Prompt the user with a list of authentication sources.
+     *
+     * This method saves the information about the configured sources,
+     * and redirects to a page where the user must select one of these
+     * authentication sources.
+     *
+     * This method never return. The authentication process is finished
+     * in the delegateAuthentication method.
+     *
+     * @param array &$state Information about the current authentication.
+     */
+    public function authenticate(&$state)
+    {
+        assert(is_array($state));
+
+        $state[self::AUTHID] = $this->authId;
+        $state[self::SOURCESID] = $this->sources;
+
+        // Save the $state array, so that we can restore if after a redirect
+        $id = \SimpleSAML\Auth\State::saveState($state, self::STAGEID);
+
+        /* Redirect to the select source page. We include the identifier of the
+         * saved state array as a parameter to the login form
+         */
+        $url = \SimpleSAML\Module::getModuleURL('multiauth/selectsource.php');
+        $params = ['AuthState' => $id];
+
+        // Allowes the user to specify the auth souce to be used
+        if (isset($_GET['source'])) {
+            $params['source'] = $_GET['source'];
+        }
+
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, $params);
+
+        // The previous function never returns, so this code is never executed
+        assert(false);
+    }
+
+    /**
+     * Delegate authentication.
+     *
+     * This method is called once the user has choosen one authentication
+     * source. It saves the selected authentication source in the session
+     * to be able to logout properly. Then it calls the authenticate method
+     * on such selected authentication source.
+     *
+     * @param string $authId Selected authentication source
+     * @param array $state Information about the current authentication.
+     */
+    public static function delegateAuthentication($authId, $state)
+    {
+        assert(is_string($authId));
+        assert(is_array($state));
+
+        $as = \SimpleSAML\Auth\Source::getById($authId);
+        $valid_sources = array_map(
+            function ($src) {
+                return $src['source'];
+            },
+            $state[self::SOURCESID]
+        );
+        if ($as === null || !in_array($authId, $valid_sources, true)) {
+            throw new \Exception('Invalid authentication source: '.$authId);
+        }
+
+        // Save the selected authentication source for the logout process.
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $session->setData(
+            self::SESSION_SOURCE,
+            $state[self::AUTHID],
+            $authId,
+            \SimpleSAML\Session::DATA_TIMEOUT_SESSION_END
         );
-		if ($as === NULL || !in_array($authId, $valid_sources, true)) {
-			throw new Exception('Invalid authentication source: ' . $authId);
-		}
-
-		/* Save the selected authentication source for the logout process. */
-		$session = SimpleSAML_Session::getSessionFromRequest();
-		$session->setData(self::SESSION_SOURCE, $state[self::AUTHID], $authId, SimpleSAML_Session::DATA_TIMEOUT_SESSION_END);
-
-		try {
-			$as->authenticate($state);
-		} catch (SimpleSAML_Error_Exception $e) {
-			SimpleSAML_Auth_State::throwException($state, $e);
-		} catch (Exception $e) {
-			$e = new SimpleSAML_Error_UnserializableException($e);
-			SimpleSAML_Auth_State::throwException($state, $e);
-		}
-		SimpleSAML_Auth_Source::completeAuth($state);
-	}
-
-	/**
-	 * Log out from this authentication source.
-	 *
-	 * This method retrieves the authentication source used for this
-	 * session and then call the logout method on it.
-	 *
-	 * @param array &$state	 Information about the current logout operation.
-	 */
-	public function logout(&$state) {
-		assert(is_array($state));
-
-		/* Get the source that was used to authenticate */
-		$session = SimpleSAML_Session::getSessionFromRequest();
-		$authId = $session->getData(self::SESSION_SOURCE, $this->authId);
-
-		$source = SimpleSAML_Auth_Source::getById($authId);
-		if ($source === NULL) {
-			throw new Exception('Invalid authentication source during logout: ' . $source);
-		}
-		/* Then, do the logout on it */
-		$source->logout($state);
-	}
-
-	/**
-	* Set the previous authentication source.
-	*
-	* This method remembers the authentication source that the user selected
-	* by storing its name in a cookie.
-	*
-	* @param string $source Name of the authentication source the user selected.
-	*/
-	public function setPreviousSource($source) {
-		assert(is_string($source));
-
-		$cookieName = 'multiauth_source_' . $this->authId;
-
-		$config = SimpleSAML_Configuration::getInstance();
-		$params = array(
-			/* We save the cookies for 90 days. */
-			'lifetime' => (60*60*24*90),
-			/* The base path for cookies.
-			This should be the installation directory for SimpleSAMLphp. */
-			'path' => $config->getBasePath(),
-			'httponly' => FALSE,
-		);
-
-        \SimpleSAML\Utils\HTTP::setCookie($cookieName, $source, $params, FALSE);
-	}
-
-	/**
-	* Get the previous authentication source.
-	*
-	* This method retrieves the authentication source that the user selected
-	* last time or NULL if this is the first time or remembering is disabled.
-	*/
-	public function getPreviousSource() {
-		$cookieName = 'multiauth_source_' . $this->authId;
-		if(array_key_exists($cookieName, $_COOKIE)) {
-			return $_COOKIE[$cookieName];
-		} else {
-			return NULL;
-		}
-	}
+
+        try {
+            $as->authenticate($state);
+        } catch (\SimpleSAML\Error\Exception $e) {
+            \SimpleSAML\Auth\State::throwException($state, $e);
+        } catch (\Exception $e) {
+            $e = new \SimpleSAML\Error\UnserializableException($e);
+            \SimpleSAML\Auth\State::throwException($state, $e);
+        }
+        \SimpleSAML\Auth\Source::completeAuth($state);
+    }
+
+    /**
+     * Log out from this authentication source.
+     *
+     * This method retrieves the authentication source used for this
+     * session and then call the logout method on it.
+     *
+     * @param array &$state Information about the current logout operation.
+     */
+    public function logout(&$state)
+    {
+        assert(is_array($state));
+
+        // Get the source that was used to authenticate
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $authId = $session->getData(self::SESSION_SOURCE, $this->authId);
+
+        $source = \SimpleSAML\Auth\Source::getById($authId);
+        if ($source === null) {
+            throw new \Exception('Invalid authentication source during logout: '.$source);
+        }
+        // Then, do the logout on it
+        $source->logout($state);
+    }
+
+    /**
+     * Set the previous authentication source.
+     *
+     * This method remembers the authentication source that the user selected
+     * by storing its name in a cookie.
+     *
+     * @param string $source Name of the authentication source the user selected.
+     */
+    public function setPreviousSource($source)
+    {
+        assert(is_string($source));
+
+        $cookieName = 'multiauth_source_'.$this->authId;
+
+        $config = \SimpleSAML\Configuration::getInstance();
+        $params = [
+            // We save the cookies for 90 days
+            'lifetime' => 7776000, //60*60*24*90
+            // The base path for cookies. This should be the installation directory for SimpleSAMLphp.
+            'path' => $config->getBasePath(),
+            'httponly' => false,
+        ];
+
+        \SimpleSAML\Utils\HTTP::setCookie($cookieName, $source, $params, false);
+    }
+
+    /**
+     * Get the previous authentication source.
+     *
+     * This method retrieves the authentication source that the user selected
+     * last time or NULL if this is the first time or remembering is disabled.
+     */
+    public function getPreviousSource()
+    {
+        $cookieName = 'multiauth_source_'.$this->authId;
+        if (array_key_exists($cookieName, $_COOKIE)) {
+            return $_COOKIE[$cookieName];
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/modules/multiauth/templates/selectsource.php b/modules/multiauth/templates/selectsource.php
index f5eaba07e742a959fa8ddcba53196eb45185a7cf..294fcbc0c53c703862a870624327a82bba812f3d 100644
--- a/modules/multiauth/templates/selectsource.php
+++ b/modules/multiauth/templates/selectsource.php
@@ -1,6 +1,5 @@
 <?php
 $this->data['header'] = $this->t('{multiauth:multiauth:select_source_header}');
-
 $this->includeAtTemplateBase('includes/header.php');
 ?>
 
@@ -9,23 +8,23 @@ $this->includeAtTemplateBase('includes/header.php');
 <p><?php echo $this->t('{multiauth:multiauth:select_source_text}'); ?></p>
 
 <form action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" method="get">
-<input type="hidden" name="AuthState" value="<?php echo htmlspecialchars($this->data['authstate']); ?>" />
-<ul>
+    <input type="hidden" name="AuthState" value="<?php echo htmlspecialchars($this->data['authstate']); ?>" />
+    <ul>
 <?php
-foreach($this->data['sources'] as $source) {
-	echo '<li class="' . htmlspecialchars($source['css_class']) . ' authsource">';
-	if ($source['source'] === $this->data['preferred']) {
-		$autofocus = ' autofocus="autofocus"';
-	} else {
-		$autofocus = '';
-	}
-	$name = 'src-' . base64_encode($source['source']);
-	echo '<input type="submit" name="' . htmlspecialchars($name) . '"' . $autofocus . ' ' .
-		'id="button-' . htmlspecialchars($source['source']) . '" ' .
-		'value="' . htmlspecialchars($this->t($source['text'])) . '" />';
-	echo '</li>';
+foreach ($this->data['sources'] as $source) {
+    echo '<li class="'.htmlspecialchars($source['css_class']).' authsource">';
+    if ($source['source'] === $this->data['preferred']) {
+        $autofocus = ' autofocus="autofocus"';
+    } else {
+        $autofocus = '';
+    }
+    $name = 'src-'.base64_encode($source['source']);
+    echo '<input type="submit" name="'.htmlspecialchars($name).'"'.$autofocus.' '.
+        'id="button-'.htmlspecialchars($source['source']).'" '.
+        'value="'.htmlspecialchars($this->t($source['text'])).'" />';
+    echo '</li>';
 }
 ?>
-</ul>
+    </ul>
 </form>
 <?php $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/multiauth/templates/selectsource.twig b/modules/multiauth/templates/selectsource.twig
new file mode 100644
index 0000000000000000000000000000000000000000..5d1e3793e93dc82d3752390d1ab24013aa6d560b
--- /dev/null
+++ b/modules/multiauth/templates/selectsource.twig
@@ -0,0 +1,23 @@
+{% set pagetitle = '{multiauth:multiauth:select_source_header}'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ '{multiauth:multiauth:select_source_header}'| trans }}</h2>
+    <p>{{ '{multiauth:multiauth:select_source_text}'| trans }}</p>
+
+    <form action="{{ selfUrl|escape('html') }}" method="get">
+        <input type="hidden" name="AuthState" value="{{ authstate|escape('html') }} ">
+        <ul>
+        {% for key, source in sources %}
+            {% set name = ('src-' ~ source.source64) %}
+            {% set button = ('button-' ~ source.source) %}
+	    <li class="{{ source.css_class|escape('html') }} authsource">
+            <input type="submit" name="{{ name|escape('html') }}" id="{{ button|escape('html') }}" value="{{ source.text|escape('html') }}"{%- if source.source == preferred %} autofocus{% endif -%}>
+            {% if source.help %}
+              <p>{{ source.help|escape('html') }}</p>
+            {% endif %}
+            </li>
+        {% endfor %}
+        </ul>
+    </form>
+{% endblock %}
diff --git a/modules/multiauth/www/selectsource.php b/modules/multiauth/www/selectsource.php
index db09029f89a18ecc50d38de81213afac86a67a0d..287f7808eab880abd9749df3e665f90f4b836fac 100644
--- a/modules/multiauth/www/selectsource.php
+++ b/modules/multiauth/www/selectsource.php
@@ -3,7 +3,7 @@
 /**
  * This page shows a list of authentication sources. When the user selects
  * one of them if pass this information to the
- * sspmod_multiauth_Auth_Source_MultiAuth class and call the
+ * \SimpleSAML\Module\multiauth\Auth\Source\MultiAuth class and call the
  * delegateAuthentication method on it.
  *
  * @author Lorenzo Gil, Yaco Sistemas S.L.
@@ -12,49 +12,71 @@
 
 // Retrieve the authentication state
 if (!array_key_exists('AuthState', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthState parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthState parameter.');
 }
 $authStateId = $_REQUEST['AuthState'];
-$state = SimpleSAML_Auth_State::loadState($authStateId, sspmod_multiauth_Auth_Source_MultiAuth::STAGEID);
+$state = \SimpleSAML\Auth\State::loadState($authStateId, \SimpleSAML\Module\multiauth\Auth\Source\MultiAuth::STAGEID);
 
-if (array_key_exists("SimpleSAML_Auth_Source.id", $state)) {
-	$authId = $state["SimpleSAML_Auth_Source.id"];
-	$as = SimpleSAML_Auth_Source::getById($authId);
+if (array_key_exists("\SimpleSAML\Auth\Source.id", $state)) {
+    $authId = $state["\SimpleSAML\Auth\Source.id"];
+    $as = \SimpleSAML\Auth\Source::getById($authId);
 } else {
-	$as = NULL;
+    $as = null;
 }
 
-$source = NULL;
+$source = null;
 if (array_key_exists('source', $_REQUEST)) {
-	$source = $_REQUEST['source'];
+    $source = $_REQUEST['source'];
 } else {
-	foreach ($_REQUEST as $k => $v) {
-		$k = explode('-', $k, 2);
-		if (count($k) === 2 && $k[0] === 'src') {
-			$source = base64_decode($k[1]);
-		}
-	}
+    foreach ($_REQUEST as $k => $v) {
+        $k = explode('-', $k, 2);
+        if (count($k) === 2 && $k[0] === 'src') {
+            $source = base64_decode($k[1]);
+        }
+    }
 }
-if ($source !== NULL) {
-	if ($as !== NULL) {
-		$as->setPreviousSource($source);
-	}
-	sspmod_multiauth_Auth_Source_MultiAuth::delegateAuthentication($source, $state);
+if ($source !== null) {
+    if ($as !== null) {
+        $as->setPreviousSource($source);
+    }
+    \SimpleSAML\Module\multiauth\Auth\Source\MultiAuth::delegateAuthentication($source, $state);
 }
 
 if (array_key_exists('multiauth:preselect', $state)) {
-	$source = $state['multiauth:preselect'];
-	sspmod_multiauth_Auth_Source_MultiAuth::delegateAuthentication($source, $state);
+    $source = $state['multiauth:preselect'];
+    \SimpleSAML\Module\multiauth\Auth\Source\MultiAuth::delegateAuthentication($source, $state);
+}
+
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'multiauth:selectsource.php');
+
+$defaultLanguage = $globalConfig->getString('language.default', 'en');
+$language = $t->getTranslator()->getLanguage()->getLanguage();
+
+$sources = $state[\SimpleSAML\Module\multiauth\Auth\Source\MultiAuth::SOURCESID];
+foreach ($sources as $key => $source) {
+    $sources[$key]['source64'] = base64_encode($sources[$key]['source']);
+    if (isset($sources[$key]['text'][$language])) {
+        $sources[$key]['text'] = $sources[$key]['text'][$language];
+    } else {
+        $sources[$key]['text'] = $sources[$key]['text'][$defaultLanguage];
+    }
+
+    if (isset($sources[$key]['help'][$language])) {
+        $sources[$key]['help'] = $sources[$key]['help'][$language];
+    } else {
+        $sources[$key]['help'] = $sources[$key]['help'][$defaultLanguage];
+    }
 }
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'multiauth:selectsource.php');
 $t->data['authstate'] = $authStateId;
-$t->data['sources'] = $state[sspmod_multiauth_Auth_Source_MultiAuth::SOURCESID];
-if ($as !== NULL) {
-	$t->data['preferred'] = $as->getPreviousSource();
+$t->data['sources'] = $sources;
+$t->data['selfUrl'] = $_SERVER['PHP_SELF'];
+
+if ($as !== null) {
+    $t->data['preferred'] = $as->getPreviousSource();
 } else {
-	$t->data['preferred'] = NULL;
+    $t->data['preferred'] = null;
 }
 $t->show();
 exit();
diff --git a/modules/negotiate/docs/negotiate.md b/modules/negotiate/docs/negotiate.md
index a57044de9bb5f059a1c0767b5751c5c29f95c7b4..8563b338d38f1df29c83e7df33cbcf9013f89e2e 100644
--- a/modules/negotiate/docs/negotiate.md
+++ b/modules/negotiate/docs/negotiate.md
@@ -51,7 +51,7 @@ client.
 
 All configuration is handled in authsources.php:
 
-     'weblogin' => array(
+     'weblogin' => [
              'negotiate:Negotiate',
              'keytab' => '/path/to/keytab-file',
              'fallback' => 'ldap',
@@ -59,19 +59,18 @@ All configuration is handled in authsources.php:
              'base' => 'cn=people,dc=example,dc=com',
              'adminUser' => 'cn=idp-fallback,cn=services,dc=example,dc=com',
              'adminPassword' => 'VerySecretPassphraseHush'
-     ),
-     'ldap' => array(
+     ],
+     'ldap' => [
              'ldap:LDAP',
              'hostname' => 'ldap.example.com',
              'enable_tls' => TRUE,
              'dnpattern' => 'uid=%username%,cn=people,dc=example,dc=com',
              'search.enable' => FALSE
-     ),
+     ],
 
 
 
-`php_krb5`
-++++++++++
+### `php_krb5`
 
 The processing involving the actual Kerberos ticket handling is done
 by php_krb5. The package is not yet labeled stable but has worked well
@@ -80,7 +79,7 @@ during testing.
 NOTE! php_krb5 hardcodes the service name in the keytab file to 'HTTP'
 as of php_krb5-1.0rc2. To change this you need to edit the module code.
 Be wary of how much space is allocated to the string in
-negotiate_auth.c:101.
+`negotiate_auth.c:101`.
 
 Depending on you apache config you may need a rewrite rule to allow
 php_krb5 to read the HTTP_AUTHORIZATION header:
@@ -94,40 +93,38 @@ Test the Kerberos setup with the following script:
 
      <?php
      if(!extension_loaded('krb5')) {
-             die('KRB5 Extension not installed');
+         die('KRB5 Extension not installed');
      }
 
      if(!empty($_SERVER['HTTP_AUTHORIZATION'])) {
-            list($mech, $data) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
-             if(strtolower($mech) == 'basic') {
-                     echo "Client sent basic";
-                     die('Unsupported request');
-             } else if(strtolower($mech) != 'negotiate') {
-                     echo "Couldn't find negotiate";
-                     die('Unsupported request');
-             }
-             $auth = new KRB5NegotiateAuth('/path/to/keytab');
-             $reply = '';
-             if($reply = $auth->doAuthentication()) {
-                     header('HTTP/1.1 200 Success');
-                     echo 'Success - authenticated as ' . $auth->getAuthenticatedUser() . '<br>';
-             } else {
-                     echo 'Failed to authN.';
-                     die();
-             }
+         list($mech, $data) = explode(' ', $_SERVER['HTTP_AUTHORIZATION']);
+         if(strtolower($mech) == 'basic') {
+             echo "Client sent basic";
+             die('Unsupported request');
+         } else if(strtolower($mech) != 'negotiate') {
+             echo "Couldn't find negotiate";
+             die('Unsupported request');
+         }
+         $auth = new KRB5NegotiateAuth('/path/to/keytab');
+         $reply = '';
+         if($reply = $auth->doAuthentication()) {
+             header('HTTP/1.1 200 Success');
+             echo 'Success - authenticated as ' . $auth->getAuthenticatedUser() . '<br>';
+         } else {
+             echo 'Failed to authN.';
+             die();
+         }
      } else {
-             header('HTTP/1.1 401 Unauthorized');
-             header('WWW-Authenticate: Negotiate',false);
-             echo 'Not authenticated. No HTTP_AUTHORIZATION available.';
-             echo 'Check headers sent by the browser and verify that ';
-             echo 'apache passes them to PHP';
+         header('HTTP/1.1 401 Unauthorized');
+         header('WWW-Authenticate: Negotiate',false);
+         echo 'Not authenticated. No HTTP_AUTHORIZATION available.';
+         echo 'Check headers sent by the browser and verify that ';
+         echo 'apache passes them to PHP';
      }
-     ?>
 
 
 
-`LDAP`
-++++++
+### LDAP
 
 LDAP is used to verify the user due to the lack of metadata in
 Kerberos. A domain can contain lots of kiosk users, non-personal
@@ -146,15 +143,14 @@ be a DN to an object with access to search for all relevant user
 objects and to look up attributes needed by the SP.
 
 
-`Subnet filtering`
-++++++++++++++++++
+### Subnet filtering
 
 Subnet is meant to filter which clients you subject to the
 WWW-Authenticate request.
 
 Syntax is:
 
-     'subnet' => array('127.0.0.0/16','192.168.0.0/16'),
+     'subnet' => [ '127.0.0.0/16','192.168.0.0/16' ],
 
 Browsers, especially IE, behave erratically when they encounter a
 WWW-Authenticate from the webserver. Included in RFC4559 Negotiate is
@@ -167,18 +163,16 @@ currently in the domain should be the only ones that are promted with
 WWW-Authenticate: Negotiate.
 
 
-`Enabling/disabling Negotiate from a web browser`
-+++++++++++++++++++++++++++++++++++++++++++++++++
+### Enabling/disabling Negotiate from a web browser
 
 Included in Negotiate are semi-static web pages for enabling and
-disabling Negotiate for any given client. The pages simple set/deletes
+disabling Negotiate for any given client. The pages simplly set/delete
 a cookie that Negotiate will look for when a client attempts AuthN.
 The help text in the JSON files should be locally overwritten to fully
 explain which clients are accepted by Negotiate.
 
 
-`Logout/Login loop and reauthenticating`
-++++++++++++++++++++++++++++++++++++++++
+### Logout/Login loop and reauthenticating
 
 Due to the automatic AuthN of certain clients and how SPs will
 automatically redirect clients to the IdP when clients try to access
@@ -188,50 +182,51 @@ out user. The consequence of this is that the user will be presented
 with the login mechanism of the fallback module specified in Negotiate
 config.
 
-SimpleSamlPhp offers no decent way of adding hooks or piggyback this
+SimpleSamlPHP offers no decent way of adding hooks or piggyback this
 information to the fallback module. In future releases one might add a
 box of information to the user explaining what's happening.
 
 One can add this bit of code to the template in the fallback AuthN
 module:
 
-// This should be placed in your www script
-$nego_session = FALSE;
-$nego_perm = FALSE;
-$nego_retry = NULL;
-if (array_key_exists('negotiate:authId', $state)) {
-    $nego = SimpleSAML_Auth_Source::getById($state['negotiate:authId']);
-    $mask = $nego->checkMask();
-    $disabled = $nego->spDisabledInMetadata($spMetadata);
-    $session_disabled = $session->getData('negotiate:disable', 'session');
-    if ($mask and !$disabled) {
-        if(array_key_exists('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', $_COOKIE) &&
-           $_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT'] == 'True') {
-            $nego_perm = TRUE;
-        } elseif ($session_disabled) {
-            $retryState = SimpleSAML_Auth_State::cloneState($state);
-            unset($retryState[SimpleSAML_Auth_State::ID]);
-            $nego_retry = SimpleSAML_Auth_State::saveState($retryState, 'sspmod_negotiate_Auth_Source_Negotiate.StageId');
-            $nego_session = TRUE;
+    // This should be placed in your www script
+    $nego_session = false;
+    $nego_perm = false;
+    $nego_retry = null;
+    if (array_key_exists('negotiate:authId', $state)) {
+        $nego = \SimpleSAML\Auth\Source::getById($state['negotiate:authId']);
+        $mask = $nego->checkMask();
+        $disabled = $nego->spDisabledInMetadata($spMetadata);
+        $session_disabled = $session->getData('negotiate:disable', 'session');
+        if ($mask and !$disabled) {
+            if(array_key_exists('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', $_COOKIE) &&
+               $_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT'] == 'True') {
+                $nego_perm = true;
+            } elseif ($session_disabled) {
+                $retryState = \SimpleSAML\Auth\State::cloneState($state);
+                unset($retryState[\SimpleSAML\Auth\State::ID]);
+                $nego_retry = \SimpleSAML\Auth\State::saveState($retryState, '\SimpleSAML\Module\negotiate\Auth\Source\Negotiate.StageId');
+                $nego_session = true;
+            }
         }
     }
-}
-
-// This should reside in your template
-if($this->data['nego']['disable_perm']) {
-    echo '<span id="login-extra-info-uio.no" class="login-extra-info">'
-          . '<span class="login-extra-info-divider"></span>'
-          . $this->t('{feide:login:login_uio_negotiate_disabled_permanent_info}')
-          . '</span>';
-} elseif($this->data['nego']['disable_session']) {
-     echo '<span id="login-extra-info-uio.no" class="login-extra-info">'
-          . '<span class="login-extra-info-divider"></span>'
-          . $this->t('{feide:login:login_uio_negotiate_disabled_session_info}')
-          . '<br><a href="'.SimpleSAML\Module::getModuleURL('negotiate/retry.php', array('AuthState' => $this->data['nego']['retry_id'])).'">'
-          . $this->t('{feide:login:login_uio_negotiate_disabled_session_info_link}')
-          . '</a>'
-          . '</span>';
-}
+    
+    // This should reside in your template
+    if($this->data['nego']['disable_perm']) {
+        echo '<span id="login-extra-info-uio.no" class="login-extra-info">'
+              . '<span class="login-extra-info-divider"></span>'
+              . $this->t('{feide:login:login_uio_negotiate_disabled_permanent_info}')
+              . '</span>';
+    } elseif($this->data['nego']['disable_session']) {
+         echo '<span id="login-extra-info-uio.no" class="login-extra-info">'
+              . '<span class="login-extra-info-divider"></span>'
+              . $this->t('{feide:login:login_uio_negotiate_disabled_session_info}')
+              . '<br><a href="'.SimpleSAML\Module::getModuleURL('negotiate/retry.php', [ 'AuthState' => $this->data['nego']['retry_id'] ]).'">'
+              . $this->t('{feide:login:login_uio_negotiate_disabled_session_info_link}')
+              . '</a>'
+              . '</span>';
+    }
+
 
 The above may or may not work right out of the box for you but it is
 the gist of it. By looking at the state variable, cookie and checking
@@ -247,33 +242,35 @@ security check in SSP's state handling library. If you omit this and
 pass on the original state you will see a warning in the log like
 this:
 
-    Sep 27 13:47:36 simplesamlphp WARNING [b99e6131ee] Wrong stage in state. Was 'foo', should be 'sspmod_negotiate_Auth_Source_Negotiate.StageId'.
+    Sep 27 13:47:36 simplesamlphp WARNING [b99e6131ee] Wrong stage in state. Was 'foo', should be '\SimpleSAML\Module\negotiate\Auth\Source\Negotiate.StageId'.
 
 It will work as loadState will take controll and call
 Negotiate->authenticate() but remaining code in retry.php will be
 discarded. Other side-effects may occur.
 
 
-`Clients`
-+++++++++
+### Clients
 
-* Internet Explorer
+#### Internet Explorer
 
 YMMV but generally you need to have your IdP defined in "Internet
 Options" -> "Security" -> "Local intranet" -> "Sites" -> "Advanced".
 You also need "Internet Options" -> "Advanced" -> "Security" -> Enable
 Integrated Windows Authentication" enabled.
 
-* Firefox
+#### Firefox
 
 Open "about:config". Locate "network.auth.use-sspi" and verify that
 this is true (on a Windows machine). Next locate
 "network.negotiate-auth.trusted-uris" and insert your IdP.
 
-* Safari
+#### Safari
 
 TODO
 
-* Chrome
+#### Chromium
+
+To allow Kerberos SPN generation on Linux-based platforms, add the
+following line to /etc/chromium.d/default-flags:
+    export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --auth-server-whitelist=.example.com"
 
-TODO
diff --git a/modules/negotiate/lib/Auth/Source/Negotiate.php b/modules/negotiate/lib/Auth/Source/Negotiate.php
index c1d56500d63e94d16a741d793fbb059a3c64be1e..21601452f408a68ff26b1f973dda20cbbf3141e6 100644
--- a/modules/negotiate/lib/Auth/Source/Negotiate.php
+++ b/modules/negotiate/lib/Auth/Source/Negotiate.php
@@ -1,5 +1,8 @@
 <?php
 
+namespace SimpleSAML\Module\negotiate\Auth\Source;
+
+use \SimpleSAML\Logger;
 
 /**
  * The Negotiate module. Allows for password-less, secure login by Kerberos and Negotiate.
@@ -7,11 +10,11 @@
  * @author Mathias Meisfjordskar, University of Oslo <mathias.meisfjordskar@usit.uio.no>
  * @package SimpleSAMLphp
  */
-class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
-{
 
+class Negotiate extends \SimpleSAML\Auth\Source
+{
     // Constants used in the module
-    const STAGEID = 'sspmod_negotiate_Auth_Source_Negotiate.StageId';
+    const STAGEID = '\SimpleSAML\Module\negotiate\Auth\Source\Negotiate.StageId';
 
     protected $ldap = null;
     protected $backend = '';
@@ -22,8 +25,8 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
     protected $debugLDAP = false;
     protected $timeout = 30;
     protected $keytab = '';
-    protected $base = array();
-    protected $attr = 'uid';
+    protected $base = [];
+    protected $attr = ['uid'];
     protected $subnet = null;
     protected $admin_user = null;
     protected $admin_pw = null;
@@ -44,13 +47,13 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
         assert(is_array($config));
 
         if (!extension_loaded('krb5')) {
-            throw new Exception('KRB5 Extension not installed');
+            throw new \Exception('KRB5 Extension not installed');
         }
 
         // call the parent constructor first, as required by the interface
         parent::__construct($info, $config);
 
-        $config = SimpleSAML_Configuration::loadFromArray($config);
+        $config = \SimpleSAML\Configuration::loadFromArray($config);
 
         $this->backend = $config->getString('fallback');
         $this->hostname = $config->getString('hostname');
@@ -59,9 +62,9 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
         $this->enableTLS = $config->getBoolean('enable_tls', false);
         $this->debugLDAP = $config->getBoolean('debugLDAP', false);
         $this->timeout = $config->getInteger('timeout', 30);
-        $this->keytab = $config->getString('keytab');
+        $this->keytab = \SimpleSAML\Utils\Config::getCertPath($config->getString('keytab'));
         $this->base = $config->getArrayizeString('base');
-        $this->attr = $config->getString('attr', 'uid');
+        $this->attr = $config->getArrayizeString('attr', 'uid');
         $this->subnet = $config->getArray('subnet', null);
         $this->admin_user = $config->getString('adminUser', null);
         $this->admin_pw = $config->getString('adminPassword', null);
@@ -85,9 +88,9 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
         assert(is_array($state));
 
         // set the default backend to config
-        $state['LogoutState'] = array(
+        $state['LogoutState'] = [
             'negotiate:backend' => $this->backend,
-        );
+        ];
         $state['negotiate:authId'] = $this->authId;
 
 
@@ -97,14 +100,14 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
         }
         /* Go straight to fallback if Negotiate is disabled or if you are sent back to the IdP directly from the SP
         after having logged out. */
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $disabled = $session->getData('negotiate:disable', 'session');
 
         if ($disabled ||
             (!empty($_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT']) &&
                 $_COOKIE['NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT'] == 'True')
         ) {
-            SimpleSAML\Logger::debug('Negotiate - session disabled. falling back');
+            Logger::debug('Negotiate - session disabled. falling back');
             $this->fallBack($state);
             // never executed
             assert(false);
@@ -116,10 +119,10 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
             assert(false);
         }
 
-        SimpleSAML\Logger::debug('Negotiate - authenticate(): looking for Negotiate');
+        Logger::debug('Negotiate - authenticate(): looking for Negotiate');
         if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
-            SimpleSAML\Logger::debug('Negotiate - authenticate(): Negotiate found');
-            $this->ldap = new SimpleSAML_Auth_LDAP(
+            Logger::debug('Negotiate - authenticate(): Negotiate found');
+            $this->ldap = new \SimpleSAML\Auth\LDAP(
                 $this->hostname,
                 $this->enableTLS,
                 $this->debugLDAP,
@@ -130,58 +133,57 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
 
             list($mech,) = explode(' ', $_SERVER['HTTP_AUTHORIZATION'], 2);
             if (strtolower($mech) == 'basic') {
-                SimpleSAML\Logger::debug('Negotiate - authenticate(): Basic found. Skipping.');
+                Logger::debug('Negotiate - authenticate(): Basic found. Skipping.');
             } else {
                 if (strtolower($mech) != 'negotiate') {
-                    SimpleSAML\Logger::debug('Negotiate - authenticate(): No "Negotiate" found. Skipping.');
+                    Logger::debug('Negotiate - authenticate(): No "Negotiate" found. Skipping.');
                 }
             }
 
-            $auth = new KRB5NegotiateAuth($this->keytab);
+            $auth = new \KRB5NegotiateAuth($this->keytab);
             // attempt Kerberos authentication
             try {
                 $reply = $auth->doAuthentication();
-            } catch (Exception $e) {
-                SimpleSAML\Logger::error('Negotiate - authenticate(): doAuthentication() exception: '.$e->getMessage());
+            } catch (\Exception $e) {
+                Logger::error('Negotiate - authenticate(): doAuthentication() exception: '.$e->getMessage());
                 $reply = null;
             }
 
             if ($reply) {
                 // success! krb TGS received
                 $user = $auth->getAuthenticatedUser();
-                SimpleSAML\Logger::info('Negotiate - authenticate(): '.$user.' authenticated.');
+                Logger::info('Negotiate - authenticate(): '.$user.' authenticated.');
                 $lookup = $this->lookupUserData($user);
                 if ($lookup !== null) {
                     $state['Attributes'] = $lookup;
                     // Override the backend so logout will know what to look for
-                    $state['LogoutState'] = array(
+                    $state['LogoutState'] = [
                         'negotiate:backend' => null,
-                    );
-                    SimpleSAML\Logger::info('Negotiate - authenticate(): '.$user.' authorized.');
-                    SimpleSAML_Auth_Source::completeAuth($state);
+                    ];
+                    Logger::info('Negotiate - authenticate(): '.$user.' authorized.');
+                    \SimpleSAML\Auth\Source::completeAuth($state);
                     // Never reached.
                     assert(false);
                 }
             } else {
                 // Some error in the received ticket. Expired?
-                SimpleSAML\Logger::info('Negotiate - authenticate(): Kerberos authN failed. Skipping.');
+                Logger::info('Negotiate - authenticate(): Kerberos authN failed. Skipping.');
             }
         } else {
             // No auth token. Send it.
-            SimpleSAML\Logger::debug('Negotiate - authenticate(): Sending Negotiate.');
+            Logger::debug('Negotiate - authenticate(): Sending Negotiate.');
             // Save the $state array, so that we can restore if after a redirect
-            SimpleSAML\Logger::debug('Negotiate - fallback: '.$state['LogoutState']['negotiate:backend']);
-            $id = SimpleSAML_Auth_State::saveState($state, self::STAGEID);
-            $params = array('AuthState' => $id);
+            Logger::debug('Negotiate - fallback: '.$state['LogoutState']['negotiate:backend']);
+            $id = \SimpleSAML\Auth\State::saveState($state, self::STAGEID);
+            $params = ['AuthState' => $id];
 
             $this->sendNegotiate($params);
             exit;
         }
 
-        SimpleSAML\Logger::info('Negotiate - authenticate(): Client failed Negotiate. Falling back');
+        Logger::info('Negotiate - authenticate(): Client failed Negotiate. Falling back');
         $this->fallBack($state);
-        /* The previous function never returns, so this code is never
-           executed */
+        // The previous function never returns, so this code is never executed
         assert(false);
     }
 
@@ -190,13 +192,13 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
     {
         if (array_key_exists('negotiate:disable', $spMetadata)) {
             if ($spMetadata['negotiate:disable'] == true) {
-                SimpleSAML\Logger::debug('Negotiate - SP disabled. falling back');
+                Logger::debug('Negotiate - SP disabled. falling back');
                 return true;
             } else {
-                SimpleSAML\Logger::debug('Negotiate - SP disable flag found but set to FALSE');
+                Logger::debug('Negotiate - SP disable flag found but set to FALSE');
             }
         } else {
-            SimpleSAML\Logger::debug('Negotiate - SP disable flag not found');
+            Logger::debug('Negotiate - SP disable flag not found');
         }
         return false;
     }
@@ -218,13 +220,13 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
         }
         $ip = $_SERVER['REMOTE_ADDR'];
         foreach ($this->subnet as $cidr) {
-            $ret = SimpleSAML\Utils\Net::ipCIDRcheck($cidr);
+            $ret = \SimpleSAML\Utils\Net::ipCIDRcheck($cidr);
             if ($ret) {
-                SimpleSAML\Logger::debug('Negotiate: Client "'.$ip.'" matched subnet.');
+                Logger::debug('Negotiate: Client "'.$ip.'" matched subnet.');
                 return true;
             }
         }
-        SimpleSAML\Logger::debug('Negotiate: Client "'.$ip.'" did not match subnet.');
+        Logger::debug('Negotiate: Client "'.$ip.'" did not match subnet.');
         return false;
     }
 
@@ -237,22 +239,19 @@ class sspmod_negotiate_Auth_Source_Negotiate extends SimpleSAML_Auth_Source
      */
     protected function sendNegotiate($params)
     {
-        $url = htmlspecialchars(SimpleSAML\Module::getModuleURL('negotiate/backend.php', $params));
+        $config = \SimpleSAML\Configuration::getInstance();
+
+        $url = htmlspecialchars(\SimpleSAML\Module::getModuleURL('negotiate/backend.php', $params));
         $json_url = json_encode($url);
 
         header('HTTP/1.1 401 Unauthorized');
         header('WWW-Authenticate: Negotiate', false);
-        echo <<<EOF
-<html>
- <head>
-  <script type="text/javascript">window.location = $json_url</script>
-  <title>Redirect to login</title>
- </head>
-<body>
- <p>Your browser seems to have Javascript disabled. Please click <a href="$url">here</a>.</p>
-</body>
-</html>
-EOF;
+
+        $t = new \SimpleSAML\XHTML\Template($config, 'negotiate:redirect.twig');
+        $t->data['baseurlpath'] = \SimpleSAML\Module::getModuleURL('negotiate');
+        $t->data['url'] = $url;
+        $t->data['json_url'] = $json_url;
+        $t->show();
     }
 
 
@@ -261,29 +260,29 @@ EOF;
      *
      * @param array $state Information about the current authentication.
      *
-     * @throws SimpleSAML_Error_Error If couldn't determine the auth source.
-     * @throws SimpleSAML_Error_Exception
-     * @throws Exception
+     * @throws \SimpleSAML\Error\Error If couldn't determine the auth source.
+     * @throws \SimpleSAML\Error\Exception
+     * @throws \Exception
      */
     public static function fallBack(&$state)
     {
         $authId = $state['LogoutState']['negotiate:backend'];
 
         if ($authId === null) {
-            throw new SimpleSAML_Error_Error(array(500, "Unable to determine auth source."));
+            throw new \SimpleSAML\Error\Error([500, "Unable to determine auth source."]);
         }
-        $source = SimpleSAML_Auth_Source::getById($authId);
+        $source = \SimpleSAML\Auth\Source::getById($authId);
 
         try {
             $source->authenticate($state);
-        } catch (SimpleSAML_Error_Exception $e) {
-            SimpleSAML_Auth_State::throwException($state, $e);
-        } catch (Exception $e) {
-            $e = new SimpleSAML_Error_UnserializableException($e);
-            SimpleSAML_Auth_State::throwException($state, $e);
+        } catch (\SimpleSAML\Error\Exception $e) {
+            \SimpleSAML\Auth\State::throwException($state, $e);
+        } catch (\Exception $e) {
+            $e = new \SimpleSAML\Error\UnserializableException($e);
+            \SimpleSAML\Auth\State::throwException($state, $e);
         }
         // fallBack never returns after loginCompleted()
-        SimpleSAML\Logger::debug('Negotiate: backend returned');
+        Logger::debug('Negotiate: backend returned');
         self::loginCompleted($state);
     }
 
@@ -309,8 +308,8 @@ EOF;
         try {
             $dn = $this->ldap->searchfordn($this->base, $this->attr, $uid);
             return $this->ldap->getAttributes($dn, $this->attributes);
-        } catch (SimpleSAML_Error_Exception $e) {
-            SimpleSAML\Logger::debug('Negotiate - ldap lookup failed: '.$e);
+        } catch (\SimpleSAML\Error\Exception $e) {
+            Logger::debug('Negotiate - ldap lookup failed: '.$e);
             return null;
         }
     }
@@ -326,14 +325,12 @@ EOF;
             // no admin user
             return;
         }
-        SimpleSAML\Logger::debug(
-            'Negotiate - authenticate(): Binding as system user '.var_export($this->admin_user, true)
-        );
+        Logger::debug('Negotiate - authenticate(): Binding as system user '.var_export($this->admin_user, true));
 
         if (!$this->ldap->bind($this->admin_user, $this->admin_pw)) {
             $msg = 'Unable to authenticate system user (LDAP_INVALID_CREDENTIALS) '.var_export($this->admin_user, true);
-            SimpleSAML\Logger::error('Negotiate - authenticate(): '.$msg);
-            throw new SimpleSAML_Error_AuthSource('negotiate', $msg);
+            Logger::error('Negotiate - authenticate(): '.$msg);
+            throw new \SimpleSAML\Error\AuthSource('negotiate', $msg);
         }
     }
 
@@ -351,14 +348,14 @@ EOF;
         assert(is_array($state));
         // get the source that was used to authenticate
         $authId = $state['negotiate:backend'];
-        SimpleSAML\Logger::debug('Negotiate - logout has the following authId: "'.$authId.'"');
+        Logger::debug('Negotiate - logout has the following authId: "'.$authId.'"');
 
         if ($authId === null) {
-            $session = SimpleSAML_Session::getSessionFromRequest();
+            $session = \SimpleSAML\Session::getSessionFromRequest();
             $session->setData('negotiate:disable', 'session', true, 24 * 60 * 60);
             parent::logout($state);
         } else {
-            $source = SimpleSAML_Auth_Source::getById($authId);
+            $source = \SimpleSAML\Auth\Source::getById($authId);
             $source->logout($state);
         }
     }
diff --git a/modules/negotiate/locales/af/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/af/LC_MESSAGES/negotiate.po
index 9976b2b2fbf8976fb87aa1876114888a020b0fa2..bfbdf2194bff2f8e163143a24cb9b513e684dad9 100644
--- a/modules/negotiate/locales/af/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/af/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p> Deur toegang te verkry tot die bladsy het jy outomatiese aanmelding "
 "vermoë afgeskakel vir die webblaaier.</p> <p> Om dit weer te aktiveer "
-"besoek <a href='URL'> hierdie bladsy </a>. </p>"
+"besoek <a href='%URL%'> hierdie bladsy </a>. </p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p> Deur toegang te verkry tot die bladsy het jy outomatiese aanmelding "
 "vermoë aangeskakel vir die webblaaier.</p> <p> Om dit weer te deaktiveer "
-"besoek <a href='URL'> hierdie bladsy </a>. </p>"
+"besoek <a href='%URL%'> hierdie bladsy </a>. </p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
diff --git a/modules/negotiate/locales/ar/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/ar/LC_MESSAGES/negotiate.po
index 18ed6f13d1422764ed8483bc9df182e1ecf86d8c..91af8a473c7a379db24f96467cc6c2cf0b274888 100644
--- a/modules/negotiate/locales/ar/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/ar/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgstr "لقد تم تفعيل خاصية الدخول التلقائي في ه
 msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>بدخولك على هذه الصفحة, فقد قمت بإيقاف خاصية الدخول التلقائي من "
-"المتصفح.</p><p>لإعادة تشغيلها مرة أخرى قم بزيارة <a href='URL'>هذه "
+"المتصفح.</p><p>لإعادة تشغيلها مرة أخرى قم بزيارة <a href='%URL%'>هذه "
 "الصفحة</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>بدخولك على هذه الصفحة, فقد قمت بتفعيل خاصية الدخول التلقائي من "
-"المتصفح.</p><p>لإعادة إيقافها مرة أخرى قم بزيارة <a href='URL'>هذه "
+"المتصفح.</p><p>لإعادة إيقافها مرة أخرى قم بزيارة <a href='%URL%'>هذه "
 "الصفحة</a>.</p>"
 
 msgid ""
@@ -75,9 +75,9 @@ msgstr "لقد تم تفعيل خاصية الدخول التلقائي في ه
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>بدخولك على هذه الصفحة, فقد قمت بإيقاف خاصية الدخول التلقائي من "
-"المتصفح.</p><p>لإعادة تشغيلها مرة أخرى قم بزيارة <a href='URL'>هذه "
+"المتصفح.</p><p>لإعادة تشغيلها مرة أخرى قم بزيارة <a href='%URL%'>هذه "
 "الصفحة</a>.</p>"
 
diff --git a/modules/negotiate/locales/cs/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/cs/LC_MESSAGES/negotiate.po
index 219ad399b045207d102ea6d2f4a4fe223fdd1f73..08a74a04b946bd2141416b01430823995d273b2f 100644
--- a/modules/negotiate/locales/cs/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/cs/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Přístupem na tuto stránku jste vypnuli možnost použít automatické "
 "přihlášení pro tento prohlížeč.</p><p>Pro její zapnutí, prosím, navštivte"
-" <a href='URL'>tuto stránku</a>.</p>"
+" <a href='%URL%'>tuto stránku</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Přístupem na tuto stránku jste zapnuli možnost použít automatické "
 "přihlášení pro tento prohlížeč.</p><p>Pro její vypnutí, prosím, navštivte"
-" <a href='URL'>tuto stránku</a>.</p>"
+" <a href='%URL%'>tuto stránku</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -73,9 +73,9 @@ msgstr "Povolena možnost použití automatického přihlášení pro tento proh
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Přístupem na tuto stránku jste vypnuli možnost použít automatické "
 "přihlášení pro tento prohlížeč.</p><p>Pro její zapnutí, prosím, navštivte"
-" <a href='URL'>tuto stránku</a>.</p>"
+" <a href='%URL%'>tuto stránku</a>.</p>"
 
diff --git a/modules/negotiate/locales/da/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/da/LC_MESSAGES/negotiate.po
index 5d001ccda9c190c1c691a00f3cd1a67d1c390979..5bcc8fdbd009038d3cad8c60d9793295e4c39624 100644
--- a/modules/negotiate/locales/da/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/da/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Ved at tilgĂĄ denne side har du slĂĄet mulighed for automatisk login med"
 " denne browser fra.</p><p>For at slå muligheden til igen, besøg venligst "
-"<a href='URL'>denne side</a>.</p>"
+"<a href='%URL%'>denne side</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Ved at tilgĂĄ denne side har du slĂĄet mulighed for automatisk login med"
 " denne browser til.</p><p>For at slå muligheden fra igen, besøg venligst "
-"<a href='URL'>denne side</a>.</p>"
+"<a href='%URL%'>denne side</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved at tilgĂĄ denne side har du slĂĄet mulighed for automatisk login med"
 " denne browser til.</p><p>For at slå muligheden fra igen, besøg venligst "
-"<a href='URL'>denne side</a>.</p>"
+"<a href='%URL%'>denne side</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Mulighed for automatisk login med denne browser er slĂĄet fra"
@@ -74,9 +74,9 @@ msgstr "Mulighed for automatisk login med denne browser er slĂĄet til"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved at tilgĂĄ denne side har du slĂĄet mulighed for automatisk login med"
 " denne browser fra.</p><p>For at slå muligheden til igen, besøg venligst "
-"<a href='URL'>denne side</a>.</p>"
+"<a href='%URL%'>denne side</a>.</p>"
 
diff --git a/modules/negotiate/locales/de/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/de/LC_MESSAGES/negotiate.po
index 1810f2e911a94bc82089405f665e4f479cc05793..ada16b2038774d048f5b7d84b61ab504dbfe0185 100644
--- a/modules/negotiate/locales/de/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/de/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Durch den Zugriff auf diese Seite haben Sie die automatische Anmeldung"
 " fĂĽr diesen Browser ausgeschaltet.</p><p>Um sie wieder einzuschalten, "
-"besuchen Sie bitte<a href='URL'>diese Seite</a>.</p>"
+"besuchen Sie bitte<a href='%URL%'>diese Seite</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Durch den Zugriff auf diese Seite haben Sie die automatische Anmeldung"
 " fĂĽr diesen Browser eingeschaltet.</p><p>Um sie wieder auszuschalten, "
-"besuchen Sie bitte<a href='URL'>diese Seite</a>.</p>"
+"besuchen Sie bitte<a href='%URL%'>diese Seite</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Durch den Zugriff auf diese Seite haben Sie die automatische Anmeldung"
 " fĂĽr diesen Browser eingeschaltet.</p><p>Um sie wieder auszuschalten, "
-"besuchen Sie bitte<a href='URL'>diese Seite</a>.</p>"
+"besuchen Sie bitte<a href='%URL%'>diese Seite</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Automatische Anmeldung fĂĽr diesen Browser ausgeschaltet."
@@ -74,9 +74,9 @@ msgstr "Automatische Anmeldung fĂĽr diesen Browser eingeschaltet."
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Durch den Zugriff auf diese Seite haben Sie die automatische Anmeldung"
 " fĂĽr diesen Browser ausgeschaltet.</p><p>Um sie wieder einzuschalten, "
-"besuchen Sie bitte<a href='URL'>diese Seite</a>.</p>"
+"besuchen Sie bitte<a href='%URL%'>diese Seite</a>.</p>"
 
diff --git a/modules/negotiate/locales/en/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/en/LC_MESSAGES/negotiate.po
index e15f012ff9d2191ed55389eef767985220f7a890..30a55b95e2d1262753770a4cee8a54397152572a 100644
--- a/modules/negotiate/locales/en/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/en/LC_MESSAGES/negotiate.po
@@ -33,13 +33,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -57,11 +57,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Turned off ability to use automatic login for this browser"
@@ -72,9 +72,9 @@ msgstr "Turned on the ability to use automatic login for this browser"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 
diff --git a/modules/negotiate/locales/es/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/es/LC_MESSAGES/negotiate.po
index 4e403dbabc590057554f7f944ccadc419744b940..8224dfb0dbee34caf5ee511286a4e5e7b6ef9594 100644
--- a/modules/negotiate/locales/es/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/es/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Al acceder a esta página, ha deshabilitado la posibilidad de "
 "identificarse automáticamente en este navegador.</p><p>Para habilitarla "
-"de nuevo, por favor, visite <a href='URL'>esta página</a>.</p>"
+"de nuevo, por favor, visite <a href='%URL%'>esta página</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Al acceder a esta página, ha habilitado la identificación automática "
 "en este navegador.</p><p>Para deshabilitarlo de nuevo, por favor, visite "
-"<a href='URL'>esta página</a>.</p>"
+"<a href='%URL%'>esta página</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Al acceder a esta página, ha habilitado la identificación automática "
 "en este navegador.</p><p>Para deshabilitarlo de nuevo, por favor, visite "
-"<a href='URL'>esta página</a>.</p>"
+"<a href='%URL%'>esta página</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "La identificación automática en este navegador se ha deshabilitado."
@@ -74,9 +74,9 @@ msgstr "La identificación automática en este navegador se ha habilitado."
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Al acceder a esta página, ha deshabilitado la posibilidad de "
 "identificarse automáticamente en este navegador.</p><p>Para habilitarla "
-"de nuevo, por favor, visite <a href='URL'>esta página</a>.</p>"
+"de nuevo, por favor, visite <a href='%URL%'>esta página</a>.</p>"
 
diff --git a/modules/negotiate/locales/et/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/et/LC_MESSAGES/negotiate.po
index 79347bd7fe9bacc554aa236ef960e585b4b2675e..4623c84f6ee5c249b0e400d8eb6699fb71a3a92f 100644
--- a/modules/negotiate/locales/et/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/et/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgstr "LĂĽlitasid automaatse sisselogimise selles brauseris sisse"
 msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Seda lehekĂĽlge kĂĽlastades lĂĽlitasid automaatse sisselogimise selles "
-"brauseris välja.</p><p>Sisse lülitamiseks külasta <a href='URL'>seda "
+"brauseris välja.</p><p>Sisse lülitamiseks külasta <a href='%URL%'>seda "
 "lehekĂĽlge</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Seda lehekĂĽlge kĂĽlastades lĂĽlitasid automaatse sisselogimise selles "
-"brauseris sisse.</p><p>Välja lülitamiseks külasta <a href='URL'>seda "
+"brauseris sisse.</p><p>Välja lülitamiseks külasta <a href='%URL%'>seda "
 "lehekĂĽlge</a>.</p>"
 
 msgid ""
@@ -59,10 +59,10 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Seda lehekĂĽlge kĂĽlastades lĂĽlitasid automaatse sisselogimise selles "
-"brauseris sisse.</p><p>Välja lülitamiseks külasta <a href='URL'>seda "
+"brauseris sisse.</p><p>Välja lülitamiseks külasta <a href='%URL%'>seda "
 "lehekĂĽlge</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
@@ -76,9 +76,9 @@ msgstr "LĂĽlitasid automaatse sisselogimise selles brauseris sisse"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Seda lehekĂĽlge kĂĽlastades lĂĽlitasid automaatse sisselogimise selles "
-"brauseris välja.</p><p>Sisse lülitamiseks külasta <a href='URL'>seda "
+"brauseris välja.</p><p>Sisse lülitamiseks külasta <a href='%URL%'>seda "
 "lehekĂĽlge</a>.</p>"
 
diff --git a/modules/negotiate/locales/eu/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/eu/LC_MESSAGES/negotiate.po
index 8a1f65e7cd91738c7598c2a23dc4068b7b227997..428f3c62b9e07bb68ef9355766fab6b57918c44d 100644
--- a/modules/negotiate/locales/eu/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/eu/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Orri honetan sartzean, nabigatzaile honetan automatikoki "
 "identifikatzeko aukera desgaitu da. </p><p>Berriz gaitzeko, mesedez, "
-"bisita ezazu <a href='URL'>orri hau</a>.</p>"
+"bisita ezazu <a href='%URL%'>orri hau</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Orri honetan sartzean, nabigatzaile honetan automatikoki "
 "identifikatzeko aukera gaitu da. </p><p>Berriz desgaitzeko, mesedez, "
-"bisita ezazu <a href='URL'>orri hau</a>.</p>"
+"bisita ezazu <a href='%URL%'>orri hau</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Orri honetan sartzean, nabigatzaile honetan automatikoki "
 "identifikatzeko aukera gaitu da. </p><p>Berriz desgaitzeko, mesedez, "
-"bisita ezazu <a href='URL'>orri hau</a>.</p>"
+"bisita ezazu <a href='%URL%'>orri hau</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Nabigatzaile honetan identifikazio automatikoa desgaitu da."
@@ -74,9 +74,9 @@ msgstr "Nabigatzaile honetan identifikazio automatikoa gaitu da."
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Orri honetan sartzean, nabigatzaile honetan automatikoki "
 "identifikatzeko aukera desgaitu da. </p><p>Berriz gaitzeko, mesedez, "
-"bisita ezazu <a href='URL'>orri hau</a>.</p>"
+"bisita ezazu <a href='%URL%'>orri hau</a>.</p>"
 
diff --git a/modules/negotiate/locales/fr/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/fr/LC_MESSAGES/negotiate.po
index aaa68e512f97f49b4c3fe60287b968a86e94cff3..34412937486ec94e76670fc233269535a0bbcce4 100644
--- a/modules/negotiate/locales/fr/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/fr/LC_MESSAGES/negotiate.po
@@ -38,13 +38,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>En accédant à cette page, vous avez désactivé la possibilité "
 "d'utiliser la connection automatique pour ce navigateur.</p><p>Pour "
-"l'activer Ă  nouveau, merci de visiter <a href='URL'>cette page</a>.</p>"
+"l'activer Ă  nouveau, merci de visiter <a href='%URL%'>cette page</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>En accédant à cette page, vous avez activé la possibilité d'utiliser "
 "la connection automatique pour ce navigateur.</p><p>Pour la désactiver à "
-"nouveau, merci de visiter <a href='URL'>cette page</a>.</p>"
+"nouveau, merci de visiter <a href='%URL%'>cette page</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -63,11 +63,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>En accédant à cette page, vous avez activé la possibilité d'utiliser "
 "la connection automatique pour ce navigateur.</p><p>Pour la désactiver à "
-"nouveau, merci de visiter <a href='URL'>cette page</a>.</p>"
+"nouveau, merci de visiter <a href='%URL%'>cette page</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr ""
@@ -82,9 +82,9 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>En accédant à cette page, vous avez désactivé la possibilité "
 "d'utiliser la connection automatique pour ce navigateur.</p><p>Pour "
-"l'activer Ă  nouveau, merci de visiter <a href='URL'>cette page</a>.</p>"
+"l'activer Ă  nouveau, merci de visiter <a href='%URL%'>cette page</a>.</p>"
 
diff --git a/modules/negotiate/locales/hr/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/hr/LC_MESSAGES/negotiate.po
index 66224180fd6f2b496182a0a96f47c855443eac03..e4e8c246d74e72857957325557554f1cb4a56cb6 100644
--- a/modules/negotiate/locales/hr/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/hr/LC_MESSAGES/negotiate.po
@@ -35,13 +35,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Pristupanjem ovoj stranici iskljuÄŤili ste opciju automatske prijave za"
 " ovaj web preglednik.</p><p>Da biste je ponovo ukljuÄŤili, kliknite <a "
-"href='URL'>ovdje</a>.</p>"
+"href='%URL%'>ovdje</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Pristupanjem ovoj stranici ukljuÄŤili ste opciju automatske prijave za "
 "ovaj web preglednik.</p><p>Da biste iskljuÄŤili opciju automatskog "
-"prijavljivanja, kliknite <a href='URL'>ovdje</a>.</p>"
+"prijavljivanja, kliknite <a href='%URL%'>ovdje</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -60,11 +60,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Pristupanjem ovoj stranici ukljuÄŤili ste opciju automatske prijave za "
 "ovaj web preglednik.</p><p>Da biste iskljuÄŤili opciju automatskog "
-"prijavljivanja, kliknite <a href='URL'>ovdje</a>.</p>"
+"prijavljivanja, kliknite <a href='%URL%'>ovdje</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Mogućnost automatske prijave za ovaj web preglednik je isključena"
@@ -75,9 +75,9 @@ msgstr "Mogućnost automatske prijave za ovaj web preglednik je uključena"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Pristupanjem ovoj stranici iskljuÄŤili ste opciju automatske prijave za"
 " ovaj web preglednik.</p><p>Da biste je ponovo ukljuÄŤili, kliknite <a "
-"href='URL'>ovdje</a>.</p>"
+"href='%URL%'>ovdje</a>.</p>"
 
diff --git a/modules/negotiate/locales/id/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/id/LC_MESSAGES/negotiate.po
index 03418cde3c240c01bafec28d1dfe87ff4be63849..efa859cf47a29f127388528938c5dd22d1932f89 100644
--- a/modules/negotiate/locales/id/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/id/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Dengan mengakses halaman ini, Anda telah mematikan login otomatis pada"
 " peramban ini.</p><p>Hendak menghidupkan login otomatis? Mohon kunjungi "
-"<a href='URL'>halaman ini</a>.</p>"
+"<a href='%URL%'>halaman ini</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Dengan mengakses halaman ini, Anda telah mengaktifkan login otomatis "
 "pada peramban ini.</p><p>Hendak mematika  login otomatis? Silakan "
-"kunjungi <a href='URL'>halaman ini</a>.</p>"
+"kunjungi <a href='%URL%'>halaman ini</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Dengan mengakses halaman ini, Anda telah mengaktifkan login otomatis "
 "pada peramban ini.</p><p>Hendak mematika  login otomatis? Silakan "
-"kunjungi <a href='URL'>halaman ini</a>.</p>"
+"kunjungi <a href='%URL%'>halaman ini</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Login otomatis pada peramban ini telah dimatikan"
@@ -74,9 +74,9 @@ msgstr "Login otomatis pada peramban ini telah diaktifkan"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Dengan mengakses halaman ini, Anda telah mematikan login otomatis pada"
 " peramban ini.</p><p>Hendak menghidupkan login otomatis? Mohon kunjungi "
-"<a href='URL'>halaman ini</a>.</p>"
+"<a href='%URL%'>halaman ini</a>.</p>"
 
diff --git a/modules/negotiate/locales/it/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/it/LC_MESSAGES/negotiate.po
index 4edff1d992725bc4ec3aef2bdcb8d32153be8d58..f579734f0feb26fdc7f2f87430127b6acce2214a 100644
--- a/modules/negotiate/locales/it/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/it/LC_MESSAGES/negotiate.po
@@ -32,13 +32,13 @@ msgstr "Login automatico per questo browser attivato."
 msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Per accedere a questa pagina devi disabilitare il login automatico sul"
-" tuo browser</p><p>Per riattivarlo visita <a href='URL'>questa "
+" tuo browser</p><p>Per riattivarlo visita <a href='%URL%'>questa "
 "pagina</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Per accedere a questa pagina devi abilitare il login automatico sul "
-"tuo browser</p><p>Per riattivarlo visita <a href='URL'>questa "
+"tuo browser</p><p>Per riattivarlo visita <a href='%URL%'>questa "
 "pagina</a>.</p>"
 
 msgid ""
@@ -57,10 +57,10 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Per accedere a questa pagina devi abilitare il login automatico sul "
-"tuo browser</p><p>Per riattivarlo visita <a href='URL'>questa "
+"tuo browser</p><p>Per riattivarlo visita <a href='%URL%'>questa "
 "pagina</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
@@ -72,9 +72,9 @@ msgstr "Login automatico per questo browser attivato."
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Per accedere a questa pagina devi disabilitare il login automatico sul"
-" tuo browser</p><p>Per riattivarlo visita <a href='URL'>questa "
+" tuo browser</p><p>Per riattivarlo visita <a href='%URL%'>questa "
 "pagina</a>.</p>"
 
diff --git a/modules/negotiate/locales/lt/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/lt/LC_MESSAGES/negotiate.po
index ab0b640e2486a63508d30f8959cb3954a25b2fe0..ef7d482034a817d14f1a3088f3b8097184e0b68f 100644
--- a/modules/negotiate/locales/lt/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/lt/LC_MESSAGES/negotiate.po
@@ -35,13 +35,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Jungdamiesi į šią setainę, Jūs išjungėte galimybę naudoti automatinį "
 "prisijungimą šioje naršyklėje.</p><p>Norėdami jį vėl įjungti, "
-"apsilankykite <a href='URL'>šioje svetainėje</a>.</p>"
+"apsilankykite <a href='%URL%'>šioje svetainėje</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Jungdamiesi į šią setainę, Jūs įjungėte galimybę naudoti automatinį "
 "prisijungimą šioje naršyklėje.</p><p>Norėdami jį vėl išjungti, "
-"apsilankykite <a href='URL'>šioje svetainėje</a>.</p>"
+"apsilankykite <a href='%URL%'>šioje svetainėje</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -60,11 +60,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Jungdamiesi į šią setainę, Jūs įjungėte galimybę naudoti automatinį "
 "prisijungimą šioje naršyklėje.</p><p>Norėdami jį vėl išjungti, "
-"apsilankykite <a href='URL'>šioje svetainėje</a>.</p>"
+"apsilankykite <a href='%URL%'>šioje svetainėje</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Išjungta galimybė naudoti automatinį prisijungimą šioje naršyklėje"
@@ -75,9 +75,9 @@ msgstr "Įjungta galimybė naudoti automatinį prisijungimą šioje naršyklėje
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Jungdamiesi į šią setainę, Jūs išjungėte galimybę naudoti automatinį "
 "prisijungimą šioje naršyklėje.</p><p>Norėdami jį vėl įjungti, "
-"apsilankykite <a href='URL'>šioje svetainėje</a>.</p>"
+"apsilankykite <a href='%URL%'>šioje svetainėje</a>.</p>"
 
diff --git a/modules/negotiate/locales/nb/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/nb/LC_MESSAGES/negotiate.po
index 64d3071f15f35395de7b07a92039f0e6d8ccd0de..ac282609bf5bd8180103e7b977dd9a716495e14b 100644
--- a/modules/negotiate/locales/nb/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/nb/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd av muligheten for automatisk "
 "innlogging for denne nettleseren.</p><p>For ĂĄ skru pĂĄ igjen muligheten, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd pĂĄ muligheten for automatisk "
 "innlogging for denne nettleseren.</p><p>For ĂĄ skru av igjen muligheten, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd pĂĄ muligheten for automatisk "
 "innlogging for denne nettleseren.</p><p>For ĂĄ skru av igjen muligheten, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Skrudd av mulighet for automatisk innlogging for denne nettleseren"
@@ -74,9 +74,9 @@ msgstr "Skrudd pĂĄ mulighet for automatisk innlogging for denne nettleseren"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd av muligheten for automatisk "
 "innlogging for denne nettleseren.</p><p>For ĂĄ skru pĂĄ igjen muligheten, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
diff --git a/modules/negotiate/locales/nl/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/nl/LC_MESSAGES/negotiate.po
index 1a073b86fca3792a423ccaf0136a6e722903c6b8..f0553d41f620f3cde570501965ae36ccd91803d4 100644
--- a/modules/negotiate/locales/nl/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/nl/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Middels het laden van deze pagina heeft u de mogelijkheid tot "
 "automatisch inloggen uitgeschakeld voor deze browser.</p><p>Om dit weer "
-"in te schakelen, bezoekt u <a href='URL'>deze pagina</a>.</p>"
+"in te schakelen, bezoekt u <a href='%URL%'>deze pagina</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Middels het laden van deze pagina heeft u de mogelijkheid tot "
 "automatisch inloggen ingeschakeld voor deze browser.</p><p>Om dit weer "
-"uit te schakelen, bezoekt u <a href='URL'>deze pagina</a>.</p>"
+"uit te schakelen, bezoekt u <a href='%URL%'>deze pagina</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Middels het laden van deze pagina heeft u de mogelijkheid tot "
 "automatisch inloggen ingeschakeld voor deze browser.</p><p>Om dit weer "
-"uit te schakelen, bezoekt u <a href='URL'>deze pagina</a>.</p>"
+"uit te schakelen, bezoekt u <a href='%URL%'>deze pagina</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Mogelijkheid tot automatisch inloggen voor deze browser uitgeschakeld"
@@ -74,9 +74,9 @@ msgstr "Mogelijkheid tot automatisch inloggen voor deze browser ingeschakeld"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Middels het laden van deze pagina heeft u de mogelijkheid tot "
 "automatisch inloggen uitgeschakeld voor deze browser.</p><p>Om dit weer "
-"in te schakelen, bezoekt u <a href='URL'>deze pagina</a>.</p>"
+"in te schakelen, bezoekt u <a href='%URL%'>deze pagina</a>.</p>"
 
diff --git a/modules/negotiate/locales/nn/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/nn/LC_MESSAGES/negotiate.po
index 05e0c597fff2b0e8718273ce42cbca4571b8ba3b..5c79bdfb3df82342c6f81e3204b25604ac956995 100644
--- a/modules/negotiate/locales/nn/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/nn/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd av moglegheit for automatisk "
 "innlogging for denne nettlesaren.</p><p>For ĂĄ skru pĂĄ igjen moglegheita, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd pĂĄ moglegheit for automatisk "
 "innlogging for denne nettlesaren.</p><p>For ĂĄ skru av igjen moglegheita, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -59,11 +59,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd pĂĄ moglegheit for automatisk "
 "innlogging for denne nettlesaren.</p><p>For ĂĄ skru av igjen moglegheita, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Skrudd av moglegheit for automatisk innlogging for denne nettlesaren"
@@ -74,9 +74,9 @@ msgstr "Skrudd pĂĄ moglegheit for automatisk innlogging for denne nettlesaren"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Ved ĂĄ gĂĄ til denne siden har du skrudd av moglegheit for automatisk "
 "innlogging for denne nettlesaren.</p><p>For ĂĄ skru pĂĄ igjen moglegheita, "
-"kan du gĂĄ til <a href='URL'>denne siden</a>.</p>"
+"kan du gĂĄ til <a href='%URL%'>denne siden</a>.</p>"
 
diff --git a/modules/negotiate/locales/ro/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/ro/LC_MESSAGES/negotiate.po
index ff2c088615063b1ec300deba1601fa0a9c5913b9..259e2fdc28258022acf333095932c6f0d81e05e9 100644
--- a/modules/negotiate/locales/ro/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/ro/LC_MESSAGES/negotiate.po
@@ -39,14 +39,14 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Prin accesarea acestei pagini ați dezactivat posibilitatea utilizării "
 "autentificării automate pentru acest browser.</p><p>Pentru a activa din "
-"nou această posibilitate vă rugăm să accesați <a href=\"URL\">această "
+"nou această posibilitate vă rugăm să accesați <a href='%URL%'>această "
 "pagină</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Prin accesarea acestei pagini ați activat posibilitatea utilizării "
 "autentificării automate pentru acest browser.</p><p>Pentru a dezactiva "
-"această posibilitate vă rugăm să accesați <a href=\"URL\">această "
+"această posibilitate vă rugăm să accesați <a href='%URL%'>această "
 "pagină</a>.</p>"
 
 msgid ""
@@ -66,11 +66,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Prin accesarea acestei pagini ați activat posibilitatea utilizării "
 "autentificării automate pentru acest browser.</p><p>Pentru a dezactiva "
-"această posibilitate vă rugăm să accesați <a href=\"URL\">această "
+"această posibilitate vă rugăm să accesați <a href='%URL%'>această "
 "pagină</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
@@ -86,10 +86,10 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Prin accesarea acestei pagini ați dezactivat posibilitatea utilizării "
 "autentificării automate pentru acest browser.</p><p>Pentru a activa din "
-"nou această posibilitate vă rugăm să accesați <a href=\"URL\">această "
+"nou această posibilitate vă rugăm să accesați <a href='%URL%'>această "
 "pagină</a>.</p>"
 
diff --git a/modules/negotiate/locales/ru/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/ru/LC_MESSAGES/negotiate.po
index cefd89e1ffded6a06326624d1078fe2af2b0cf11..0011b484cbeec43d0ca0f4287337fd6012a10b70 100644
--- a/modules/negotiate/locales/ru/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/ru/LC_MESSAGES/negotiate.po
@@ -36,13 +36,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Войдя на эту страницу, Вы отключили возможность использовать функцию "
 "автоматического логина в данном браузере.</p><p>Для повторного включения "
-"посетите <a href='URL'>эту страницу</a>.</p>"
+"посетите <a href='%URL%'>эту страницу</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Войдя на эту страницу, Вы включили возможность использовать функцию "
 "автоматического логина в данном браузере.</p><p>Для ее отключения , "
-"пожалуйста, посетите <a href='URL'>эту страницу</a>.</p>"
+"пожалуйста, посетите <a href='%URL%'>эту страницу</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -60,11 +60,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Войдя на эту страницу, Вы включили возможность использовать функцию "
 "автоматического логина в данном браузере.</p><p>Для ее отключения , "
-"пожалуйста, посетите <a href='URL'>эту страницу</a>.</p>"
+"пожалуйста, посетите <a href='%URL%'>эту страницу</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Отключить функцию автоматического логина для данного браузера"
@@ -77,9 +77,9 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Войдя на эту страницу, Вы отключили возможность использовать функцию "
 "автоматического логина в данном браузере.</p><p>Для повторного включения "
-"посетите <a href='URL'>эту страницу</a>.</p>"
+"посетите <a href='%URL%'>эту страницу</a>.</p>"
 
diff --git a/modules/negotiate/locales/sr/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/sr/LC_MESSAGES/negotiate.po
index 3b6711bd5df3cabb424b63079adeefbb91dab118..dadd2077f4d98af96b10f7fb6014ca05613cc68c 100644
--- a/modules/negotiate/locales/sr/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/sr/LC_MESSAGES/negotiate.po
@@ -34,13 +34,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Pristupanjem na ovu stranicu, ovaj pretraĹľivaÄŤ ste za iskljuÄŤili "
 "mogućnost automatske prijave.</p><p>Da bi ste opet uključili ovu "
-"mogućnost, molim vas posetite <a href='URL'>ovu stranicu</a>.</p>"
+"mogućnost, molim vas posetite <a href='%URL%'>ovu stranicu</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Pristupanjem na ovu stranicu, ovaj pretraĹľivaÄŤ ste za ukljuÄŤili "
 "mogućnost automatske prijave.</p><p>Da bi ste opet isključili ovu "
-"mogućnost, molim vas posetite <a href='URL'>ovu stranicu</a>.</p>"
+"mogućnost, molim vas posetite <a href='%URL%'>ovu stranicu</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -58,11 +58,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Pristupanjem na ovu stranicu, ovaj pretraĹľivaÄŤ ste za ukljuÄŤili "
 "mogućnost automatske prijave.</p><p>Da bi ste opet isključili ovu "
-"mogućnost, molim vas posetite <a href='URL'>ovu stranicu</a>.</p>"
+"mogućnost, molim vas posetite <a href='%URL%'>ovu stranicu</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "Mogućnost automatske prijave je za ovaj pretraživač isključena"
@@ -73,9 +73,9 @@ msgstr "Mogućnost automatske prijave je za ovaj pretraživač uključena"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Pristupanjem na ovu stranicu, ovaj pretraĹľivaÄŤ ste za iskljuÄŤili "
 "mogućnost automatske prijave.</p><p>Da bi ste opet uključili ovu "
-"mogućnost, molim vas posetite <a href='URL'>ovu stranicu</a>.</p>"
+"mogućnost, molim vas posetite <a href='%URL%'>ovu stranicu</a>.</p>"
 
diff --git a/modules/negotiate/locales/sv/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/sv/LC_MESSAGES/negotiate.po
index b2e6bfefe035cfe55266aa3253e3591cab9d4d0b..ef4890ee15aad29cdb5717c751f97ef11afa5501 100644
--- a/modules/negotiate/locales/sv/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/sv/LC_MESSAGES/negotiate.po
@@ -38,13 +38,13 @@ msgid "{negotiate:negotiate:disable_info_pre}"
 msgstr ""
 "<p>Genom att besöka denna sida har du stängt av möjligheten att använda "
 "automatisk inloggning för denna webbläsare.</p><p>För att slå på "
-"möjligheten igen besök <a href='URL'>denna sida</a>.</p>"
+"möjligheten igen besök <a href='%URL%'>denna sida</a>.</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
 msgstr ""
 "<p>Genom att besöka denna sida har du aktiverat möjligheten att använda "
 "automatisk inloggning för denna webbläsare.</p><p>För att slå av "
-"möjligheten igen besök <a href='URL'>denna sida</a>.</p>"
+"möjligheten igen besök <a href='%URL%'>denna sida</a>.</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -63,11 +63,11 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Genom att besöka denna sida har du aktiverat möjligheten att använda "
 "automatisk inloggning för denna webbläsare.</p><p>För att slå av "
-"möjligheten igen besök <a href='URL'>denna sida</a>.</p>"
+"möjligheten igen besök <a href='%URL%'>denna sida</a>.</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr ""
@@ -82,9 +82,9 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
+" <a href='%URL%'>this page</a>.</p>"
 msgstr ""
 "<p>Genom att besöka denna sida har du stängt av möjligheten att använda "
 "automatisk inloggning för denna webbläsare.</p><p>För att slå på "
-"möjligheten igen besök <a href='URL'>denna sida</a>.</p>"
+"möjligheten igen besök <a href='%URL%'>denna sida</a>.</p>"
 
diff --git a/modules/negotiate/locales/zh-tw/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/zh-tw/LC_MESSAGES/negotiate.po
index c0c0fbb2a0ef39c33f8723a5ba772907baa6b1c5..4d85c762449728a83fc86721b0ecc1ef0510cd8a 100644
--- a/modules/negotiate/locales/zh-tw/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/zh-tw/LC_MESSAGES/negotiate.po
@@ -28,10 +28,10 @@ msgid "{negotiate:negotiate:enable_title}"
 msgstr "嘗試於瀏覽器開啟自動登入"
 
 msgid "{negotiate:negotiate:disable_info_pre}"
-msgstr "<p>當存取此頁時,您已經於瀏覽器關閉自動登入。</p><p>如要再度開啟,請造訪<a href='URL'>此頁</a>。</p>"
+msgstr "<p>當存取此頁時,您已經於瀏覽器關閉自動登入。</p><p>如要再度開啟,請造訪<a href='%URL%'>此頁</a>。</p>"
 
 msgid "{negotiate:negotiate:enable_info_pre}"
-msgstr "<p>當存取此頁時,您已經開啟瀏覽器自動登入。</p><p>如要再次關閉,請造訪<a href='URL'>此頁</a>。</p>"
+msgstr "<p>當存取此頁時,您已經開啟瀏覽器自動登入。</p><p>如要再次關閉,請造訪<a href='%URL%'>此頁</a>。</p>"
 
 msgid ""
 "<h3>What is automatic login</h3><p>Automatic login allows you to log in "
@@ -47,8 +47,8 @@ msgstr ""
 msgid ""
 "<p>By accessing this page, you have turned on the ability to use "
 "automatic login for this browser.</p><p>To turn it off again, please "
-"visit <a href='URL'>this page</a>.</p>"
-msgstr "<p>當存取此頁時,您已經開啟瀏覽器自動登入。</p><p>如要再次關閉,請造訪<a href='URL'>此頁</a>。</p>"
+"visit <a href='%URL%'>this page</a>.</p>"
+msgstr "<p>當存取此頁時,您已經開啟瀏覽器自動登入。</p><p>如要再次關閉,請造訪<a href='%URL%'>此頁</a>。</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "嘗試於瀏覽器關閉自動登入功能"
@@ -59,6 +59,6 @@ msgstr "嘗試於瀏覽器開啟自動登入"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
-msgstr "<p>當存取此頁時,您已經於瀏覽器關閉自動登入。</p><p>如要再度開啟,請造訪<a href='URL'>此頁</a>。</p>"
+" <a href='%URL%'>this page</a>.</p>"
+msgstr "<p>當存取此頁時,您已經於瀏覽器關閉自動登入。</p><p>如要再度開啟,請造訪<a href='%URL%'>此頁</a>。</p>"
 
diff --git a/modules/negotiate/locales/zh/LC_MESSAGES/negotiate.po b/modules/negotiate/locales/zh/LC_MESSAGES/negotiate.po
index c7f787f2cd795dea8762fa8b316863fff8858be3..5df463436a30be2ea9c56cf1122867bc80a5aaf4 100644
--- a/modules/negotiate/locales/zh/LC_MESSAGES/negotiate.po
+++ b/modules/negotiate/locales/zh/LC_MESSAGES/negotiate.po
@@ -22,7 +22,7 @@ msgid "{negotiate:negotiate:enable_title}"
 msgstr "启用本浏览器上的自动登录功能"
 
 msgid "{negotiate:negotiate:disable_info_pre}"
-msgstr "<p>当您连上本页面时,本浏览器自动登录功能已关闭。</p><p>请访问<a href='URL'>此处</a>以重新启用自动登录功能。</p>"
+msgstr "<p>当您连上本页面时,本浏览器自动登录功能已关闭。</p><p>请访问<a href='%URL%'>此处</a>以重新启用自动登录功能。</p>"
 
 msgid "Turned off ability to use automatic login for this browser"
 msgstr "关闭本浏览器上的自动登录功能"
@@ -33,6 +33,6 @@ msgstr "启用本浏览器上的自动登录功能"
 msgid ""
 "<p>By accessing this page, you have turned off the ability to use "
 "automatic login for this browser.</p><p>To turn it on again, please visit"
-" <a href='URL'>this page</a>.</p>"
-msgstr "<p>当您连上本页面时,本浏览器自动登录功能已关闭。</p><p>请访问<a href='URL'>此处</a>以重新启用自动登录功能。</p>"
+" <a href='%URL%'>this page</a>.</p>"
+msgstr "<p>当您连上本页面时,本浏览器自动登录功能已关闭。</p><p>请访问<a href='%URL%'>此处</a>以重新启用自动登录功能。</p>"
 
diff --git a/modules/negotiate/templates/disable.php b/modules/negotiate/templates/disable.php
index f9e2d55082eebd2a5e4efe9c84eecaebb1833a09..fd8338e9f49265f8a80830aeb5d033bf69c4a6f4 100644
--- a/modules/negotiate/templates/disable.php
+++ b/modules/negotiate/templates/disable.php
@@ -10,7 +10,7 @@
 $this->includeAtTemplateBase('includes/header.php');
 ?>
 <h1><?php echo $this->t('{negotiate:negotiate:disable_title}'); ?></h1>
-<?php echo $this->t('{negotiate:negotiate:disable_info_pre}', array('URL' => htmlspecialchars($this->data['url']))); ?>
+<?php echo $this->t('{negotiate:negotiate:disable_info_pre}', ['URL' => htmlspecialchars($this->data['url'])]); ?>
 
 <?php echo $this->t('{negotiate:negotiate:info_post}'); ?>
 
diff --git a/modules/negotiate/templates/disable.twig b/modules/negotiate/templates/disable.twig
new file mode 100644
index 0000000000000000000000000000000000000000..07fccdd269674e0262a98e5eada9541e90354c64
--- /dev/null
+++ b/modules/negotiate/templates/disable.twig
@@ -0,0 +1,9 @@
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>{{ '{negotiate:negotiate:disable_title}'|trans }}</h1>
+    <br />
+    {{ '{negotiate:negotiate:disable_info_pre}'|trans({'%URL%': url}, "app")|raw }}
+    <br />
+    {{ '{negotiate:negotiate:info_post}'|trans|raw }}
+{% endblock %}
diff --git a/modules/negotiate/templates/enable.php b/modules/negotiate/templates/enable.php
index 939af6fb6d828aedd6d178970fa803e064cc099a..a25b6a213b414cfe8c7348d41c13d168fffa412f 100644
--- a/modules/negotiate/templates/enable.php
+++ b/modules/negotiate/templates/enable.php
@@ -11,7 +11,7 @@ $this->includeAtTemplateBase('includes/header.php');
 ?>
 <h1><?php echo $this->t('{negotiate:negotiate:enable_title}'); ?></h1>
 
-<?php echo $this->t('{negotiate:negotiate:enable_info_pre}', array('URL' => htmlspecialchars($this->data['url']))); ?>
+<?php echo $this->t('{negotiate:negotiate:enable_info_pre}', ['URL' => htmlspecialchars($this->data['url'])]); ?>
 
 <?php echo $this->t('{negotiate:negotiate:info_post}'); ?>
 
diff --git a/modules/negotiate/templates/enable.twig b/modules/negotiate/templates/enable.twig
new file mode 100644
index 0000000000000000000000000000000000000000..07e5579646ad3cd524995969a6553a58fef1fe58
--- /dev/null
+++ b/modules/negotiate/templates/enable.twig
@@ -0,0 +1,9 @@
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>{{ '{negotiate:negotiate:enable_title}'|trans }}</h1>
+    <br />
+    {{ '{negotiate:negotiate:enable_info_pre}'|trans({'%URL%': url}, "app")|raw }}
+    <br />
+    {{ '{negotiate:negotiate:info_post}'|trans|raw }}
+{% endblock %}
diff --git a/modules/negotiate/templates/redirect.twig b/modules/negotiate/templates/redirect.twig
new file mode 100644
index 0000000000000000000000000000000000000000..3a69556eec3127cc60c5dec5ab09fac27d970857
--- /dev/null
+++ b/modules/negotiate/templates/redirect.twig
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<html lang="en-US">
+    <head>
+        <script src="{{ baseurlpath }}/assets/js/redirect.js"></script>
+        <title>Redirect to login</title>
+    </head>
+    <body>
+        <p>Your browser seems to have Javascript disabled. Please click <a id="redirect" href="{{ url }}">here</a>.</p>
+    </body>
+</html>
+
diff --git a/modules/negotiate/www/assets/js/redirect.js b/modules/negotiate/www/assets/js/redirect.js
new file mode 100644
index 0000000000000000000000000000000000000000..3b829d111db9ff4fbbb28f36c7ccb8dc87ce0277
--- /dev/null
+++ b/modules/negotiate/www/assets/js/redirect.js
@@ -0,0 +1,3 @@
+document.addEventListener('DOMContentLoaded', function () {
+    window.location = document.querySelector('#redirect');
+});
diff --git a/modules/negotiate/www/backend.php b/modules/negotiate/www/backend.php
index 5fa2619a4f160044026be82006777f31198a2373..8a5222f26dd378995e108b38105ce3fb445615c8 100644
--- a/modules/negotiate/www/backend.php
+++ b/modules/negotiate/www/backend.php
@@ -8,9 +8,12 @@
  * @package SimpleSAMLphp
  */
 
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], sspmod_negotiate_Auth_Source_Negotiate::STAGEID);
-SimpleSAML\Logger::debug('backend - fallback: '.$state['LogoutState']['negotiate:backend']);
+$state = \SimpleSAML\Auth\State::loadState(
+    $_REQUEST['AuthState'],
+    \SimpleSAML\Module\negotiate\Auth\Source\Negotiate::STAGEID
+);
+\SimpleSAML\Logger::debug('backend - fallback: '.$state['LogoutState']['negotiate:backend']);
 
-sspmod_negotiate_Auth_Source_Negotiate::fallBack($state);
+\SimpleSAML\Module\negotiate\Auth\Source\Negotiate::fallBack($state);
 
 exit;
diff --git a/modules/negotiate/www/disable.php b/modules/negotiate/www/disable.php
index 9cf8c592bfade86c515c6cec924a925ffe5f3a74..2734f05c31a7bbb9214a3ecf0965a3f74128aac4 100644
--- a/modules/negotiate/www/disable.php
+++ b/modules/negotiate/www/disable.php
@@ -1,23 +1,20 @@
 <?php
-
 /**
- *
- *
  * @author Mathias Meisfjordskar, University of Oslo.
  *         <mathias.meisfjordskar@usit.uio.no>
  * @package SimpleSAMLphp
  */
 
-$params = array(
-    'expire' => (mktime(0,0,0,1,1,2038)),
-    'secure' => FALSE,
-    'httponly' => TRUE,
-);
-\SimpleSAML\Utils\HTTP::setCookie('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', 'True', $params, FALSE);
+$params = [
+    'expire' => (mktime(0, 0, 0, 1, 1, 2038)),
+    'secure' => false,
+    'httponly' => true,
+];
+\SimpleSAML\Utils\HTTP::setCookie('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', 'True', $params, false);
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
-$session->setData('negotiate:disable', 'session', FALSE, 24*60*60);
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'negotiate:disable.php');
-$t->data['url'] = SimpleSAML\Module::getModuleURL('negotiate/enable.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
+$session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'negotiate:disable.php');
+$t->data['url'] = \SimpleSAML\Module::getModuleURL('negotiate/enable.php');
 $t->show();
diff --git a/modules/negotiate/www/enable.php b/modules/negotiate/www/enable.php
index 04c5e16ffc17c2a40fa5a3849e836b3d3efa8a73..be52928db4be463d68b030e0cf07d0fbb8a8a26c 100644
--- a/modules/negotiate/www/enable.php
+++ b/modules/negotiate/www/enable.php
@@ -1,22 +1,19 @@
 <?php
-
 /**
- *
- *
  * @author Mathias Meisfjordskar, University of Oslo.
  *         <mathias.meisfjordskar@usit.uio.no>
  * @package SimpleSAMLphp
  */
 
-$params = array(
-    'secure' => FALSE,
-    'httponly' => TRUE,
-);
-\SimpleSAML\Utils\HTTP::setCookie('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', NULL, $params, FALSE);
+$params = [
+    'secure' => false,
+    'httponly' => true,
+];
+\SimpleSAML\Utils\HTTP::setCookie('NEGOTIATE_AUTOLOGIN_DISABLE_PERMANENT', null, $params, false);
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
-$session->setData('negotiate:disable', 'session', FALSE, 24*60*60);
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'negotiate:enable.php');
-$t->data['url'] = SimpleSAML\Module::getModuleURL('negotiate/disable.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
+$session->setData('negotiate:disable', 'session', false, 86400); // 24*60*60=86400
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'negotiate:enable.php');
+$t->data['url'] = \SimpleSAML\Module::getModuleURL('negotiate/disable.php');
 $t->show();
diff --git a/modules/negotiate/www/retry.php b/modules/negotiate/www/retry.php
index a39b9596bd94597c3bca7542444ee9146e77e2f3..c4ffd87a52ee21a5553fcb6d5277f5a2066c1bbf 100644
--- a/modules/negotiate/www/retry.php
+++ b/modules/negotiate/www/retry.php
@@ -1,30 +1,34 @@
 <?php
 
 /**
- *
  *
  * @author Mathias Meisfjordskar, University of Oslo.
  *         <mathias.meisfjordskar@usit.uio.no>
  * @package SimpleSAMLphp
+ *
  */
 
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], sspmod_negotiate_Auth_Source_Negotiate::STAGEID);
+$state = \SimpleSAML\Auth\State::loadState(
+    $_REQUEST['AuthState'],
+    \SimpleSAML\Module\negotiate\Auth\Source\Negotiate::STAGEID
+);
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted', 'metaindex');
 $idpmeta = $metadata->getMetaData($idpid, 'saml20-idp-hosted');
 
 if (isset($idpmeta['auth'])) {
-	$source = SimpleSAML_Auth_Source::getById($idpmeta['auth']);
-	if ($source === NULL)
-		throw new SimpleSAML_Error_BadRequest('Invalid AuthId "' . $idpmeta['auth'] . '" - not found.');
+    $source = \SimpleSAML\Auth\Source::getById($idpmeta['auth']);
+    if ($source === null) {
+        throw new \SimpleSAML\Error\BadRequest('Invalid AuthId "'.$idpmeta['auth'].'" - not found.');
+    }
 
-	$session = SimpleSAML_Session::getSessionFromRequest();
-	$session->setData('negotiate:disable', 'session', FALSE, 24*60*60);
-	SimpleSAML\Logger::debug('Negotiate(retry) - session enabled, retrying.');
-	$source->authenticate($state);
-	assert(false);
+    $session = \SimpleSAML\Session::getSessionFromRequest();
+    $session->setData('negotiate:disable', 'session', false, 86400); //24*60*60=86400
+    \SimpleSAML\Logger::debug('Negotiate(retry) - session enabled, retrying.');
+    $source->authenticate($state);
+    assert(false);
 } else {
-	SimpleSAML\Logger::error('Negotiate - retry - no "auth" parameter found in IdP metadata.');
-	assert(false);
+    \SimpleSAML\Logger::error('Negotiate - retry - no "auth" parameter found in IdP metadata.');
+    assert(false);
 }
diff --git a/modules/oauth/config-template/module_oauth.php b/modules/oauth/config-template/module_oauth.php
index 41b46d5bbca70239df914227abdbc29110e1f9d9..63327d6be9a83f009b69908ec944ac9f025feb31 100644
--- a/modules/oauth/config-template/module_oauth.php
+++ b/modules/oauth/config-template/module_oauth.php
@@ -1,28 +1,24 @@
 <?php
-/* 
+/*
  * Configuration for the OAuth module.
- * 
+ *
  */
 
-$config = array (
+$config = [
+    /* Enable the getUserInfo endpoint. Do not enable unless you know what you do.
+     * It may give external parties access to userInfo unless properly secured.
+     */
+    'getUserInfo.enable' => true,
 
-	/* Enable the getUserInfo endpoint. Do not enable unless you know what you do.
-	 * It may give external parties access to userInfo unless properly secured.
-	 */
-	'getUserInfo.enable' => TRUE,
-	
-	'requestTokenDuration' => 60*30, // 30 minutes
-	'accessTokenDuration'  => 60*60*24, // 24 hours
-	'nonceCache'           => 60*60*24*14, // 14 days
+    'requestTokenDuration' => 60 * 30, // 30 minutes
+    'accessTokenDuration'  => 60 * 60 * 24, // 24 hours
+    'nonceCache'           => 60 * 60 * 24 * 14, // 14 days
 
+    // Tag to run storage cleanup script using the cron module...
+    'cron_tag' => 'hourly',
 
-	// Tag to run storage cleanup script using the cron module...
-	'cron_tag' => 'hourly',
-
-	// auth is the idp to use for admin authentication, 
-	// useridattr is the attribute-name that contains the userid as returned from idp
-	'auth' => 'default-sp',
-        'useridattr', 'user',
-
-);
-
+    // auth is the idp to use for admin authentication,
+    // useridattr is the attribute-name that contains the userid as returned from idp
+    'auth' => 'default-sp',
+    'useridattr', 'user',
+];
diff --git a/modules/oauth/hooks/hook_cron.php b/modules/oauth/hooks/hook_cron.php
index 182c51a692285b0035d338bcb3a83c5927c73c4a..1a37cb41d6e4777583b75d23cad64f509ed2fc87 100644
--- a/modules/oauth/hooks/hook_cron.php
+++ b/modules/oauth/hooks/hook_cron.php
@@ -1,29 +1,33 @@
 <?php
+
 /**
  * Hook to run a cron job.
  *
  * @param array &$croninfo  Output
  */
-function oauth_hook_cron(&$croninfo) {
-	assert(is_array($croninfo));
-	assert(array_key_exists('summary', $croninfo));
-	assert(array_key_exists('tag', $croninfo));
 
-	$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_statistics.php');
-	
-	if (is_null($oauthconfig->getValue('cron_tag', 'hourly'))) return;
-	if ($oauthconfig->getValue('cron_tag', NULL) !== $croninfo['tag']) return;
-	
-	try {
-		$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
-		$cleaned = $store->removeExpired();
-		
-#		if ($cleaned > 0) 
-			$croninfo['summary'][] = 'OAuth clean up. Removed ' . $cleaned . ' expired entries from OAuth storage.';
-		
-	} catch (Exception $e) {
-		$message = 'OAuth clean up cron script failed: ' . $e->getMessage();
-		SimpleSAML\Logger::warning($message);
-		$croninfo['summary'][] = $message;
-	}
+function oauth_hook_cron(&$croninfo)
+{
+    assert(is_array($croninfo));
+    assert(array_key_exists('summary', $croninfo));
+    assert(array_key_exists('tag', $croninfo));
+
+    $oauthconfig = \SimpleSAML\Configuration::getOptionalConfig('module_statistics.php');
+
+    if (is_null($oauthconfig->getValue('cron_tag', 'hourly'))) {
+        return;
+    }
+    if ($oauthconfig->getValue('cron_tag', null) !== $croninfo['tag']) {
+        return;
+    }
+
+    try {
+        $store = new \SimpleSAML\Module\core\Storage\SQLPermanentStorage('oauth');
+        $cleaned = $store->removeExpired();
+        $croninfo['summary'][] = 'OAuth clean up. Removed '.$cleaned.' expired entries from OAuth storage.';
+    } catch (\Exception $e) {
+        $message = 'OAuth clean up cron script failed: '.$e->getMessage();
+        \SimpleSAML\Logger::warning($message);
+        $croninfo['summary'][] = $message;
+    }
 }
diff --git a/modules/oauth/hooks/hook_frontpage.php b/modules/oauth/hooks/hook_frontpage.php
index 583ef5d6c06061ffb0caff4cf552cbb6b818118c..028e11c85d0750157741bb07f5b5cffe20ca6cbf 100644
--- a/modules/oauth/hooks/hook_frontpage.php
+++ b/modules/oauth/hooks/hook_frontpage.php
@@ -4,14 +4,13 @@
  *
  * @param array &$links  The links on the frontpage, split into sections.
  */
-function oauth_hook_frontpage(&$links) {
-	assert(is_array($links));
-	assert(array_key_exists('links', $links));
-
-	$links['federation']['oauthregistry'] = array(
-		'href' => SimpleSAML\Module::getModuleURL('oauth/registry.php'),
-		'text' => array('en' => 'OAuth Consumer Registry'),
-		'shorttext' => array('en' => 'OAuth Registry'),
-	);
+function oauth_hook_frontpage(&$links)
+{
+    assert(is_array($links));
+    assert(array_key_exists('links', $links));
 
+    $links['federation']['oauthregistry'] = [
+        'href' => SimpleSAML\Module::getModuleURL('oauth/registry.php'),
+        'text' => '{core:frontpage:link_oauth}',
+    ];
 }
diff --git a/modules/oauth/lib/Consumer.php b/modules/oauth/lib/Consumer.php
index 62644f739c35fd53b8358fc33f5b0ef8d8d46dcb..b3a4080ae6c384a48b3971fcc51c9354d1ac5f4d 100644
--- a/modules/oauth/lib/Consumer.php
+++ b/modules/oauth/lib/Consumer.php
@@ -1,6 +1,8 @@
 <?php
 
-require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
+namespace SimpleSAML\Module\oauth;
+
+require_once(dirname(dirname(__FILE__)).'/libextinc/OAuth.php');
 
 /**
  * OAuth Consumer
@@ -8,19 +10,22 @@ require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
  * @author Andreas Ă…kre Solberg, <andreas.solberg@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_oauth_Consumer
+
+class Consumer
 {
     private $consumer;
     private $signer;
 
     public function __construct($key, $secret)
     {
-        $this->consumer = new OAuthConsumer($key, $secret, null);
-        $this->signer = new OAuthSignatureMethod_HMAC_SHA1();
+        $this->consumer = new \OAuthConsumer($key, $secret, null);
+        $this->signer = new \OAuthSignatureMethod_HMAC_SHA1();
     }
 
     // Used only to load the libextinc library early
-    public static function dummy() {}
+    public static function dummy()
+    {
+    }
 
     public static function getOAuthError($hrh)
     {
@@ -46,37 +51,37 @@ class sspmod_oauth_Consumer
      * This static helper function wraps \SimpleSAML\Utils\HTTP::fetch
      * and throws an exception with diagnostics messages if it appear
      * to be failing on an OAuth endpoint.
-     * 
+     *
      * If the status code is not 200, an exception is thrown. If the content-type
-     * of the response if text/plain, the content of the response is included in 
+     * of the response if text/plain, the content of the response is included in
      * the text of the Exception thrown.
      */
     public static function getHTTP($url, $context = '')
     {
         try {
             $response = \SimpleSAML\Utils\HTTP::fetch($url);
-        } catch (\SimpleSAML_Error_Exception $e) {
+        } catch (\SimpleSAML\Error\Exception $e) {
             $statuscode = 'unknown';
             if (preg_match('/^HTTP.*\s([0-9]{3})/', $http_response_header[0], $matches)) {
                 $statuscode = $matches[1];
             }
 
-            $error = $context . ' [statuscode: ' . $statuscode . ']: ';
+            $error = $context.' [statuscode: '.$statuscode.']: ';
             $oautherror = self::getOAuthError($http_response_header);
 
             if (!empty($oautherror)) {
                 $error .= $oautherror;
             }
 
-            throw new Exception($error . ':' . $url);
-        } 
+            throw new \Exception($error.':'.$url);
+        }
         // Fall back to return response, if could not reckognize HTTP header. Should not happen.
         return $response;
     }
 
     public function getRequestToken($url, $parameters = null)
     {
-        $req_req = OAuthRequest::from_consumer_and_token($this->consumer, null, "GET", $url, $parameters);
+        $req_req = \OAuthRequest::from_consumer_and_token($this->consumer, null, "GET", $url, $parameters);
         $req_req->sign_request($this->signer, $this->consumer, null);
 
         $response_req = self::getHTTP(
@@ -87,18 +92,18 @@ class sspmod_oauth_Consumer
         parse_str($response_req, $responseParsed);
 
         if (array_key_exists('error', $responseParsed)) {
-            throw new Exception('Error getting request token: ' . $responseParsed['error']);
+            throw new \Exception('Error getting request token: '.$responseParsed['error']);
         }
 
         $requestToken = $responseParsed['oauth_token'];
         $requestTokenSecret = $responseParsed['oauth_token_secret'];
 
-        return new OAuthToken($requestToken, $requestTokenSecret);
+        return new \OAuthToken($requestToken, $requestTokenSecret);
     }
 
     public function getAuthorizeRequest($url, $requestToken, $redirect = true, $callback = null)
     {
-        $params = array('oauth_token' => $requestToken->key);
+        $params = ['oauth_token' => $requestToken->key];
         if ($callback) {
             $params['oauth_callback'] = $callback;
         }
@@ -106,73 +111,69 @@ class sspmod_oauth_Consumer
         if ($redirect) {
             \SimpleSAML\Utils\HTTP::redirectTrustedURL($authorizeURL);
             exit;
-        }	
+        }
         return $authorizeURL;
     }
 
     public function getAccessToken($url, $requestToken, $parameters = null)
     {
-        $acc_req = OAuthRequest::from_consumer_and_token($this->consumer, $requestToken, "GET", $url, $parameters);
+        $acc_req = \OAuthRequest::from_consumer_and_token($this->consumer, $requestToken, "GET", $url, $parameters);
         $acc_req->sign_request($this->signer, $this->consumer, $requestToken);
 
         try {
             $response_acc = \SimpleSAML\Utils\HTTP::fetch($acc_req->to_url());
-        } catch (\SimpleSAML_Error_Exception $e) {
-            throw new Exception('Error contacting request_token endpoint on the OAuth Provider');
+        } catch (\SimpleSAML\Error\Exception $e) {
+            throw new \Exception('Error contacting request_token endpoint on the OAuth Provider');
         }
 
-        SimpleSAML\Logger::debug('oauth: Reponse to get access token: '. $response_acc);
+        \SimpleSAML\Logger::debug('oauth: Reponse to get access token: '.$response_acc);
 
         parse_str($response_acc, $accessResponseParsed);
 
         if (array_key_exists('error', $accessResponseParsed)) {
-            throw new Exception('Error getting request token: ' . $accessResponseParsed['error']);
+            throw new \Exception('Error getting request token: '.$accessResponseParsed['error']);
         }
 
         $accessToken = $accessResponseParsed['oauth_token'];
         $accessTokenSecret = $accessResponseParsed['oauth_token_secret'];
 
-        return new OAuthToken($accessToken, $accessTokenSecret);
+        return new \OAuthToken($accessToken, $accessTokenSecret);
     }
 
     public function postRequest($url, $accessToken, $parameters)
     {
-        $data_req = OAuthRequest::from_consumer_and_token($this->consumer, $accessToken, "POST", $url, $parameters);
+        $data_req = \OAuthRequest::from_consumer_and_token($this->consumer, $accessToken, "POST", $url, $parameters);
         $data_req->sign_request($this->signer, $this->consumer, $accessToken);
         $postdata = $data_req->to_postdata();
 
-        $opts = array(
-            'ssl' => array(
+        $opts = [
+            'ssl' => [
                 'verify_peer' => false,
                 'capture_peer_cert' => true,
                 'capture_peer_chain' => true
-            ),
-            'http' => array(
+            ],
+            'http' => [
                 'method' => 'POST',
                 'content' => $postdata,
                 'header' => 'Content-Type: application/x-www-form-urlencoded',
-            ),
-        );
+            ],
+        ];
 
         try {
             $response = \SimpleSAML\Utils\HTTP::fetch($url, $opts);
-        } catch (\SimpleSAML_Error_Exception $e) {
-            throw new SimpleSAML_Error_Exception('Failed to push definition file to ' . $url);
+        } catch (\SimpleSAML\Error\Exception $e) {
+            throw new \SimpleSAML\Error\Exception('Failed to push definition file to '.$url);
         }
         return $response;
     }
 
     public function getUserInfo($url, $accessToken, $opts = null)
     {
-        $data_req = OAuthRequest::from_consumer_and_token($this->consumer, $accessToken, "GET", $url, null);
+        $data_req = \OAuthRequest::from_consumer_and_token($this->consumer, $accessToken, "GET", $url, null);
         $data_req->sign_request($this->signer, $this->consumer, $accessToken);
 
-        if (is_array($opts)) {
-            $opts = stream_context_create($opts);
-        }
         $data = \SimpleSAML\Utils\HTTP::fetch($data_req->to_url(), $opts);
 
         return  json_decode($data, true);
     }
 }
-
diff --git a/modules/oauth/lib/OAuthServer.php b/modules/oauth/lib/OAuthServer.php
index 03d04fe30e355052acbc863b4b707d3f656424de..b6607e6feb6bfeb4372dd1c50462295f6325821d 100644
--- a/modules/oauth/lib/OAuthServer.php
+++ b/modules/oauth/lib/OAuthServer.php
@@ -1,6 +1,8 @@
 <?php
 
-require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
+namespace SimpleSAML\Module\oauth;
+
+require_once(dirname(dirname(__FILE__)).'/libextinc/OAuth.php');
 
 /**
  * OAuth Provider implementation..
@@ -8,9 +10,16 @@ require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
  * @author Andreas Ă…kre Solberg, <andreas.solberg@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_oauth_OAuthServer extends OAuthServer {
-	public function get_signature_methods() {
-		return $this->signature_methods;
-	}
-}
 
+class OAuthServer extends OAuthServer
+{
+    public function __construct($store)
+    {
+        parent::__construct($store);
+    }
+
+    public function get_signature_methods()
+    {
+        return $this->signature_methods;
+    }
+}
diff --git a/modules/oauth/lib/OAuthStore.php b/modules/oauth/lib/OAuthStore.php
index 3b9ec1afac68493a7c66ac10daa7199847e33490..b0c9d222dd5176dd343878a774309676bf03eb2c 100644
--- a/modules/oauth/lib/OAuthStore.php
+++ b/modules/oauth/lib/OAuthStore.php
@@ -1,180 +1,213 @@
 <?php
-require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
+
+namespace SimpleSAML\Module\oauth;
+
+require_once(dirname(dirname(__FILE__)).'/libextinc/OAuth.php');
 
 /**
  * OAuth Store
- * 
- * Updated version, works with consumer-callbacks, certificates and 1.0-RevA protocol 
+ *
+ * Updated version, works with consumer-callbacks, certificates and 1.0-RevA protocol
  * behaviour (requestToken-callbacks and verifiers)
  *
  * @author Andreas Ă…kre Solberg, <andreas.solberg@uninett.no>, UNINETT AS.
  * @author Mark Dobrinic, <mdobrinic@cozmanova.com>, Cozmanova bv
  * @package SimpleSAMLphp
  */
-class sspmod_oauth_OAuthStore extends OAuthDataStore {
-
-	private $store;
-	private $config;
-	private $defaultversion = '1.0';
-
-	protected $_store_tables = array(
-					'consumers' => 'consumer = array with consumer attributes', 
-					'nonce' => 'nonce+consumer_key = -boolean-',
-					'requesttorequest' => 'requestToken.key = array(version,callback,consumerKey,)',
-					'authorized' => 'requestToken.key, verifier = array(authenticated-user-attributes)',
-					'access' => 'accessToken.key+consumerKey = accestoken',
-					'request' => 'requestToken.key+consumerKey = requesttoken',
-				);
-				
-    function __construct() {
-		$this->store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
-		$this->config = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
+
+class OAuthStore extends \OAuthDataStore
+{
+    private $store;
+    private $config;
+    private $defaultversion = '1.0';
+
+    protected $_store_tables = [
+        'consumers' => 'consumer = array with consumer attributes',
+        'nonce' => 'nonce+consumer_key = -boolean-',
+        'requesttorequest' => 'requestToken.key = array(version,callback,consumerKey,)',
+        'authorized' => 'requestToken.key, verifier = array(authenticated-user-attributes)',
+        'access' => 'accessToken.key+consumerKey = accesstoken',
+        'request' => 'requestToken.key+consumerKey = requesttoken',
+    ];
+
+
+    public function __construct()
+    {
+        $this->store = new \SimpleSAML\Module\core\Storage\SQLPermanentStorage('oauth');
+        $this->config = \SimpleSAML\Configuration::getOptionalConfig('module_oauth.php');
     }
-	
-    
+
+
     /**
      * Attach the data to the token, and establish the Callback URL and verifier
-     * @param $requestTokenKey RequestToken that was authorized
-     * @param $data Data that is authorized and to be attached to the requestToken
+     * @param string $requestTokenKey RequestToken that was authorized
+     * @param string $data Data that is authorized and to be attached to the requestToken
      * @return array(string:url, string:verifier) ; empty verifier for 1.0-response
      */
-	public function authorize($requestTokenKey, $data) {
-		$url = null;
-		
-		// See whether to remember values from the original requestToken request:
-		$request_attributes = $this->store->get('requesttorequest', $requestTokenKey, '');	// must be there ..
-		if ($request_attributes['value']) {
-			// establish callback to use
-			if ($request_attributes['value']['callback']) {
-				$url = $request_attributes['value']['callback'];
-			}
-		}
-		
-		
-		// Is there a callback registered? This is leading, even over a supplied oauth_callback-parameter
-		$oConsumer = $this->lookup_consumer($request_attributes['value']['consumerKey']);
-		
-		if ($oConsumer && ($oConsumer->callback_url)) $url = $oConsumer->callback_url;
-		
-		$verifier = SimpleSAML\Utils\Random::generateID();
-		$url = \SimpleSAML\Utils\HTTP::addURLParameters($url, array("oauth_verifier"=>$verifier));
-		
-		$this->store->set('authorized', $requestTokenKey, $verifier, $data, $this->config->getValue('requestTokenDuration', 60*30) );
-		
-		return array($url, $verifier);
-	}
-	
-	/**
-	 * Perform lookup whether a given token exists in the list of authorized tokens; if a verifier is
-	 * passed as well, the verifier *must* match the verifier that was registered with the token<br/>
-	 * Note that an accessToken should never be stored with a verifier
-	 * @param $requestToken
-	 * @param $verifier
-	 * @return unknown_type
-	 */
-	public function isAuthorized($requestToken, $verifier='') {
-		SimpleSAML\Logger::info('OAuth isAuthorized(' . $requestToken . ')');
-		return $this->store->exists('authorized', $requestToken, $verifier);
-	}
-	
-	public function getAuthorizedData($token, $verifier = '') {
-		SimpleSAML\Logger::info('OAuth getAuthorizedData(' . $token . ')');
-		$data = $this->store->get('authorized', $token, $verifier);
-		return $data['value'];
-	}
-	
-	public function moveAuthorizedData($requestToken, $verifier, $accessTokenKey) {
-		SimpleSAML\Logger::info('OAuth moveAuthorizedData(' . $requestToken . ', ' . $accessTokenKey . ')');
-
-		// Retrieve authorizedData from authorized.requestToken (with provider verifier)
-		$authorizedData = $this->getAuthorizedData($requestToken, $verifier);
-		
-		// Remove the requesttoken+verifier from authorized store
-		$this->store->remove('authorized', $requestToken, $verifier);
-		
-		// Add accesstoken with authorizedData to authorized store (with empty verifier)
-		// accessTokenKey+consumer => accessToken is already registered in 'access'-table
-		$this->store->set('authorized', $accessTokenKey, '', $authorizedData, $this->config->getValue('accessTokenDuration', 60*60*24));
-	}
-	
-    public function lookup_consumer($consumer_key) {
-		SimpleSAML\Logger::info('OAuth lookup_consumer(' . $consumer_key . ')');
-		if (! $this->store->exists('consumers', $consumer_key, ''))  return NULL;
-		$consumer = $this->store->get('consumers', $consumer_key, '');
-		
-		$callback = NULL;
-		if ($consumer['value']['callback_url']) $callback = $consumer['value']['callback_url'];
-
-		if ($consumer['value']['RSAcertificate']) {
-			return new OAuthConsumer($consumer['value']['key'], $consumer['value']['RSAcertificate'], $callback);
-		} else {
-			return new OAuthConsumer($consumer['value']['key'], $consumer['value']['secret'], $callback);
-		}
+    public function authorize($requestTokenKey, $data)
+    {
+        $url = null;
+
+        // See whether to remember values from the original requestToken request:
+        $request_attributes = $this->store->get('requesttorequest', $requestTokenKey, '');
+        // must be there
+        if ($request_attributes['value']) {
+            // establish callback to use
+            if ($request_attributes['value']['callback']) {
+                $url = $request_attributes['value']['callback'];
+            }
+        }
+
+        // Is there a callback registered? This is leading, even over a supplied oauth_callback-parameter
+        $oConsumer = $this->lookup_consumer($request_attributes['value']['consumerKey']);
+
+        if ($oConsumer && ($oConsumer->callback_url)) {
+            $url = $oConsumer->callback_url;
+        }
+
+        $verifier = \SimpleSAML\Utils\Random::generateID();
+        $url = \SimpleSAML\Utils\HTTP::addURLParameters($url, ["oauth_verifier"=>$verifier]);
+
+        $this->store->set('authorized', $requestTokenKey, $verifier, $data, $this->config->getValue('requestTokenDuration', 1800)); //60*30=1800
+
+        return [$url, $verifier];
+    }
+
+    /**
+     * Perform lookup whether a given token exists in the list of authorized tokens; if a verifier is
+     * passed as well, the verifier *must* match the verifier that was registered with the token<br/>
+     * Note that an accessToken should never be stored with a verifier
+     * @param string $requestToken
+     * @param string $verifier
+     * @return bool
+     */
+    public function isAuthorized($requestToken, $verifier = '')
+    {
+        \SimpleSAML\Logger::info('OAuth isAuthorized('.$requestToken.')');
+        return $this->store->exists('authorized', $requestToken, $verifier);
     }
 
-    function lookup_token($consumer, $tokenType = 'default', $token) {
-		SimpleSAML\Logger::info('OAuth lookup_token(' . $consumer->key . ', ' . $tokenType. ',' . $token . ')');
-		$data = $this->store->get($tokenType, $token, $consumer->key);
-		if ($data == NULL) throw new Exception('Could not find token');
-		return $data['value'];
+    public function getAuthorizedData($token, $verifier = '')
+    {
+        \SimpleSAML\Logger::info('OAuth getAuthorizedData('.$token.')');
+        $data = $this->store->get('authorized', $token, $verifier);
+        return $data['value'];
     }
 
-    function lookup_nonce($consumer, $token, $nonce, $timestamp) {
-		SimpleSAML\Logger::info('OAuth lookup_nonce(' . $consumer . ', ' . $token. ',' . $nonce . ')');
-		if ($this->store->exists('nonce', $nonce, $consumer->key))  return TRUE;
-		$this->store->set('nonce', $nonce, $consumer->key, TRUE, $this->config->getValue('nonceCache', 60*60*24*14));
-		return FALSE;
+    public function moveAuthorizedData($requestToken, $verifier, $accessTokenKey)
+    {
+        \SimpleSAML\Logger::info('OAuth moveAuthorizedData('.$requestToken.', '.$accessTokenKey.')');
+
+        // Retrieve authorizedData from authorized.requestToken (with provider verifier)
+        $authorizedData = $this->getAuthorizedData($requestToken, $verifier);
+
+        // Remove the requesttoken+verifier from authorized store
+        $this->store->remove('authorized', $requestToken, $verifier);
+
+        // Add accesstoken with authorizedData to authorized store (with empty verifier)
+        // accessTokenKey+consumer => accessToken is already registered in 'access'-table
+        $this->store->set('authorized', $accessTokenKey, '', $authorizedData, $this->config->getValue('accessTokenDuration', 86400)); //60*60*24=86400
+    }
+
+    public function lookup_consumer($consumer_key)
+    {
+        \SimpleSAML\Logger::info('OAuth lookup_consumer('.$consumer_key.')');
+        if (!$this->store->exists('consumers', $consumer_key, '')) {
+            return null;
+        }
+        $consumer = $this->store->get('consumers', $consumer_key, '');
+
+        $callback = null;
+        if ($consumer['value']['callback_url']) {
+            $callback = $consumer['value']['callback_url'];
+        }
+
+        if ($consumer['value']['RSAcertificate']) {
+            return new \OAuthConsumer($consumer['value']['key'], $consumer['value']['RSAcertificate'], $callback);
+        } else {
+            return new \OAuthConsumer($consumer['value']['key'], $consumer['value']['secret'], $callback);
+        }
     }
 
-    function new_request_token($consumer, $callback = null, $version = null) {
-		SimpleSAML\Logger::info('OAuth new_request_token(' . $consumer . ')');
-		
-		$lifetime = $this->config->getValue('requestTokenDuration', 60*30); 
-		
-		$token = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID());
-		$token->callback = $callback;	// OAuth1.0-RevA
-		$this->store->set('request', $token->key, $consumer->key, $token, $lifetime);
-		
-		// also store in requestToken->key => array('callback'=>CallbackURL, 'version'=>oauth_version
-		$request_attributes = array(
-				'callback' => $callback, 
-				'version' => ($version?$version:$this->defaultversion),
-				'consumerKey' => $consumer->key,
-			);
-		$this->store->set('requesttorequest', $token->key, '', $request_attributes, $lifetime);
-		
-		// also store in requestToken->key => Consumer->key (enables consumer-lookup during reqToken-authorization stage)
-		$this->store->set('requesttoconsumer', $token->key, '', $consumer->key, $lifetime);
-		
+    public function lookup_token($consumer, $tokenType = 'default', $token)
+    {
+        \SimpleSAML\Logger::info('OAuth lookup_token('.$consumer->key.', '.$tokenType.','.$token.')');
+        $data = $this->store->get($tokenType, $token, $consumer->key);
+        if ($data == null) {
+            throw new \Exception('Could not find token');
+        }
+        return $data['value'];
+    }
+
+    public function lookup_nonce($consumer, $token, $nonce, $timestamp)
+    {
+        \SimpleSAML\Logger::info('OAuth lookup_nonce('.$consumer.', '.$token.','.$nonce.')');
+        if ($this->store->exists('nonce', $nonce, $consumer->key)) {
+            return true;
+        }
+        $this->store->set('nonce', $nonce, $consumer->key, true, $this->config->getValue('nonceCache', 1209600)); //60*60*24*14=1209600
+        return false;
+    }
+
+    public function new_request_token($consumer, $callback = null, $version = null)
+    {
+        \SimpleSAML\Logger::info('OAuth new_request_token('.$consumer.')');
+
+        $lifetime = $this->config->getValue('requestTokenDuration', 1800); //60*30
+
+        $token = new \OAuthToken(\SimpleSAML\Utils\Random::generateID(), \SimpleSAML\Utils\Random::generateID());
+        $token->callback = $callback; // OAuth1.0-RevA
+        $this->store->set('request', $token->key, $consumer->key, $token, $lifetime);
+
+        // also store in requestToken->key => array('callback'=>CallbackURL, 'version'=>oauth_version
+        $request_attributes = [
+            'callback' => $callback,
+            'version' => ($version ? $version : $this->defaultversion),
+            'consumerKey' => $consumer->key,
+        ];
+        $this->store->set('requesttorequest', $token->key, '', $request_attributes, $lifetime);
+
+        /* also store in requestToken->key =>
+         * Consumer->key (enables consumer-lookup during reqToken-authorization stage)
+         */
+        $this->store->set('requesttoconsumer', $token->key, '', $consumer->key, $lifetime);
+
         return $token;
     }
 
-    function new_access_token($requestToken, $consumer, $verifier = null) {
-		SimpleSAML\Logger::info('OAuth new_access_token(' . $requestToken . ',' . $consumer . ')');
-		$accestoken = new OAuthToken(SimpleSAML\Utils\Random::generateID(), SimpleSAML\Utils\Random::generateID());
-		$this->store->set('access', $accestoken->key, $consumer->key, $accestoken, $this->config->getValue('accessTokenDuration', 60*60*24) );
-        return $accestoken;
+    public function new_access_token($requestToken, $consumer, $verifier = null)
+    {
+        \SimpleSAML\Logger::info('OAuth new_access_token('.$requestToken.','.$consumer.')');
+        $accesstoken = new \OAuthToken(\SimpleSAML\Utils\Random::generateID(), \SimpleSAML\Utils\Random::generateID());
+        $this->store->set(
+            'access',
+            $accesstoken->key,
+            $consumer->key,
+            $accesstoken,
+            $this->config->getValue('accessTokenDuration', 86400) //60*60*24=86400
+        );
+        return $accesstoken;
     }
-    
+
     /**
      * Return OAuthConsumer-instance that a given requestToken was issued to
-     * @param $requestTokenKey
-     * @return unknown_type
+     * @param string $requestTokenKey
+     * @return mixed
      */
-    public function lookup_consumer_by_requestToken($requestTokenKey) {
-		SimpleSAML\Logger::info('OAuth lookup_consumer_by_requestToken(' . $requestTokenKey . ')');
-		if (! $this->store->exists('requesttorequest', $requestTokenKey, '')) return NULL;
-		
-		$request = $this->store->get('requesttorequest', $requestTokenKey, '');
-		$consumerKey = $request['value']['consumerKey'];
-		if (! $consumerKey) {
-			return NULL;
-		}
-		
-		$consumer = $this->store->get('consumers', $consumerKey['value'], '');
-		return $consumer['value'];
-	}
-	
-    
+    public function lookup_consumer_by_requestToken($requestTokenKey)
+    {
+        \SimpleSAML\Logger::info('OAuth lookup_consumer_by_requestToken('.$requestTokenKey.')');
+        if (!$this->store->exists('requesttorequest', $requestTokenKey, '')) {
+            return null;
+        }
 
+        $request = $this->store->get('requesttorequest', $requestTokenKey, '');
+        $consumerKey = $request['value']['consumerKey'];
+        if (!$consumerKey) {
+            return null;
+        }
+
+        $consumer = $this->store->get('consumers', $consumerKey['value'], '');
+        return $consumer['value'];
+    }
 }
diff --git a/modules/oauth/lib/Registry.php b/modules/oauth/lib/Registry.php
index b2bc33bb9c8debb74e456bae2683b069839bd95b..0939be6f410ce90c587c388c7ffa15e7cbc89c12 100644
--- a/modules/oauth/lib/Registry.php
+++ b/modules/oauth/lib/Registry.php
@@ -1,133 +1,151 @@
 <?php
 
+namespace SimpleSAML\Module\oauth;
+
 /**
  * Editor for OAuth Client Registry
  *
  * @author Andreas Ă…kre Solberg <andreas@uninett.no>, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_oauth_Registry {
-
-
-	protected function getStandardField($request, &$entry, $key) {
-		if (array_key_exists('field_' . $key, $request)) {
-			$entry[$key] = $request['field_' . $key];
-		} else {
-			if (isset($entry[$key])) unset($entry[$key]);
-		}
-	}
-
-	public function formToMeta($request, $entry = array(), $override = NULL) {
-		$this->getStandardField($request, $entry, 'name');
-		$this->getStandardField($request, $entry, 'description');
-		$this->getStandardField($request, $entry, 'key');
-		$this->getStandardField($request, $entry, 'secret');
-		$this->getStandardField($request, $entry, 'RSAcertificate');
-		$this->getStandardField($request, $entry, 'callback_url');
-
-		if ($override) {
-			foreach($override AS $key => $value) {
-				$entry[$key] = $value;
-			}
-		}
-		
-		return $entry;
-	}
-
-	protected function requireStandardField($request, $key) {
-		if (!array_key_exists('field_' . $key, $request))
-			throw new Exception('Required field [' . $key . '] was missing.');
-		if (empty($request['field_' . $key]))
-			throw new Exception('Required field [' . $key . '] was empty.');
-	}
-
-	public function checkForm($request) {
-		$this->requireStandardField($request, 'name');
-		$this->requireStandardField($request, 'description');
-		$this->requireStandardField($request, 'key');
-	}
-	
-
-	protected function header($name) {
-		return '<tr ><td>&nbsp;</td><td class="header">' . $name . '</td></tr>';
-		
-	}
-	
-	protected function readonlyDateField($metadata, $key, $name) {
-		$value = '<span style="color: #aaa">Not set</a>';
-		if (array_key_exists($key, $metadata))
-			$value = date('j. F Y, G:i', $metadata[$key]);
-		return '<tr>
-			<td class="name">' . $name . '</td>
-			<td class="data">' . $value . '</td></tr>';
-
-	}
-	
-	protected function readonlyField($metadata, $key, $name) {
-		$value = '';
-		if (array_key_exists($key, $metadata))
-			$value = $metadata[$key];
-		return '<tr>
-			<td class="name">' . $name . '</td>
-			<td class="data">' . htmlspecialchars($value) . '</td></tr>';
-
-	}
-	
-	protected function hiddenField($key, $value) {
-		return '<input type="hidden" name="' . $key . '" value="' . htmlspecialchars($value) . '" />';
-	}
-	
-	protected function flattenLanguageField(&$metadata, $key) {
-		if (array_key_exists($key, $metadata)) {
-			if (is_array($metadata[$key])) {
-				if (isset($metadata[$key]['en'])) {
-					$metadata[$key] = $metadata[$key]['en'];
-				} else {
-					unset($metadata[$key]);
-				}
-			}
-		}
-	}
-	
-	protected function standardField($metadata, $key, $name, $textarea = FALSE) {
-		$value = '';
-		if (array_key_exists($key, $metadata)) {
-			$value = htmlspecialchars($metadata[$key]);
-		}
-		
-		if ($textarea) {
-			return '<tr><td class="name">' . $name . '</td><td class="data">
-			<textarea name="field_' . $key . '" rows="5" cols="50">' . $value . '</textarea></td></tr>';
-			
-		} else {
-			return '<tr><td class="name">' . $name . '</td><td class="data">
-			<input type="text" size="60" name="field_' . $key . '" value="' . $value . '" /></td></tr>';
-			
-		}
-	}
-
-	public function metaToForm($metadata) {
-		return '<form action="registry.edit.php" method="post">' .
-			'<div id="tabdiv">' .
-			'<ul>' .
-			'<li><a href="#basic">Name and descrition</a></li>' .
-			'</ul>' .
-			'<div id="basic"><table class="formtable">' .
-				$this->standardField($metadata, 'name', 'Name of client') .
-				$this->standardField($metadata, 'description', 'Description of client', TRUE) .
-				$this->readonlyField($metadata, 'owner', 'Owner') .
-				$this->standardField($metadata, 'key', 'Consumer Key') .
-				$this->readonlyField($metadata, 'secret', 'Consumer Secret<br/>(Used for HMAC_SHA1 signatures)') .
-				$this->standardField($metadata, 'RSAcertificate', 'RSA certificate (PEM)<br/>(Used for RSA_SHA1 signatures)', TRUE) .
-				$this->standardField($metadata, 'callback_url', 'Static/enforcing callback-url') .
-				$this->hiddenField('field_secret', $metadata['secret']) .
-
-			'</table></div>' .
-			'</div>' .
-			'<input type="submit" name="submit" value="Save" style="margin-top: 5px" />' .
-		'</form>';
-	}
-	
-}
 
+class Registry
+{
+    public static function requireOwnership($entry, $userid)
+    {
+        if (!isset($entry['owner'])) {
+            throw new \Exception('OAuth Consumer has no owner. Which means no one is granted access, not even you.');
+        } elseif ($entry['owner'] !== $userid) {
+            throw new \Exception(
+                'OAuth Consumer has an owner that is not equal to your userid, hence you are not granted access.'
+            );
+        }
+    }
+
+    protected function getStandardField($request, &$entry, $key)
+    {
+        if (array_key_exists('field_'.$key, $request)) {
+            $entry[$key] = $request['field_'.$key];
+        } elseif (isset($entry[$key])) {
+            unset($entry[$key]);
+        }
+    }
+
+    public function formToMeta($request, $entry = [], $override = null)
+    {
+        $this->getStandardField($request, $entry, 'name');
+        $this->getStandardField($request, $entry, 'description');
+        $this->getStandardField($request, $entry, 'key');
+        $this->getStandardField($request, $entry, 'secret');
+        $this->getStandardField($request, $entry, 'RSAcertificate');
+        $this->getStandardField($request, $entry, 'callback_url');
+
+        if ($override) {
+            foreach ($override as $key => $value) {
+                $entry[$key] = $value;
+            }
+        }
+        return $entry;
+    }
+
+    protected function requireStandardField($request, $key)
+    {
+        if (!array_key_exists('field_'.$key, $request)) {
+            throw new \Exception('Required field ['.$key.'] was missing.');
+        }
+        if (empty($request['field_'.$key])) {
+            throw new \Exception('Required field ['.$key.'] was empty.');
+        }
+    }
+
+    public function checkForm($request)
+    {
+        $this->requireStandardField($request, 'name');
+        $this->requireStandardField($request, 'description');
+        $this->requireStandardField($request, 'key');
+    }
+
+    protected function header($name)
+    {
+        return '<tr><td>&nbsp;</td><td class="header">'.$name.'</td></tr>';
+    }
 
+    protected function readonlyDateField($metadata, $key, $name)
+    {
+        $value = '<span style="color: #aaa">Not set</a>';
+        if (array_key_exists($key, $metadata)) {
+            $value = date('j. F Y, G:i', $metadata[$key]);
+        }
+        return '<tr><td class="name">'.$name.'</td><td class="data">'.$value.'</td></tr>';
+    }
+
+    protected function readonlyField($metadata, $key, $name)
+    {
+        $value = '';
+        if (array_key_exists($key, $metadata)) {
+            $value = $metadata[$key];
+        }
+        return '<tr><td class="name">'.$name.'</td><td class="data">'.htmlspecialchars($value).'</td></tr>';
+    }
+
+    protected function hiddenField($key, $value)
+    {
+        return '<input type="hidden" name="'.$key.'" value="'.htmlspecialchars($value).'" />';
+    }
+
+    protected function flattenLanguageField(&$metadata, $key)
+    {
+        if (array_key_exists($key, $metadata)) {
+            if (is_array($metadata[$key])) {
+                if (isset($metadata[$key]['en'])) {
+                    $metadata[$key] = $metadata[$key]['en'];
+                } else {
+                    unset($metadata[$key]);
+                }
+            }
+        }
+    }
+
+    protected function standardField($metadata, $key, $name, $textarea = false)
+    {
+        $value = '';
+        if (array_key_exists($key, $metadata)) {
+            $value = htmlspecialchars($metadata[$key]);
+        }
+
+        if ($textarea) {
+            return '<tr><td class="name">'.$name.'</td><td class="data">
+                <textarea name="field_'.$key.'" rows="5" cols="50">'.$value.'</textarea></td></tr>';
+        } else {
+            return '<tr><td class="name">'.$name.'</td><td class="data">
+                <input type="text" size="60" name="field_'.$key.'" value="'.$value.'" /></td></tr>';
+        }
+    }
+
+    public function metaToForm($metadata)
+    {
+        return '<form action="registry.edit.php" method="post">'.
+            '<div id="tabdiv">'.
+            '<ul class="tabset_tabs">'.
+            '<li class="tab-link current" data-tab="basic"><a href="#basic">Name and description</a></li>'.
+            '</ul>'.
+            '<div id="basic" class="tabset_content current"><table class="formtable">'.
+                $this->standardField($metadata, 'name', 'Name of client').
+                $this->standardField($metadata, 'description', 'Description of client', true).
+                $this->readonlyField($metadata, 'owner', 'Owner').
+                $this->standardField($metadata, 'key', 'Consumer Key').
+                $this->readonlyField($metadata, 'secret', 'Consumer Secret<br />(Used for HMAC_SHA1 signatures)').
+                $this->standardField(
+                    $metadata,
+                    'RSAcertificate',
+                    'RSA certificate (PEM)<br />(Used for RSA_SHA1 signatures)',
+                    true
+                ).
+                $this->standardField($metadata, 'callback_url', 'Static/enforcing callback-url').
+            '</table></div>'.
+            '</div>'.
+            $this->hiddenField('field_secret', $metadata['secret']).
+            '<input type="submit" name="submit" value="Save" style="margin-top: 5px" />'.
+            '</form>';
+    }
+}
diff --git a/modules/oauth/libextinc/OAuth.php b/modules/oauth/libextinc/OAuth.php
index acaf4360d41c1a754c36fc25eeb04ba81bcf9dec..c8811d6ce1263032e6fe32c9227546a5014ad945 100644
--- a/modules/oauth/libextinc/OAuth.php
+++ b/modules/oauth/libextinc/OAuth.php
@@ -12,18 +12,20 @@ if (!class_exists('OAuthException')) {
     /*
      * Generic exception class
      */
-    class OAuthException extends Exception {
+    class OAuthException extends Exception
+    {
         // pass
     }
 }
 
 if (!class_exists('OAuthConsumer')) {
-    class OAuthConsumer {
+    class OAuthConsumer
+    {
         public $key;
         public $secret;
         public $callback_url;
 
-        public function __construct($key, $secret, $callback_url=null)
+        public function __construct($key, $secret, $callback_url = null)
         {
             $this->key = $key;
             $this->secret = $secret;
@@ -37,7 +39,8 @@ if (!class_exists('OAuthConsumer')) {
     }
 }
 
-class OAuthToken {
+class OAuthToken
+{
     // access tokens and request tokens
     public $key;
     public $secret;
@@ -58,14 +61,15 @@ class OAuthToken {
      */
     public function to_string()
     {
-        return "oauth_token=" .
-        OAuthUtil::urlencode_rfc3986($this->key) .
-        "&oauth_token_secret=" .
-        OAuthUtil::urlencode_rfc3986($this->secret) .
+        return "oauth_token=".
+        OAuthUtil::urlencode_rfc3986($this->key).
+        "&oauth_token_secret=".
+        OAuthUtil::urlencode_rfc3986($this->secret).
         "&oauth_callback_confirmed=true";
     }
 
-    function __toString() {
+    public function __toString()
+    {
         return $this->to_string();
     }
 }
@@ -134,7 +138,7 @@ abstract class OAuthSignatureMethod
  */
 class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
 {
-    function get_name()
+    public function get_name()
     {
         return "HMAC-SHA1";
     }
@@ -144,10 +148,10 @@ class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod
         $base_string = $request->get_signature_base_string();
         $request->base_string = $base_string;
 
-        $key_parts = array(
+        $key_parts = [
             $consumer->secret,
             ($token) ? $token->secret : ""
-        );
+        ];
 
         $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
         $key = implode('&', $key_parts);
@@ -179,10 +183,10 @@ class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod
      */
     public function build_signature($request, $consumer, $token)
     {
-        $key_parts = array(
+        $key_parts = [
             $consumer->secret,
             ($token) ? $token->secret : ""
-        );
+        ];
 
         $key_parts = OAuthUtil::urlencode_rfc3986($key_parts);
         $key = implode('&', $key_parts);
@@ -273,9 +277,9 @@ class OAuthRequest
     public static $version = '1.0';
     public static $POST_INPUT = 'php://input';
 
-    public function __construct($http_method, $http_url, $parameters=null)
+    public function __construct($http_method, $http_url, $parameters = null)
     {
-        $parameters = ($parameters) ? $parameters : array();
+        $parameters = ($parameters) ? $parameters : [];
         $parameters = array_merge(OAuthUtil::parse_parameters(parse_url($http_url, PHP_URL_QUERY)), $parameters);
         $this->parameters = $parameters;
         $this->http_method = $http_method;
@@ -286,15 +290,15 @@ class OAuthRequest
     /**
      * attempt to build up a request from what was passed to the server
      */
-    public static function from_request($http_method=NULL, $http_url=null, $parameters=null)
+    public static function from_request($http_method = null, $http_url = null, $parameters = null)
     {
         $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
             ? 'http'
             : 'https';
-        $http_url = ($http_url) ? $http_url : $scheme .
-            '://' . $_SERVER['SERVER_NAME'] .
-            ':' .
-            $_SERVER['SERVER_PORT'] .
+        $http_url = ($http_url) ? $http_url : $scheme.
+            '://'.$_SERVER['SERVER_NAME'].
+            ':'.
+            $_SERVER['SERVER_PORT'].
             $_SERVER['REQUEST_URI'];
         $http_method = ($http_method) ? $http_method : $_SERVER['REQUEST_METHOD'];
 
@@ -312,9 +316,8 @@ class OAuthRequest
             // It's a POST request of the proper content-type, so parse POST
             // parameters and add those overriding any duplicates from GET
             if ($http_method == "POST"
-                &&  isset($request_headers['Content-Type'])
-                && strstr($request_headers['Content-Type'],
-                    'application/x-www-form-urlencoded')
+                && isset($request_headers['Content-Type'])
+                && strstr($request_headers['Content-Type'], 'application/x-www-form-urlencoded')
             ) {
                 $post_data = OAuthUtil::parse_parameters(
                     file_get_contents(self::$POST_INPUT)
@@ -324,13 +327,14 @@ class OAuthRequest
 
             // We have a Authorization-header with OAuth data. Parse the header
             // and add those overriding any duplicates from GET or POST
-            if (isset($request_headers['Authorization']) && substr($request_headers['Authorization'], 0, 6) == 'OAuth ') {
+            if (isset($request_headers['Authorization'])
+                && substr($request_headers['Authorization'], 0, 6) == 'OAuth '
+            ) {
                 $header_parameters = OAuthUtil::split_header(
                     $request_headers['Authorization']
                 );
                 $parameters = array_merge($parameters, $header_parameters);
             }
-
         }
 
         return new OAuthRequest($http_method, $http_url, $parameters);
@@ -339,15 +343,16 @@ class OAuthRequest
     /**
      * pretty much a helper function to set up the request
      */
-    public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=null)
-    {
-        $parameters = ($parameters) ?  $parameters : array();
-        $defaults = array("oauth_version" => OAuthRequest::$version,
-                          "oauth_nonce" => OAuthRequest::generate_nonce(),
-                          "oauth_timestamp" => OAuthRequest::generate_timestamp(),
-                          "oauth_consumer_key" => $consumer->key);
-        if ($token)
+    public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters = null)
+    {
+        $parameters = ($parameters) ? $parameters : [];
+        $defaults = ["oauth_version" => OAuthRequest::$version,
+                            "oauth_nonce" => OAuthRequest::generate_nonce(),
+                            "oauth_timestamp" => OAuthRequest::generate_timestamp(),
+                            "oauth_consumer_key" => $consumer->key];
+        if ($token) {
             $defaults['oauth_token'] = $token->key;
+        }
 
         $parameters = array_merge($defaults, $parameters);
 
@@ -361,7 +366,7 @@ class OAuthRequest
             if (is_scalar($this->parameters[$name])) {
                 // This is the first duplicate, so transform scalar (string)
                 // into an array so we can add the duplicates
-                $this->parameters[$name] = array($this->parameters[$name]);
+                $this->parameters[$name] = [$this->parameters[$name]];
             }
 
             $this->parameters[$name][] = $value;
@@ -412,11 +417,11 @@ class OAuthRequest
      */
     public function get_signature_base_string()
     {
-        $parts = array(
+        $parts = [
             $this->get_normalized_http_method(),
             $this->get_normalized_http_url(),
             $this->get_signable_parameters()
-        );
+        ];
 
         $parts = OAuthUtil::urlencode_rfc3986($parts);
 
@@ -479,7 +484,7 @@ class OAuthRequest
     {
         $first = true;
         if ($realm) {
-            $out = 'Authorization: OAuth realm="' . OAuthUtil::urlencode_rfc3986($realm) . '"';
+            $out = 'Authorization: OAuth realm="'.OAuthUtil::urlencode_rfc3986($realm).'"';
             $first = false;
         } else {
             $out = 'Authorization: OAuth';
@@ -493,9 +498,9 @@ class OAuthRequest
                 throw new OAuthException('Arrays not supported in headers');
             }
             $out .= ($first) ? ' ' : ',';
-            $out .= OAuthUtil::urlencode_rfc3986($k) .
-                '="' .
-                OAuthUtil::urlencode_rfc3986($v) .
+            $out .= OAuthUtil::urlencode_rfc3986($k).
+                '="'.
+                OAuthUtil::urlencode_rfc3986($v).
                 '"';
             $first = false;
         }
@@ -541,15 +546,15 @@ class OAuthRequest
         $mt = microtime();
         $rand = mt_rand();
 
-        return md5($mt . $rand); // md5s look nicer than numbers
+        return md5($mt.$rand); // md5s look nicer than numbers
     }
 }
 
 class OAuthServer
 {
     protected $timestamp_threshold = 300; // in seconds, five minutes
-    protected $version = '1.0';             // hi blaine
-    protected $signature_methods = array();
+    protected $version = '1.0'; // hi blaine
+    protected $signature_methods = [];
 
     protected $data_store;
 
@@ -572,14 +577,14 @@ class OAuthServer
      */
     public function fetch_request_token(&$request)
     {
-        $this->get_version($request);
+        $this->getVersion($request);
 
-        $consumer = $this->get_consumer($request);
+        $consumer = $this->getConsumer($request);
 
         // no token required for the initial token request
-        $token = NULL;
+        $token = null;
 
-        $this->check_signature($request, $consumer, $token);
+        $this->checkSignature($request, $consumer, $token);
 
         // Rev A change
         $callback = $request->get_parameter('oauth_callback');
@@ -594,14 +599,14 @@ class OAuthServer
      */
     public function fetch_access_token(&$request)
     {
-        $this->get_version($request);
+        $this->getVersion($request);
 
-        $consumer = $this->get_consumer($request);
+        $consumer = $this->getConsumer($request);
 
         // requires authorized request token
-        $token = $this->get_token($request, $consumer, "request");
+        $token = $this->getToken($request, $consumer, "request");
 
-        $this->check_signature($request, $consumer, $token);
+        $this->checkSignature($request, $consumer, $token);
 
         // Rev A change
         $verifier = $request->get_parameter('oauth_verifier');
@@ -615,18 +620,18 @@ class OAuthServer
      */
     public function verify_request(&$request)
     {
-        $this->get_version($request);
-        $consumer = $this->get_consumer($request);
-        $token = $this->get_token($request, $consumer, "access");
-        $this->check_signature($request, $consumer, $token);
-        return array($consumer, $token);
+        $this->getVersion($request);
+        $consumer = $this->getConsumer($request);
+        $token = $this->getToken($request, $consumer, "access");
+        $this->checkSignature($request, $consumer, $token);
+        return [$consumer, $token];
     }
 
     // Internals from here
     /**
      * version 1
      */
-    private function get_version(&$request)
+    private function getVersion(&$request)
     {
         $version = $request->get_parameter("oauth_version");
         if (!$version) {
@@ -643,11 +648,11 @@ class OAuthServer
     /**
      * figure out the signature with some defaults
      */
-    private function get_signature_method($request)
+    private function getSignatureMethod($request)
     {
         $signature_method = $request instanceof OAuthRequest
             ? $request->get_parameter("oauth_signature_method")
-            : NULL;
+            : null;
 
         if (!$signature_method) {
             // According to chapter 7 ("Accessing Protected Ressources") the signature-method
@@ -655,11 +660,10 @@ class OAuthServer
             throw new OAuthException('No signature method parameter. This parameter is required');
         }
 
-        if (!in_array($signature_method,
-            array_keys($this->signature_methods))) {
+        if (!in_array($signature_method, array_keys($this->signature_methods))) {
             throw new OAuthException(
-                "Signature method '$signature_method' not supported " .
-                "try one of the following: " .
+                "Signature method '$signature_method' not supported ".
+                "try one of the following: ".
                 implode(", ", array_keys($this->signature_methods))
             );
         }
@@ -669,11 +673,11 @@ class OAuthServer
     /**
      * try to find the consumer for the provided request's consumer key
      */
-    private function get_consumer($request)
+    private function getConsumer($request)
     {
         $consumer_key = $request instanceof OAuthRequest
             ? $request->get_parameter("oauth_consumer_key")
-            : NULL;
+            : null;
 
         if (!$consumer_key) {
             throw new OAuthException("Invalid consumer key");
@@ -690,21 +694,18 @@ class OAuthServer
     /**
      * try to find the token for the provided request's token key
      */
-    private function get_token($request, $consumer, $token_type="access")
+    private function getToken($request, $consumer, $token_type = "access")
     {
         $token_field = $request instanceof OAuthRequest
             ? $request->get_parameter('oauth_token')
             : null;
 
         if (!empty($token_field)) {
-            $token = $this->data_store->lookup_token(
-                $consumer, $token_type, $token_field
-            );
+            $token = $this->data_store->lookup_token($consumer, $token_type, $token_field);
             if (!$token) {
-                throw new OAuthException("Invalid $token_type token: $token_field");
+                throw new OAuthException('Invalid '.$token_type.' token: '.$token_field);
             }
-        }
-        else {
+        } else {
             $token = new OAuthToken('', '');
         }
         return $token;
@@ -714,7 +715,7 @@ class OAuthServer
      * all-in-one function to check the signature on a request
      * should guess the signature method appropriately
      */
-    private function check_signature($request, $consumer, $token)
+    private function checkSignature($request, $consumer, $token)
     {
         // this should probably be in a different method
         $timestamp = $request instanceof OAuthRequest
@@ -724,13 +725,13 @@ class OAuthServer
             ? $request->get_parameter('oauth_nonce')
             : null;
 
-        $this->check_timestamp($timestamp);
-        $this->check_nonce($consumer, $token, $nonce, $timestamp);
+        $this->checkTimestamp($timestamp);
+        $this->checkNonce($consumer, $token, $nonce, $timestamp);
 
-        $signature_method = $this->get_signature_method($request);
+        $signature_method = $this->getSignatureMethod($request);
 
         $signature = $request->get_parameter('oauth_signature');
-        $valid_sig = $signature_method->check_signature(
+        $valid_sig = $signature_method->checkSignature(
             $request,
             $consumer,
             $token,
@@ -745,9 +746,9 @@ class OAuthServer
     /**
      * check that the timestamp is new enough
      */
-    private function check_timestamp($timestamp)
+    private function checkTimestamp($timestamp)
     {
-        if (! $timestamp) {
+        if (!$timestamp) {
             throw new OAuthException(
                 'Missing timestamp parameter. The parameter is required'
             );
@@ -765,9 +766,9 @@ class OAuthServer
     /**
      * check that the nonce is not repeated
      */
-    private function check_nonce($consumer, $token, $nonce, $timestamp)
+    private function checkNonce($consumer, $token, $nonce, $timestamp)
     {
-        if (! $nonce) {
+        if (!$nonce) {
             throw new OAuthException(
                 'Missing nonce parameter. The parameter is required'
             );
@@ -815,7 +816,6 @@ class OAuthDataStore
         // is authorized
         // should also invalidate the request token
     }
-
 }
 
 class OAuthUtil
@@ -823,8 +823,8 @@ class OAuthUtil
     public static function urlencode_rfc3986($input)
     {
         if (is_array($input)) {
-            return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input);
-        } else if (is_scalar($input)) {
+            return array_map(['OAuthUtil', 'urlencode_rfc3986'], $input);
+        } elseif (is_scalar($input)) {
             return str_replace(
                 '+',
                 ' ',
@@ -851,8 +851,12 @@ class OAuthUtil
     //                  see http://code.google.com/p/oauth/issues/detail?id=163
     public static function split_header($header, $only_allow_oauth_parameters = true)
     {
-        $params = array();
-        if (preg_match_all('/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $header, $matches)) {
+        $params = [];
+        if (preg_match_all(
+            '/('.($only_allow_oauth_parameters ? 'oauth_' : '').'[a-z_-]*)=(:?"([^"]*)"|([^,]*))/',
+            $header,
+            $matches
+        )) {
             foreach ($matches[1] as $i => $h) {
                 $params[$h] = OAuthUtil::urldecode_rfc3986(empty($matches[3][$i]) ? $matches[4][$i] : $matches[3][$i]);
             }
@@ -875,7 +879,7 @@ class OAuthUtil
             // we always want the keys to be Cased-Like-This and arh()
             // returns the headers in the same case as they are in the
             // request
-            $out = array();
+            $out = [];
             foreach ($headers as $key => $value) {
                 $key = str_replace(
                     " ",
@@ -887,7 +891,7 @@ class OAuthUtil
         } else {
             // otherwise we don't have apache and are just going to have to hope
             // that $_SERVER actually contains what we need
-            $out = array();
+            $out = [];
             if (isset($_SERVER['CONTENT_TYPE'])) {
                 $out['Content-Type'] = $_SERVER['CONTENT_TYPE'];
             }
@@ -922,12 +926,12 @@ class OAuthUtil
     public static function parse_parameters($input)
     {
         if (!isset($input) || !$input) {
-            return array();
+            return [];
         }
 
         $pairs = explode('&', $input);
 
-        $parsed_parameters = array();
+        $parsed_parameters = [];
         foreach ($pairs as $pair) {
             $split = explode('=', $pair, 2);
             $parameter = OAuthUtil::urldecode_rfc3986($split[0]);
@@ -940,7 +944,7 @@ class OAuthUtil
                 if (is_scalar($parsed_parameters[$parameter])) {
                     // This is the first duplicate, so transform scalar (string) into an array
                     // so we can add the duplicates
-                    $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
+                    $parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
                 }
 
                 $parsed_parameters[$parameter][] = $value;
@@ -966,7 +970,7 @@ class OAuthUtil
         // Ref: Spec: 9.1.1 (1)
         uksort($params, 'strcmp');
 
-        $pairs = array();
+        $pairs = [];
         foreach ($params as $parameter => $value) {
             if (is_array($value)) {
                 // If two or more parameters share the same name, they are sorted by their value
@@ -974,10 +978,10 @@ class OAuthUtil
                 // June 12th, 2010 - changed to sort because of issue 164 by hidetaka
                 sort($value, SORT_STRING);
                 foreach ($value as $duplicate_value) {
-                    $pairs[] = $parameter . '=' . $duplicate_value;
+                    $pairs[] = $parameter.'='.$duplicate_value;
                 }
             } else {
-                $pairs[] = $parameter . '=' . $value;
+                $pairs[] = $parameter.'='.$value;
             }
         }
         // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61)
diff --git a/modules/oauth/templates/registry.edit.tpl.php b/modules/oauth/templates/registry.edit.tpl.php
index 4c97f36f57300b845bbecb62620bff0241371cf9..b43c40d39c3239424a148bff6084f0aa056b2406 100644
--- a/modules/oauth/templates/registry.edit.tpl.php
+++ b/modules/oauth/templates/registry.edit.tpl.php
@@ -1,21 +1,18 @@
 <?php
 
-$this->data['jquery'] = array('core' => true, 'ui' => true, 'css' => true);
-$this->data['head']  = '<link rel="stylesheet" type="text/css" href="/' . $this->data['baseurlpath'] . 'module.php/oauth/resources/style.css" />' . "\n";
-$this->data['head'] .= '<script type="text/javascript">
-$(document).ready(function() {
-	$("#tabdiv").tabs();
-});
-</script>';
+$this->data['jquery'] = ['core' => true, 'ui' => true, 'css' => true];
+$this->data['head'] = '<link rel="stylesheet" type="text/css" href="/'.
+    $this->data['baseurlpath'].'module.php/oauth/assets/css/oauth.css" />'."\n";
+$this->data['head'] .= '<script type="text/javascript" src="/'.
+    $this->data['baseurlpath'].'module.php/oauth/assets/js/oauth.js"></script>';
 
 $this->includeAtTemplateBase('includes/header.php');
 
+echo '<h1>OAuth Client</h1>';
 
-echo('<h1>OAuth Client</h1>');
+echo $this->data['form'];
 
-echo($this->data['form']);
-
-echo('<p style="float: right"><a href="registry.php">Return to entity listing <strong>without saving...</strong></a></p>');
+echo '<p style="float: right"><a href="registry.php">'.
+    'Return to entity listing <strong>without saving...</strong></a></p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
-
diff --git a/modules/oauth/templates/registry.edit.twig b/modules/oauth/templates/registry.edit.twig
new file mode 100644
index 0000000000000000000000000000000000000000..ad9345d731a93a397528e1c6e2c0a05d7dd940f6
--- /dev/null
+++ b/modules/oauth/templates/registry.edit.twig
@@ -0,0 +1,18 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}assets/css/oauth.css" rel="stylesheet">
+{% endblock %}
+
+{% block postload %}
+    <script src="{{ baseurlpath}}assets/js/oauth.js"></script>
+{% endblock %}
+
+{% block content %}
+    <h1>OAuth Client</h1>
+    {{ form|raw }}
+    <p style="float: right">
+        <a href="registry.php">Return to entity listing <strong>without saving...</strong></a>
+    </p>
+{% endblock %}
diff --git a/modules/oauth/templates/registry.list.php b/modules/oauth/templates/registry.list.php
index 28d64e38ee539f028a385b8a94136db4d92e1f86..1c3b287fb696b8ced33285dbe34599ebd85426ef 100644
--- a/modules/oauth/templates/registry.list.php
+++ b/modules/oauth/templates/registry.list.php
@@ -1,51 +1,47 @@
 <?php
-
-$this->data['jquery'] = array('core' => TRUE, 'ui' => TRUE, 'css' => TRUE);
-$this->data['head']  = '<link rel="stylesheet" type="text/css" href="/' . $this->data['baseurlpath'] . 'module.php/oauth/resources/style.css" />' . "\n";
+$this->data['jquery'] = ['core' => true, 'ui' => true, 'css' => true];
+$this->data['head'] = '<link rel="stylesheet" type="text/css" href="/'.
+    $this->data['baseurlpath'].'module.php/oauth/assets/oauth.css" />'."\n";
 $this->includeAtTemplateBase('includes/header.php');
 
-
-echo('<h1>OAuth Client Registry</h1>');
-
-echo('<p>Here you can register new OAuth Clients. You are successfully logged in as ' . htmlspecialchars($this->data['userid']) . '</p>');
-
-echo('<h2>Your clients</h2>');
-echo('<table class="metalist" style="width: 100%">');
-$i = 0; $rows = array('odd', 'even');
-foreach($this->data['entries']['mine'] AS $entryc ) {
-	$entry = $entryc['value'];
-	$i++; 
-	echo('<tr class="' . $rows[$i % 2] . '">
-		<td>' . htmlspecialchars($entry['name']) . '</td>
-		<td><tt>' . htmlspecialchars($entry['key']) . '</tt></td>
-		<td>
-			<a href="registry.edit.php?editkey=' . urlencode($entry['key']) . '">edit</a>
-			<a href="registry.php?delete=' . urlencode($entry['key']) . '">delete</a>
-		</td></tr>');
+echo '<h1>OAuth Client Registry</h1>';
+echo '<p>Here you can register new OAuth Clients. You are successfully logged in as '.
+    htmlspecialchars($this->data['userid']).'</p>';
+
+echo '<h2>Your clients</h2>';
+echo '<table class="metalist" style="width: 100%">';
+$i = 0;
+$rows = ['odd', 'even'];
+foreach ($this->data['entries']['mine'] as $entryc) {
+    $entry = $entryc['value'];
+    $i++;
+    echo '<tr class="'.$rows[$i % 2].'"><td>'.
+        htmlspecialchars($entry['name']).'</td>	<td><code>'.htmlspecialchars($entry['key']).
+        '</code></td><td><a href="registry.edit.php?editkey='.urlencode($entry['key']).
+        '">edit</a><a href="registry.php?delete='.urlencode($entry['key']).'">delete</a></td></tr>';
 }
 if ($i == 0) {
-	echo('<tr><td colspan="3">No entries registered</td></tr>');
+    echo'<tr><td colspan="3">No entries registered</td></tr>';
 }
-echo('</table>');
-
-echo('<p><a href="registry.edit.php">Add new client</a></p>');
-
-echo('<h2>Other clients</h2>');
-echo('<table class="metalist" style="width: 100%">');
-$i = 0; $rows = array('odd', 'even');
-foreach($this->data['entries']['others'] AS $entryc ) {
-	$entry = $entryc['value'];
-	$i++; 
-	echo('<tr class="' . $rows[$i % 2] . '">
-		<td>' . htmlspecialchars($entry['name']) . '</td>
-		<td><tt>' . htmlspecialchars($entry['key']) . '</tt></td>
-		<td>' . (isset($entry['owner']) ? htmlspecialchars($entry['owner']) : 'No owner') . '
-		</td></tr>');
+echo '</table>';
+
+echo '<p><a href="registry.edit.php">Add new client</a></p>';
+
+echo '<h2>Other clients</h2>';
+echo '<table class="metalist" style="width: 100%">';
+$i = 0;
+$rows = ['odd', 'even'];
+foreach ($this->data['entries']['others'] as $entryc) {
+    $entry = $entryc['value'];
+    $i++;
+    echo '<tr class="'.$rows[$i % 2].'"><td>'.
+        htmlspecialchars($entry['name']).'</td><td><code>'.htmlspecialchars($entry['key']).
+        '</code></td><td>'.(isset($entry['owner']) ? htmlspecialchars($entry['owner']) : 'No owner').
+        '</td></tr>';
 }
 if ($i == 0) {
-	echo('<tr><td colspan="3">No entries registered</td></tr>');
+    echo '<tr><td colspan="3">No entries registered</td></tr>';
 }
-echo('</table>');
+echo '</table>';
 
 $this->includeAtTemplateBase('includes/footer.php');
-
diff --git a/modules/oauth/templates/registry.list.twig b/modules/oauth/templates/registry.list.twig
new file mode 100644
index 0000000000000000000000000000000000000000..86bc5a6792a26489a6d52ec13b65538ab764ca82
--- /dev/null
+++ b/modules/oauth/templates/registry.list.twig
@@ -0,0 +1,58 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}assets/css/oauth.css" rel="stylesheet" />
+{% endblock %}
+
+{% block content %}
+    <h1>OAuth Client Registry</h1>
+    <p>Here you can register new OAuth Clients. You are successfully logged in as {{ userid|escape('html') }}</p>
+    <h2>Your clients</h2>
+
+    <table class="metalist" style="width: 100%;">
+    {% for key, entryc in entries.mine %}
+        {% if loop.index0 is even %}
+            {% set class = 'even' %}
+        {% else %}
+            {% set class = 'odd' %}
+        {% endif %}
+        {% set entry = entryc.value %}
+        <tr class="{{ class }}">
+            <td>{{ entry.name|escape('html') }}</td>
+            <td><kbd>{{ entry.key|escape('html') }}</kbd></td>
+            <td>
+                <a href="registry.edit.php?editkey={{ entry.key|escape('url') }}">edit</a>
+                <a href="registry.php?delete={{ entry.key|escape('url') }}">delete</a>
+            </td>
+        </tr>
+    {% else %}
+        <tr><td colspan="3">No entries registered</td></tr>
+    {% endfor %}
+    </table>
+
+    <p><a href="registry.edit.php">Add new client</a></p>
+    <h2>Other clients</h2>
+
+    <table class="metalist" style="width: 100%">
+    {% for key, entryc in entries.others %}
+        {% if loop.index0 is even %}
+            {% set class = 'even' %}
+        {% else %}
+            {% set class = 'odd' %}
+        {% endif %}
+        {% set entry = entryc.value %}
+        <tr class="{{ class }}">
+            <td>{{ entry.name|escape('html') }}</td>
+            <td><kbd>{{ entry.key|escape('html') }}</kbd></td>
+            {% if eentry.owner is defined %}}
+            <td>{{ entry.owner|escape('html') }}</td>
+            {% else %}
+            <td>No owner</td>
+            {% endif %}
+        </tr>
+    {% else %}
+        <tr><td colspan="3">No entries registered</td></tr>
+    {% endfor %}
+    </table>
+{% endblock%}
diff --git a/modules/oauth/templates/registry.saved.php b/modules/oauth/templates/registry.saved.php
index 0ff62eb50fb116c93272588995898d3b371b3299..2e4bd27a92a916384f614e8b55fd058803e9c199 100644
--- a/modules/oauth/templates/registry.saved.php
+++ b/modules/oauth/templates/registry.saved.php
@@ -1,15 +1,8 @@
 <?php
 
-
-
 $this->includeAtTemplateBase('includes/header.php');
 
-
-echo('<h1>OAuth Client saved</h1>');
-
-echo('<p><a href="registry.php">Go back to OAuth client listing</a></p>');
-
-
+echo '<h1>OAuth Client saved</h1>';
+echo '<p><a href="registry.php">Go back to OAuth client listing</a></p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
-
diff --git a/modules/oauth/templates/registry.saved.twig b/modules/oauth/templates/registry.saved.twig
new file mode 100644
index 0000000000000000000000000000000000000000..6c36465f7162b6b759ba0f41fdb4497b0364a8da
--- /dev/null
+++ b/modules/oauth/templates/registry.saved.twig
@@ -0,0 +1,9 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>OAith Client saved</h1>
+    <p>
+        <a href="registry.php">Go back to OAuth client listing</a>
+    </p>
+{% endblock %}
diff --git a/modules/oauth/www/assets/css/oauth.css b/modules/oauth/www/assets/css/oauth.css
new file mode 100644
index 0000000000000000000000000000000000000000..7b8ad7e92cb2d9fcf4f6f57ecaf714898bd15fa3
--- /dev/null
+++ b/modules/oauth/www/assets/css/oauth.css
@@ -0,0 +1,84 @@
+table.formtable {
+    width: 100%;
+}
+table.formtable tr td.name {
+    text-align: right;
+    vertical-align: top;
+    padding-right: .6em;
+}
+table.formtable tr td.value {
+    text-align: left;
+    padding: 0px;
+}
+table.formtable tr td.header {
+    padding-left: 5px;
+    padding-top: 8px;
+    font-weight: bold;
+    font-size: 110%;
+}
+
+table.formtable tr td input,table.formtable tr td textarea {
+    width: 90%;
+    border: 1px solid #bbb;
+    margin: 2px 5px;
+    padding: 2px 4px;
+}
+
+table.metalist {
+    border: 1px solid #aaa;
+    border-collapse: collapse;
+}
+table.metalist tr td {
+    padding: 2px 5px;
+}
+table.metalist tr.even td {
+    background: #e5e5e5;
+}
+
+@media all {
+    div#content {
+        margin: .4em ! important;
+    }
+
+    form {
+        display: inline;
+    }
+
+    ul.tabset_tabs {
+        margin: 0px;
+        padding: 0px;
+        list-style: none;
+    }
+
+    ul.tabset_tabs li {
+        background: none;
+        color: #222;
+        display: inline-block;
+        padding: 10px 15px;
+        cursor: pointer;
+    }
+
+    ul.tabset_tabs li.current {
+        background: #ededed;
+        color: #222;
+    }
+
+    .tabset_content {
+        display: none;
+        background: #ededed;
+        padding: 15px;
+    }
+
+    .tabset_content.current {
+        display: inherit;
+    }
+
+    #graph img {
+        max-width: 77%;
+        height: auto;
+    }
+    #table img {
+        max-width: 77%;
+        height: auto;
+    }
+}
diff --git a/modules/oauth/www/assets/js/oauth.js b/modules/oauth/www/assets/js/oauth.js
new file mode 100644
index 0000000000000000000000000000000000000000..442c63effcc4101a5f3ca02b50fb522cb83fd229
--- /dev/null
+++ b/modules/oauth/www/assets/js/oauth.js
@@ -0,0 +1,3 @@
+document.addEventListener('DOMContentLoaded', function () {
+    $("#tabdiv").tabs();
+});
diff --git a/modules/oauth/www/getUserInfo.php b/modules/oauth/www/getUserInfo.php
index 516b0654424436edbd4d9f229c621939bd524b7f..ad9f878c8b511be1eaa9c87a1ff7ac15120f7b22 100644
--- a/modules/oauth/www/getUserInfo.php
+++ b/modules/oauth/www/getUserInfo.php
@@ -1,15 +1,17 @@
 <?php
 
-require_once(dirname(dirname(__FILE__)) . '/libextinc/OAuth.php');
+require_once(dirname(dirname(__FILE__)).'/libextinc/OAuth.php');
 
-$oauthconfig = SimpleSAML_Configuration::getConfig('module_oauth.php');
+$oauthconfig = \SimpleSAML\Configuration::getConfig('module_oauth.php');
 
-if (!$oauthconfig->getBoolean('getUserInfo.enable', FALSE)) {
-	throw new Exception('Get user info endpoint is disabled. This endpoint can be enabled in the module_oauth.php configuration file.');
+if (!$oauthconfig->getBoolean('getUserInfo.enable', false)) {
+    throw new \Exception(
+        'Get user info endpoint is disabled. This endpoint can be enabled in the module_oauth.php configuration file.'
+    );
 }
 
-$store = new sspmod_oauth_OAuthStore();
-$server = new sspmod_oauth_OAuthServer($store);
+$store = new \SimpleSAML\Module\oauth\OAuthStore();
+$server = new \SimpleSAML\Module\oauth\OAuthServer($store);
 
 $hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
 $plaintext_method = new OAuthSignatureMethod_PLAINTEXT();
@@ -23,4 +25,3 @@ list($consumer, $token) = $server->verify_request($req);
 $data = $store->getAuthorizedData($token->key);
 
 echo json_encode($data);
-
diff --git a/modules/oauth/www/registry.edit.php b/modules/oauth/www/registry.edit.php
index ef8e42ff43bb68eca426ccd3459f4cec0e950462..a367c482050addb0af428e566bcdc40a6b1564bc 100644
--- a/modules/oauth/www/registry.edit.php
+++ b/modules/oauth/www/registry.edit.php
@@ -1,68 +1,59 @@
 <?php
 
 // Load SimpleSAMLphp, configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
-$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
+$oauthconfig = \SimpleSAML\Configuration::getOptionalConfig('module_oauth.php');
 
-$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
+$store = new \SimpleSAML\Module\core\Storage\SQLPermanentStorage('oauth');
 
-$authsource = "admin";	// force admin to authenticate as registry maintainer
+$authsource = "admin"; // force admin to authenticate as registry maintainer
 $useridattr = $oauthconfig->getValue('useridattr', 'user');
 
 if ($session->isValid($authsource)) {
-	$attributes = $session->getAuthData($authsource, 'Attributes');
-	// Check if userid exists
-	if (!isset($attributes[$useridattr])) 
-		throw new Exception('User ID is missing');
-	$userid = $attributes[$useridattr][0];
+    $attributes = $session->getAuthData($authsource, 'Attributes');
+    // Check if userid exists
+    if (!isset($attributes[$useridattr])) {
+        throw new \Exception('User ID is missing');
+    }
+    $userid = $attributes[$useridattr][0];
 } else {
-	$as = SimpleSAML_Auth_Source::getById($authsource);
-	$as->initLogin(\SimpleSAML\Utils\HTTP::getSelfURL());
-}
-
-function requireOwnership($entry, $userid) {
-	if (!isset($entry['owner']))
-		throw new Exception('OAuth Consumer has no owner. Which means no one is granted access, not even you.');
-	if ($entry['owner'] !== $userid) 
-		throw new Exception('OAuth Consumer has an owner that is not equal to your userid, hence you are not granted access.');
+    $as = \SimpleSAML\Auth\Source::getById($authsource);
+    $as->initLogin(\SimpleSAML\Utils\HTTP::getSelfURL());
 }
 
 if (array_key_exists('editkey', $_REQUEST)) {
-	$entryc = $store->get('consumers', $_REQUEST['editkey'], '');
-	$entry = $entryc['value'];
-	requireOwnership($entry, $userid);
-	
+    $entryc = $store->get('consumers', $_REQUEST['editkey'], '');
+    $entry = $entryc['value'];
+    \SimpleSAML\Module\oauth\Registry::requireOwnership($entry, $userid);
 } else {
-	$entry = array(
-		'owner' => $userid,
-		'key' => SimpleSAML\Utils\Random::generateID(),
-		'secret' => SimpleSAML\Utils\Random::generateID(),
-	);
+    $entry = [
+        'owner' => $userid,
+        'key' => \SimpleSAML\Utils\Random::generateID(),
+        'secret' => \SimpleSAML\Utils\Random::generateID(),
+    ];
 }
 
-
-$editor = new sspmod_oauth_Registry();
-
+$editor = new \SimpleSAML\Module\oauth\Registry();
 
 if (isset($_POST['submit'])) {
-	$editor->checkForm($_POST);
+    $editor->checkForm($_POST);
+
+    $entry = $editor->formToMeta($_POST, [], ['owner' => $userid]);
 
-	$entry = $editor->formToMeta($_POST, array(), array('owner' => $userid));
+    \SimpleSAML\Module\oauth\Registry::requireOwnership($entry, $userid);
 
-	requireOwnership($entry, $userid);
+    $store->set('consumers', $entry['key'], '', $entry);
 
-	$store->set('consumers', $entry['key'], '', $entry);
-	
-	$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.saved.php');
-	$template->data['entry'] = $entry;
-	$template->show();
-	exit;
+    $template = new \SimpleSAML\XHTML\Template($config, 'oauth:registry.saved.php');
+    $template->data['entry'] = $entry;
+    $template->show();
+    exit;
 }
 
 $form = $editor->metaToForm($entry);
 
-$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.edit.tpl.php');
+$template = new \SimpleSAML\XHTML\Template($config, 'oauth:registry.edit.tpl.php');
 $template->data['form'] = $form;
+$template->data['jquery'] = ['core' => false, 'ui' => true, 'css' => true];
 $template->show();
-
diff --git a/modules/oauth/www/registry.php b/modules/oauth/www/registry.php
index b53a76f9eb6318ab9001f232cb9175aad4be1c5d..4431835a63786095977605465fdb10254b097940 100644
--- a/modules/oauth/www/registry.php
+++ b/modules/oauth/www/registry.php
@@ -1,57 +1,50 @@
 <?php
-
 // Load SimpleSAMLphp, configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
-$oauthconfig = SimpleSAML_Configuration::getOptionalConfig('module_oauth.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
+$oauthconfig = \SimpleSAML\Configuration::getOptionalConfig('module_oauth.php');
 
-$store = new sspmod_core_Storage_SQLPermanentStorage('oauth');
+$store = new \SimpleSAML\Module\core\Storage\SQLPermanentStorage('oauth');
 
-$authsource = "admin";	// force admin to authenticate as registry maintainer
+$authsource = "admin"; // force admin to authenticate as registry maintainer
 $useridattr = $oauthconfig->getValue('useridattr', 'user');
 
 if ($session->isValid($authsource)) {
-	$attributes = $session->getAuthData($authsource, 'Attributes');
-	// Check if userid exists
-	if (!isset($attributes[$useridattr])) 
-		throw new Exception('User ID is missing');
-	$userid = $attributes[$useridattr][0];
+    $attributes = $session->getAuthData($authsource, 'Attributes');
+    // Check if userid exists
+    if (!isset($attributes[$useridattr])) {
+        throw new \Exception('User ID is missing');
+    }
+    $userid = $attributes[$useridattr][0];
 } else {
-	$as = SimpleSAML_Auth_Source::getById($authsource);
-	$as->initLogin(\SimpleSAML\Utils\HTTP::getSelfURL());
-}
-
-function requireOwnership($entry, $userid) {
-	if (!isset($entry['owner']))
-		throw new Exception('OAuth Consumer has no owner. Which means no one is granted access, not even you.');
-	if ($entry['owner'] !== $userid) 
-		throw new Exception('OAuth Consumer has an owner that is not equal to your userid, hence you are not granted access.');
+    $as = \SimpleSAML\Auth\Source::getById($authsource);
+    $as->initLogin(\SimpleSAML\Utils\HTTP::getSelfURL());
 }
 
-
 if (isset($_REQUEST['delete'])) {
-	$entryc = $store->get('consumers', $_REQUEST['delete'], '');
-	$entry = $entryc['value'];
+    $entryc = $store->get('consumers', $_REQUEST['delete'], '');
+    $entry = $entryc['value'];
 
-	requireOwnership($entry, $userid);
-	$store->remove('consumers', $entry['key'], '');
+    \SimpleSAML\Module\oauth\Registry::requireOwnership($entry, $userid);
+    $store->remove('consumers', $entry['key'], '');
 }
 
-
 $list = $store->getList('consumers');
 
-$slist = array('mine' => array(), 'others' => array());
-if (is_array($list)) 
-foreach($list AS $listitem) {
-	if (array_key_exists('owner', $listitem['value'])) {
-		if ($listitem['value']['owner'] === $userid) {
-			$slist['mine'][] = $listitem; continue;
-		}
-	}
-	$slist['others'][] = $listitem;
+$slist = ['mine' => [], 'others' => []];
+if (is_array($list)) {
+    foreach ($list as $listitem) {
+        if (array_key_exists('owner', $listitem['value'])) {
+            if ($listitem['value']['owner'] === $userid) {
+                $slist['mine'][] = $listitem;
+                continue;
+            }
+        }
+    }
+    $slist['others'][] = $listitem;
 }
 
-$template = new SimpleSAML_XHTML_Template($config, 'oauth:registry.list.php');
+$template = new \SimpleSAML\XHTML\Template($config, 'oauth:registry.list.php');
 $template->data['entries'] = $slist;
 $template->data['userid'] = $userid;
 $template->show();
diff --git a/modules/oauth/www/resources/style.css b/modules/oauth/www/resources/style.css
deleted file mode 100644
index 1240db06576e85af71049ead441122ca26354a04..0000000000000000000000000000000000000000
--- a/modules/oauth/www/resources/style.css
+++ /dev/null
@@ -1,37 +0,0 @@
-table.formtable {
-	width: 100%;
-}
-table.formtable tr td.name {
-	text-align: right;
-	vertical-align: top;
-	padding-right: .6em;
-}
-table.formtable tr td.value {
-	text-align: left;
-	padding: 0px;
-}
-table.formtable tr td.header {
-	padding-left: 5px;
-	padding-top: 8px;
-	font-weight: bold;
-	font-size: 110%;
-}
-
-table.formtable tr td input,table.formtable tr td textarea {
-	width: 90%;
-	border: 1px solid #bbb;
-	margin: 2px 5px;
-	padding: 2px 4px;
-}
-
-
-table.metalist {
-	border: 1px solid #aaa;
-	border-collapse: collapse;
-}
-table.metalist tr td {
-	padding: 2px 5px; 
-}
-table.metalist tr.even td {
-	background: #e5e5e5;
-}
\ No newline at end of file
diff --git a/modules/portal/config-templates/module_portal.php b/modules/portal/config-templates/module_portal.php
index bff5d9ac66ccfd02cff2adf2f3cae0fbfb5db3e5..85df6f99ab589004bc09c08671a677d25f66dcd8 100644
--- a/modules/portal/config-templates/module_portal.php
+++ b/modules/portal/config-templates/module_portal.php
@@ -1,13 +1,11 @@
 <?php
-/* 
+/*
  * Configuration for the module portal.
  */
 
-$config = array (
-
-	'pagesets' => array(
-		array('frontpage_welcome', 'frontpage_config', 'frontpage_auth', 'frontpage_federation'),
-		array('santitycheck', 'statistics'),
-	),
-	
-);
+$config = [
+    'pagesets' => [
+        ['frontpage_welcome', 'frontpage_config', 'frontpage_auth', 'frontpage_federation'],
+        ['sanitycheck', 'statistics'],
+    ],
+];
diff --git a/modules/portal/hooks/hook_htmlinject.php b/modules/portal/hooks/hook_htmlinject.php
index 3abbf8898a3bb0eb871a2855366c50c434fe4040..efa1984a32aa37402255535297c245325658deef 100644
--- a/modules/portal/hooks/hook_htmlinject.php
+++ b/modules/portal/hooks/hook_htmlinject.php
@@ -5,39 +5,41 @@
  *
  * @param array &$hookinfo  hookinfo
  */
-function portal_hook_htmlinject(&$hookinfo) {
-	assert(is_array($hookinfo));
-	assert(array_key_exists('pre', $hookinfo));
-	assert(array_key_exists('post', $hookinfo));
-	assert(array_key_exists('page', $hookinfo));
-
-	$links = array('links' => array());
-	SimpleSAML\Module::callHooks('frontpage', $links);
-
-	$portalConfig = SimpleSAML_Configuration::getOptionalConfig('module_portal.php');
-	
-	$allLinks = array();
-	foreach($links AS $ls) {
-		$allLinks = array_merge($allLinks, $ls);
-	}
-
-	$pagesets = $portalConfig->getValue('pagesets', array(
-		array('frontpage_welcome', 'frontpage_config', 'frontpage_auth', 'frontpage_federation'),
-	));
-	SimpleSAML\Module::callHooks('portalextras', $pagesets);
-	$portal = new sspmod_portal_Portal($allLinks, $pagesets);
-	
-	if (!$portal->isPortalized($hookinfo['page'])) return;
-
-	// Include jquery UI CSS files in header
-	$hookinfo['jquery']['css'] = TRUE;
-
-	// Header
-	$hookinfo['pre'][]  = '<div id="portalmenu" class="ui-tabs ui-widget ui-widget-content ui-corner-all">' . 
-		$portal->getMenu($hookinfo['page']) . 
-		'<div id="portalcontent" class="ui-tabs-panel ui-widget-content ui-corner-bottom">';
-
-	// Footer
-	$hookinfo['post'][] = '</div></div>';
-	
+function portal_hook_htmlinject(&$hookinfo)
+{
+    assert(is_array($hookinfo));
+    assert(array_key_exists('pre', $hookinfo));
+    assert(array_key_exists('post', $hookinfo));
+    assert(array_key_exists('page', $hookinfo));
+
+    $links = ['links' => []];
+    \SimpleSAML\Module::callHooks('frontpage', $links);
+
+    $portalConfig = \SimpleSAML\Configuration::getOptionalConfig('module_portal.php');
+
+    $allLinks = [];
+    foreach ($links as $ls) {
+        $allLinks = array_merge($allLinks, $ls);
+    }
+
+    $pagesets = $portalConfig->getValue('pagesets', [
+        ['frontpage_welcome', 'frontpage_config', 'frontpage_auth', 'frontpage_federation'],
+    ]);
+    \SimpleSAML\Module::callHooks('portalextras', $pagesets);
+    $portal = new \SimpleSAML\Module\portal\Portal($allLinks, $pagesets);
+
+    if (!$portal->isPortalized($hookinfo['page'])) {
+        return;
+    }
+
+    // Include jquery UI CSS files in header
+    $hookinfo['jquery']['css'] = true;
+
+    // Header
+    $hookinfo['pre'][] = '<div id="portalmenu" class="ui-tabs ui-widget ui-widget-content ui-corner-all">'.
+        $portal->getMenu($hookinfo['page']).
+        '<div id="portalcontent" class="ui-tabs-panel ui-widget-content ui-corner-bottom">';
+
+    // Footer
+    $hookinfo['post'][] = '</div></div>';
 }
diff --git a/modules/portal/lib/Portal.php b/modules/portal/lib/Portal.php
index 9cb25a2c4cd1c468f0deab9ec209e1914c7d1691..517ce2edfa4a75bf7afa0798f0d3b9c8fa0f5fbc 100644
--- a/modules/portal/lib/Portal.php
+++ b/modules/portal/lib/Portal.php
@@ -1,79 +1,82 @@
 <?php
 
-class sspmod_portal_Portal
+namespace SimpleSAML\Module\portal;
+
+class Portal
 {
-	private $pages;
-	private $config;
-	
-	public function __construct($pages, $config = null)
+    private $pages;
+    private $config;
+
+    public function __construct($pages, $config = null)
     {
-		$this->pages = $pages;
-		$this->config = $config;
-	}
-	
-	public function getTabset($thispage)
+        $this->pages = $pages;
+        $this->config = $config;
+    }
+
+    public function getTabset($thispage)
     {
-		if (!isset($this->config)) {
+        if (!isset($this->config)) {
             return null;
         }
-		foreach($this->config as $set) {
-			if (in_array($thispage, $set, true)) {
-				return $set;
-			}
-		}
-		return null;
-	}
-	
-	public function isPortalized($thispage)
+        foreach ($this->config as $set) {
+            if (in_array($thispage, $set, true)) {
+                return $set;
+            }
+        }
+        return null;
+    }
+
+    public function isPortalized($thispage)
     {
-		foreach($this->config as $set) {
-			if (in_array($thispage, $set, true)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	public function getLoginInfo($translator, $thispage)
+        foreach ($this->config as $set) {
+            if (in_array($thispage, $set, true)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public function getLoginInfo($translator, $thispage)
     {
-		$info = array('info' => '', 'translator' => $translator, 'thispage' => $thispage);
-		SimpleSAML\Module::callHooks('portalLoginInfo', $info);
-		return $info['info'];
-	}
-	
-	public function getMenu($thispage)
+        $info = ['info' => '', 'translator' => $translator, 'thispage' => $thispage];
+        \SimpleSAML\Module::callHooks('portalLoginInfo', $info);
+        return $info['info'];
+    }
+
+    public function getMenu($thispage)
     {
-		$config = SimpleSAML_Configuration::getInstance();
-		$t = new SimpleSAML\Locale\Translate($config);
-		$tabset = $this->getTabset($thispage);
-		$logininfo = $this->getLoginInfo($t, $thispage);
-		$text = '';
-		$text .= '<ul class="tabset_tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">';
-		foreach ($this->pages as $pageid => $page) {
-			if (isset($tabset) && !in_array($pageid, $tabset, true)) {
+        $config = \SimpleSAML\Configuration::getInstance();
+        $t = new \SimpleSAML\Locale\Translate($config);
+        $tabset = $this->getTabset($thispage);
+        $logininfo = $this->getLoginInfo($t, $thispage);
+        $classes = 'tabset_tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all';
+        $text = '<ul class="'.$classes.'">';
+        foreach ($this->pages as $pageid => $page) {
+            if (isset($tabset) && !in_array($pageid, $tabset, true)) {
                 continue;
             }
-			$name = 'uknown';
-			if (isset($page['text'])) {
+            $name = 'uknown';
+            if (isset($page['text'])) {
                 $name = $page['text'];
             }
-			if (isset($page['shorttext'])) {
+            if (isset($page['shorttext'])) {
                 $name = $page['shorttext'];
             }
-			if (!isset($page['href'])) {
-				$text .= '<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#">' . $t->t($name) . '</a></li>';
-			} else if($pageid === $thispage ) {
-				$text .= '<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#">' . $t->t($name) . '</a></li>';
-			} else {
-				$text .= '<li class="ui-state-default ui-corner-top"><a href="' . $page['href'] . '">' . $t->t($name) . '</a></li>';
-			}
-			
-		}
-		$text .= '</ul>';
-		if (!empty($logininfo)) {
-			$text .= '<p class="logininfo" style="text-align: right; margin: 0px">' . $logininfo . '</p>';
-		}
-
-		return $text;
-	}
+            if (!isset($page['href'])) {
+                $text .= '<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#">'.
+                    $t->t($name).'</a></li>';
+            } elseif ($pageid === $thispage) {
+                $text .= '<li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#">'.
+                    $t->t($name).'</a></li>';
+            } else {
+                $text .= '<li class="ui-state-default ui-corner-top"><a href="'.$page['href'].'">'.
+                    $t->t($name).'</a></li>';
+            }
+        }
+        $text .= '</ul>';
+        if (!empty($logininfo)) {
+            $text .= '<p class="logininfo" style="text-align: right; margin: 0px">'.$logininfo.'</p>';
+        }
+        return $text;
+    }
 }
diff --git a/modules/preprodwarning/lib/Auth/Process/Warning.php b/modules/preprodwarning/lib/Auth/Process/Warning.php
index 9ece3fa4bd5532eff56e96a36dfb66c6c5ede471..bbc6fdadb2d20f684c75db19e17f5e7419dce5bf 100644
--- a/modules/preprodwarning/lib/Auth/Process/Warning.php
+++ b/modules/preprodwarning/lib/Auth/Process/Warning.php
@@ -1,36 +1,35 @@
 <?php
 
+namespace SimpleSAML\Module\preprodwarning\Auth\Process;
+
 /**
  * Give a warning that the user is accessing a test system, not a production system.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_preprodwarning_Auth_Process_Warning extends SimpleSAML_Auth_ProcessingFilter {
-
-
-
-	/**
-	 * Process a authentication response.
-	 *
-	 * This function saves the state, and redirects the user to the page where the user
-	 * can authorize the release of the attributes.
-	 *
-	 * @param array $state  The state of the response.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-
-		if (isset($state['isPassive']) && $state['isPassive'] === TRUE) {
-			// We have a passive request. Skip the warning
-			return;
-		}
-
-		// Save state and redirect.
-		$id = SimpleSAML_Auth_State::saveState($state, 'warning:request');
-		$url = SimpleSAML\Module::getModuleURL('preprodwarning/showwarning.php');
-		\SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
-	}
-	
-
 
+class Warning extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Process a authentication response.
+     *
+     * This function saves the state, and redirects the user to the page where the user
+     * can authorize the release of the attributes.
+     *
+     * @param array $state  The state of the response.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+
+        if (isset($state['isPassive']) && $state['isPassive'] === true) {
+            // We have a passive request. Skip the warning
+            return;
+        }
+
+        // Save state and redirect.
+        $id = \SimpleSAML\Auth\State::saveState($state, 'warning:request');
+        $url = \SimpleSAML\Module::getModuleURL('preprodwarning/showwarning.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
+    }
 }
diff --git a/modules/preprodwarning/templates/warning.php b/modules/preprodwarning/templates/warning.php
index 981e2ffe3247849b75ae08ddb633b5a9b3879b52..3d09fa9c33334cd53a9dd6d49b669fa50ddc0856 100644
--- a/modules/preprodwarning/templates/warning.php
+++ b/modules/preprodwarning/templates/warning.php
@@ -16,29 +16,21 @@
  * @package SimpleSAMLphp
  */
 
-
 $this->data['header'] = $this->t('{preprodwarning:warning:warning_header}');
 $this->data['autofocus'] = 'yesbutton';
 
 $this->includeAtTemplateBase('includes/header.php');
-
-?>
-
-<form style="display: inline; margin: 0px; padding: 0px" action="<?php echo htmlspecialchars($this->data['yesTarget']); ?>">
-
-	<?php
-		// Embed hidden fields...
-		foreach ($this->data['yesData'] as $name => $value) {
-			echo('<input type="hidden" name="' . htmlspecialchars($name) . '" value="' . htmlspecialchars($value) . '" />');
-		}
-	?>
-	<p><?php echo $this->t('{preprodwarning:warning:warning}'); ?></p>
-
-	<input type="submit" name="yes" id="yesbutton" value="<?php echo htmlspecialchars($this->t('{preprodwarning:warning:yes}')) ?>" />
-
-</form>
-
-
-<?php
+$yesTarget = htmlspecialchars($this->data['yesTarget']);
+$yesWarning = htmlspecialchars($this->t('{preprodwarning:warning:yes}'));
+$warning = $this->t('{preprodwarning:warning:warning}');
+echo '<form style="display: inline; margin: 0px; padding: 0px" action="'.$yesTarget.'">';
+
+// Embed hidden fields...
+foreach ($this->data['yesData'] as $name => $value) {
+    echo '<input type="hidden" name="'.htmlspecialchars($name).'" value="'.htmlspecialchars($value).'" />';
+}
+echo '<p>'.$warning.'</p>';
+echo '<input type="submit" name="yes" id="yesbutton" value="'.$yesWarning.'" />';
+echo '</form>';
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/preprodwarning/templates/warning.twig b/modules/preprodwarning/templates/warning.twig
new file mode 100644
index 0000000000000000000000000000000000000000..838dd072b1d946abb43b16c41846dc1cf7afc13f
--- /dev/null
+++ b/modules/preprodwarning/templates/warning.twig
@@ -0,0 +1,18 @@
+{% set pagetitle = 'Warning about accessing a pre-production system'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+
+<form action="{{ yesTarget }}">
+
+        <p>{% trans %}You are now accessing a pre-production system. This authentication setup is for testing and pre-production verification only. If someone sent you a link that pointed you here, and you are not <i>a tester</i> you probably got the wrong link, and should <b>not be here</b>.{% endtrans %}</p><br />
+{% for name,value in yesData %}
+        <input type="hidden" name="{{ name }}" value="{{ value }}">
+{% endfor %}
+<p>
+        <input type="submit" name="yes" class="pure-button pure-button-red" value="{{'Yes, I know I am accessing a pre-production system'|trans}}" autofocus>
+</p>
+
+</form>
+
+{% endblock %}
diff --git a/modules/preprodwarning/www/showwarning.php b/modules/preprodwarning/www/showwarning.php
index 47490183842db9e396a7bc354e77b9abbcfdb04e..394617d35cab6a1df9f58f5fda76b366b744cc68 100644
--- a/modules/preprodwarning/www/showwarning.php
+++ b/modules/preprodwarning/www/showwarning.php
@@ -7,26 +7,22 @@
  * @package SimpleSAMLphp
  */
 
-SimpleSAML\Logger::info('PreProdWarning - Showing warning to user');
+\SimpleSAML\Logger::info('PreProdWarning - Showing warning to user');
 
 if (!array_key_exists('StateId', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing required StateId query parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing required StateId query parameter.');
 }
 $id = $_REQUEST['StateId'];
-$state = SimpleSAML_Auth_State::loadState($id, 'warning:request');
-
+$state = \SimpleSAML\Auth\State::loadState($id, 'warning:request');
 
 if (array_key_exists('yes', $_REQUEST)) {
-	// The user has pressed the yes-button
-
-	SimpleSAML_Auth_ProcessingChain::resumeProcessing($state);
+    // The user has pressed the yes-button
+    \SimpleSAML\Auth\ProcessingChain::resumeProcessing($state);
 }
 
+$globalConfig = \SimpleSAML\Configuration::getInstance();
 
-
-$globalConfig = SimpleSAML_Configuration::getInstance();
-
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'preprodwarning:warning.php');
-$t->data['yesTarget'] = SimpleSAML\Module::getModuleURL('preprodwarning/showwarning.php');
-$t->data['yesData'] = array('StateId' => $id);
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'preprodwarning:warning.php');
+$t->data['yesTarget'] = \SimpleSAML\Module::getModuleURL('preprodwarning/showwarning.php');
+$t->data['yesData'] = ['StateId' => $id];
 $t->show();
diff --git a/modules/radius/lib/Auth/Source/Radius.php b/modules/radius/lib/Auth/Source/Radius.php
index 649df807b768dcdc4f0abd3e9e8fe6d007bd1cab..70a192b4136b913ff5bbfbfc4479a4cf3602fe79 100644
--- a/modules/radius/lib/Auth/Source/Radius.php
+++ b/modules/radius/lib/Auth/Source/Radius.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\radius\Auth\Source;
+
 /**
  * RADIUS authentication source.
  *
@@ -7,7 +9,8 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase
+
+class Radius extends \SimpleSAML\Module\core\Auth\UserPassBase
 {
     /**
      * The list of radius servers to use.
@@ -80,25 +83,31 @@ class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase
         parent::__construct($info, $config);
 
         // Parse configuration.
-        $config = SimpleSAML_Configuration::loadFromArray($config,
-            'Authentication source ' . var_export($this->authId, true));
+        $config = \SimpleSAML\Configuration::loadFromArray(
+            $config,
+            'Authentication source '.var_export($this->authId, true)
+        );
 
-        $this->servers = $config->getArray('servers', array());
-        /* For backwards compatibility. */
+        $this->servers = $config->getArray('servers', []);
+        // For backwards compatibility
         if (empty($this->servers)) {
             $this->hostname = $config->getString('hostname');
             $this->port = $config->getIntegerRange('port', 1, 65535, 1812);
             $this->secret = $config->getString('secret');
-            $this->servers[] = array('hostname' => $this->hostname,
-                                     'port' => $this->port,
-                                     'secret' => $this->secret);
+            $this->servers[] = [
+                'hostname' => $this->hostname,
+                'port' => $this->port,
+                'secret' => $this->secret
+            ];
         }
         $this->timeout = $config->getInteger('timeout', 5);
         $this->retries = $config->getInteger('retries', 3);
         $this->realm = $config->getString('realm', null);
         $this->usernameAttribute = $config->getString('username_attribute', null);
-        $this->nasIdentifier = $config->getString('nas_identifier',
-            \SimpleSAML\Utils\HTTP::getSelfHost());
+        $this->nasIdentifier = $config->getString(
+            'nas_identifier',
+            \SimpleSAML\Utils\HTTP::getSelfHost()
+        );
 
         $this->vendor = $config->getInteger('attribute_vendor', null);
         if ($this->vendor !== null) {
@@ -121,61 +130,69 @@ class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase
 
         $radius = radius_auth_open();
 
-        /* Try to add all radius servers, trigger a failure if no one works. */
+        // Try to add all radius servers, trigger a failure if no one works
         $success = false;
         foreach ($this->servers as $server) {
             if (!isset($server['port'])) {
                 $server['port'] = 1812;
             }
-            if (!radius_add_server($radius,
-                $server['hostname'], $server['port'], $server['secret'], 
-                $this->timeout, $this->retries)) {
-                SimpleSAML\Logger::info("Could not add radius server: " .
-                    radius_strerror($radius));
+            if (!radius_add_server(
+                $radius,
+                $server['hostname'],
+                $server['port'],
+                $server['secret'],
+                $this->timeout,
+                $this->retries
+            )) {
+                \SimpleSAML\Logger::info(
+                    "Could not add radius server: ".radius_strerror($radius)
+                );
                 continue;
             }
             $success = true;
         }
         if (!$success) {
-            throw new Exception('Error adding radius servers, no servers available');
+            throw new \Exception('Error adding radius servers, no servers available');
         }
 
-        if (!radius_create_request($radius, RADIUS_ACCESS_REQUEST)) {
-            throw new Exception('Error creating radius request: ' .
-                radius_strerror($radius));
+        if (!radius_create_request($radius, \RADIUS_ACCESS_REQUEST)) {
+            throw new \Exception(
+                'Error creating radius request: '.radius_strerror($radius)
+            );
         }
 
         if ($this->realm === null) {
-            radius_put_attr($radius, RADIUS_USER_NAME, $username);
+            radius_put_attr($radius, \RADIUS_USER_NAME, $username);
         } else {
-            radius_put_attr($radius, RADIUS_USER_NAME, $username . '@' . $this->realm);
+            radius_put_attr($radius, \RADIUS_USER_NAME, $username.'@'.$this->realm);
         }
-        radius_put_attr($radius, RADIUS_USER_PASSWORD, $password);
+        radius_put_attr($radius, \RADIUS_USER_PASSWORD, $password);
 
         if ($this->nasIdentifier !== null) {
-            radius_put_attr($radius, RADIUS_NAS_IDENTIFIER, $this->nasIdentifier);
+            radius_put_attr($radius, \RADIUS_NAS_IDENTIFIER, $this->nasIdentifier);
         }
 
         $res = radius_send_request($radius);
-        if ($res != RADIUS_ACCESS_ACCEPT) {
+        if ($res != \RADIUS_ACCESS_ACCEPT) {
             switch ($res) {
-            case RADIUS_ACCESS_REJECT:
-                /* Invalid username or password. */
-                throw new SimpleSAML_Error_Error('WRONGUSERPASS');
-            case RADIUS_ACCESS_CHALLENGE:
-                throw new Exception('Radius authentication error: Challenge requested, but not supported.');
-            default:
-                throw new Exception('Error during radius authentication: ' .
-                    radius_strerror($radius));
+                case \RADIUS_ACCESS_REJECT:
+                    // Invalid username or password
+                    throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
+                case \RADIUS_ACCESS_CHALLENGE:
+                    throw new \Exception('Radius authentication error: Challenge requested, but not supported.');
+                default:
+                    throw new \Exception(
+                        'Error during radius authentication: '.radius_strerror($radius)
+                    );
             }
         }
 
-        /* If we get this far, we have a valid login. */
+        // If we get this far, we have a valid login
 
-        $attributes = array();
+        $attributes = [];
 
         if ($this->usernameAttribute !== null) {
-            $attributes[$this->usernameAttribute] = array($username);
+            $attributes[$this->usernameAttribute] = [$username];
         }
 
         if ($this->vendor === null) {
@@ -186,28 +203,29 @@ class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase
             return $attributes;
         }
 
-        /* get AAI attribute sets. Contributed by Stefan Winter, (c) RESTENA */
+        // get AAI attribute sets. Contributed by Stefan Winter, (c) RESTENA
         while ($resa = radius_get_attr($radius)) {
-
             if (!is_array($resa)) {
-                throw new Exception('Error getting radius attributes: ' .
-                    radius_strerror($radius));
+                throw new \Exception(
+                    'Error getting radius attributes: '.radius_strerror($radius)
+                );
             }
 
-            /* Use the received user name */
-            if ($resa['attr'] == RADIUS_USER_NAME) {
-                $attributes[$this->usernameAttribute] = array($resa['data']);
+            // Use the received user name
+            if ($resa['attr'] == \RADIUS_USER_NAME) {
+                $attributes[$this->usernameAttribute] = [$resa['data']];
                 continue;
             }
 
-            if ($resa['attr'] !== RADIUS_VENDOR_SPECIFIC) {
+            if ($resa['attr'] !== \RADIUS_VENDOR_SPECIFIC) {
                 continue;
             }
 
             $resv = radius_get_vendor_attr($resa['data']);
             if (!is_array($resv)) {
-                throw new Exception('Error getting vendor specific attribute: ' .
-                    radius_strerror($radius));
+                throw new \Exception(
+                    'Error getting vendor specific attribute: '.radius_strerror($radius)
+                );
             }
 
             $vendor = $resv['vendor'];
@@ -218,18 +236,17 @@ class sspmod_radius_Auth_Source_Radius extends sspmod_core_Auth_UserPassBase
                 continue;
             }
 
-            $attrib_name = strtok($datav,'=');
+            $attrib_name = strtok($datav, '=');
             $attrib_value = strtok('=');
 
-            /* if the attribute name is already in result set,
-                add another value */
+            // if the attribute name is already in result set, add another value
             if (array_key_exists($attrib_name, $attributes)) {
                 $attributes[$attrib_name][] = $attrib_value;
             } else {
-                $attributes[$attrib_name] = array($attrib_value);
+                $attributes[$attrib_name] = [$attrib_value];
             }
         }
-        /* end of contribution */
+        // end of contribution
 
         return $attributes;
     }
diff --git a/modules/riak/config-templates/module_riak.php b/modules/riak/config-templates/module_riak.php
index 33be27efedcb85e4edcadbb92cad3e37cc9cd469..99f535fee579d461b295c9bfcc90234f3d4cf099 100644
--- a/modules/riak/config-templates/module_riak.php
+++ b/modules/riak/config-templates/module_riak.php
@@ -4,13 +4,13 @@
  *
  */
 
-$config = array (
-	/*
-	 * This module has the following config options and defaults.
-	 *
-	 * 'path' => 'riak-php-client/riak.php',
-	 * 'host' => 'localhost',
-	 * 'port' => 8098,
-	 * 'bucket' => 'SimpleSAMLphp',
-	 */
-);
+$config = [
+    /*
+     * This module has the following config options and defaults.
+     *
+     * 'path' => 'riak-php-client/riak.php',
+     * 'host' => 'localhost',
+     * 'port' => 8098,
+     * 'bucket' => 'SimpleSAMLphp',
+     */
+];
diff --git a/modules/riak/hooks/hook_cron.php b/modules/riak/hooks/hook_cron.php
index 6e1ab68fcc75ebdc419c2892c3cbb65abe9f770d..c42d2c313e75b66cb6855a2b353e7033e1ebdff9 100644
--- a/modules/riak/hooks/hook_cron.php
+++ b/modules/riak/hooks/hook_cron.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\riak;
+
 /*
  * Copyright (c) 2012 The University of Queensland
  *
@@ -22,32 +24,34 @@
  * and Information Technology.
  */
 
-
 /**
  * Hook to run a cron job.
  *
  * @param array &$croninfo  Output
  */
-function riak_hook_cron(&$croninfo) {
-	assert(is_array($croninfo));
-	assert(array_key_exists('summary', $croninfo));
-	assert(array_key_exists('tag', $croninfo));
+function riak_hook_cron(&$croninfo)
+{
+    assert(is_array($croninfo));
+    assert(array_key_exists('summary', $croninfo));
+    assert(array_key_exists('tag', $croninfo));
 
-	if ($croninfo['tag'] !== 'hourly') return;
+    if ($croninfo['tag'] !== 'hourly') {
+        return;
+    }
 
-	try {
-		$store = new sspmod_riak_Store_Store();
-		$result = $store->bucket->indexSearch('expires', 'int',
-		    1, time() - 30);
-		foreach ($result as $link) {
-			$link->getBinary()->delete();
-		}
+    try {
+        $store = new \SimpleSAML\Module\riak\Store\Store();
+        $result = $store->bucket->indexSearch('expires', 'int', 1, time() - 30);
+        foreach ($result as $link) {
+            $link->getBinary()->delete();
+        }
 
-		SimpleSAML\Logger::info(sprintf("deleted %s riak key%s",
-		    sizeof($result), sizeof($result) == 1 ? '' : 's'));
-	} catch (Exception $e) {
-		$message = 'riak threw exception: ' . $e->getMessage();
-		SimpleSAML\Logger::warning($message);
-		$croninfo['summary'][] = $message;
-	}
+        \SimpleSAML\Logger::info(
+            sprintf("deleted %s riak key%s", sizeof($result), sizeof($result) == 1 ? '' : 's')
+        );
+    } catch (\Exception $e) {
+        $message = 'riak threw exception: '.$e->getMessage();
+        \SimpleSAML\Logger::warning($message);
+        $croninfo['summary'][] = $message;
+    }
 }
diff --git a/modules/riak/lib/Store/Store.php b/modules/riak/lib/Store/Store.php
index baa44039344582aaaac0fd3dd79c33a984d6c01b..c44f599502e9bea7073e5ce84d164ebd4f782ee8 100644
--- a/modules/riak/lib/Store/Store.php
+++ b/modules/riak/lib/Store/Store.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\riak\Store;
+
 /*
  * Copyright (c) 2012 The University of Queensland
  *
@@ -22,90 +24,88 @@
  * and Information Technology.
  */
 
-class sspmod_riak_Store_Store extends SimpleSAML\Store
+class Store extends \SimpleSAML\Store
 {
     public $client;
     public $bucket;
 
-	protected function __construct()
+    protected function __construct()
     {
-		$config = SimpleSAML_Configuration::getConfig('module_riak.php');
-
-		$path = $config->getString('path', 'riak-php-client/riak.php');
-		$host = $config->getString('host', 'localhost');
-		$port = $config->getString('port', 8098);
-		$bucket = $config->getString('bucket', 'simpleSAMLphp');
-
-		require_once($path);
-		$this->client = new \RiakClient($host, $port);
-		$this->bucket = $this->client->bucket($bucket);
-	}
-
-	/**
-	 * Retrieve a value from the datastore.
-	 *
-	 * @param string $type  The datatype.
-	 * @param string $key  The key.
-	 * @return mixed|NULL  The value.
-	 */
-	public function get($type, $key)
+        $config = \SimpleSAML\Configuration::getConfig('module_riak.php');
+
+        $path = $config->getString('path', 'riak-php-client/riak.php');
+        $host = $config->getString('host', 'localhost');
+        $port = $config->getString('port', 8098);
+        $bucket = $config->getString('bucket', 'simpleSAMLphp');
+
+        require_once($path);
+        $this->client = new \RiakClient($host, $port);
+        $this->bucket = $this->client->bucket($bucket);
+    }
+
+    /**
+     * Retrieve a value from the datastore.
+     *
+     * @param string $type  The datatype.
+     * @param string $key  The key.
+     * @return mixed|NULL  The value.
+     */
+    public function get($type, $key)
     {
-		assert(is_string($type));
-		assert(is_string($key));
-
-		$v = $this->bucket->getBinary("$type.$key");
-		if (!$v->exists()) {
-			return null;
-		}
-
-		$expires = $v->getIndex('Expires', 'int');
-		if (sizeof($expires) && (int)array_shift($expires) <= time()) {
-			$v->delete();
-			return null;
-		}
-
-		return (unserialize($v->getData()));
-	}
-
-
-	/**
-	 * Save a value to the datastore.
-	 *
-	 * @param string $type  The datatype.
-	 * @param string $key  The key.
-	 * @param mixed $value  The value.
-	 * @param int|NULL $expire  The expiration time (unix timestamp), or NULL if it never expires.
-	 */
-	public function set($type, $key, $value, $expire = null)
+        assert(is_string($type));
+        assert(is_string($key));
+
+        $v = $this->bucket->getBinary("$type.$key");
+        if (!$v->exists()) {
+            return null;
+        }
+
+        $expires = $v->getIndex('Expires', 'int');
+        if (sizeof($expires) && (int) array_shift($expires) <= time()) {
+            $v->delete();
+            return null;
+        }
+
+        return (unserialize($v->getData()));
+    }
+
+    /**
+     * Save a value to the datastore.
+     *
+     * @param string $type  The datatype.
+     * @param string $key  The key.
+     * @param mixed $value  The value.
+     * @param int|NULL $expire  The expiration time (unix timestamp), or NULL if it never expires.
+     */
+    public function set($type, $key, $value, $expire = null)
     {
-		assert(is_string($type));
-		assert(is_string($key));
-		assert($expire === null || (is_int($expire) && $expire > 2592000));
-
-		$v = $this->bucket->newBinary("$type.$key", serialize($value), 'application/php');
-		if (!is_null($expire)) {
-			$v->addIndex("Expires", "int", $expire);
-		}
-
-		$v->store();
-	}
-
-	/**
-	 * Delete a value from the datastore.
-	 *
-	 * @param string $type  The datatype.
-	 * @param string $key  The key.
-	 */
-	public function delete($type, $key)
+        assert(is_string($type));
+        assert(is_string($key));
+        assert($expire === null || (is_int($expire) && $expire > 2592000));
+
+        $v = $this->bucket->newBinary("$type.$key", serialize($value), 'application/php');
+        if (!is_null($expire)) {
+            $v->addIndex("Expires", "int", $expire);
+        }
+
+        $v->store();
+    }
+
+    /**
+     * Delete a value from the datastore.
+     *
+     * @param string $type  The datatype.
+     * @param string $key  The key.
+     */
+    public function delete($type, $key)
     {
-		assert(is_string($type));
-		assert(is_string($key));
-
-		$v = $this->bucket->getBinary("$type.$key");
-		if (!$v->exists()) {
-			return;
-		}
-
-		$v->delete();
-	}
+        assert(is_string($type));
+        assert(is_string($key));
+
+        $v = $this->bucket->getBinary("$type.$key");
+        if (!$v->exists()) {
+            return;
+        }
+        $v->delete();
+    }
 }
diff --git a/modules/saml/docs/authproc_authncontextclassref.md b/modules/saml/docs/authproc_authncontextclassref.md
new file mode 100644
index 0000000000000000000000000000000000000000..5e755a88b5d0aaa34de70f8c5f08463cb4d1b704
--- /dev/null
+++ b/modules/saml/docs/authproc_authncontextclassref.md
@@ -0,0 +1,14 @@
+`saml:AuthnContextClassRef`
+===========================
+
+IDP-side filter for setting the `AuthnContextClassRef` element in the authentication response.
+
+Examples
+--------
+
+    'authproc.idp' => array(
+      92 => array(
+        'class' => 'saml:AuthnContextClassRef',
+        'AuthnContextClassRef' => 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport',
+      ),
+    ),
diff --git a/modules/saml/docs/sp.md b/modules/saml/docs/sp.md
index f72df230ec97a590325a073e4e599cb0a29e8e06..9ee03c584d827514ec4b4c0014a8ba8c0b9bf5f9 100644
--- a/modules/saml/docs/sp.md
+++ b/modules/saml/docs/sp.md
@@ -125,6 +125,13 @@ Options
 `attributes.NameFormat`
 :   The `NameFormat` for the requested attributes.
 
+`attributes.index`
+:   The `index` attribute that is set in the md:AttributeConsumingService element. Integer value that defaults to `0`.
+
+`attributes.isDefault`
+:   If present, sets the `isDefault` attribute in the md:AttributeConsumingService element. Boolean value, when
+    unset, the attribute will be omitted.
+
 `attributes.required`
 : If you have attributes added you can here specify which should be marked as required.
 : The attributes should still be present in `attributes`.
@@ -362,12 +369,13 @@ Options
 :   *Note*: SAML 2 specific.
 
 `signature.algorithm`
-:   The algorithm to use when signing any message generated by this service provider. Defaults to RSA-SHA1.
+:   The algorithm to use when signing any message generated by this service provider. Defaults to RSA-SHA256.
 :   Possible values:
 
     * `http://www.w3.org/2000/09/xmldsig#rsa-sha1`
        *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256`
+      The default.
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384`
     * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512`
 
@@ -460,7 +468,7 @@ Here we will list some examples for this authentication source.
             // Specify friendly names for these attributes:
             'sn' => 'urn:oid:2.5.4.4',
             'givenName' => 'urn:oid:2.5.4.42',
-        )
+        ),
         'attributes.required' => array (
             'eduPersonPrincipalName',
         ),
diff --git a/modules/saml/hooks/hook_metadata_hosted.php b/modules/saml/hooks/hook_metadata_hosted.php
index 510a8133d9f270e876f25570ed2310009836746b..e1dc65c36f81892947e651fc296020ad3bfb7090 100644
--- a/modules/saml/hooks/hook_metadata_hosted.php
+++ b/modules/saml/hooks/hook_metadata_hosted.php
@@ -6,10 +6,11 @@
  * @param array &$metadataHosted  The metadata links for hosted metadata on the frontpage.
  */
 
-function saml_hook_metadata_hosted(&$metadataHosted) {
+function saml_hook_metadata_hosted(&$metadataHosted)
+{
     assert(is_array($metadataHosted));
 
-    $sources = SimpleSAML_Auth_Source::getSourcesOfType('saml:SP');
+    $sources = \SimpleSAML\Auth\Source::getSourcesOfType('saml:SP');
 
     foreach ($sources as $source) {
         $metadata = $source->getMetadata();
@@ -19,16 +20,16 @@ function saml_hook_metadata_hosted(&$metadataHosted) {
             $name = $metadata->getValue('OrganizationDisplayName', null);
         }
         if ($name === null) {
-            $name = $source->getAuthID();
+            $name = $source->getAuthId();
         }
 
-        $md = array(
+        $md = [
             'entityid' => $source->getEntityId(),
             'metadata-index' => $source->getEntityId(),
             'metadata-set' => 'saml20-sp-hosted',
-            'metadata-url' => $source->getMetadataURL() . '?output=xhtml',
+            'metadata-url' => $source->getMetadataURL().'?output=xhtml',
             'name' => $name,
-        );
+        ];
 
         $metadataHosted[] = $md;
     }
diff --git a/modules/saml/lib/Auth/Process/AttributeNameID.php b/modules/saml/lib/Auth/Process/AttributeNameID.php
index 1bb86a74e9669cc0af8a7ef9297bb5b746cd4a86..fbb5669a80e3a4ca04503f729151d8262b69b6a0 100644
--- a/modules/saml/lib/Auth/Process/AttributeNameID.php
+++ b/modules/saml/lib/Auth/Process/AttributeNameID.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to create a NameID from an attribute.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGenerator
-{
 
+class AttributeNameID extends \SimpleSAML\Module\saml\BaseNameIDGenerator
+{
     /**
      * The attribute we should use as the NameID.
      *
@@ -23,7 +24,7 @@ class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGen
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception If the required options 'Format' or 'attribute' are missing.
+     * @throws \SimpleSAMLError\Exception If the required options 'Format' or 'attribute' are missing.
      */
     public function __construct($config, $reserved)
     {
@@ -31,12 +32,12 @@ class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGen
         assert(is_array($config));
 
         if (!isset($config['Format'])) {
-            throw new SimpleSAML_Error_Exception("AttributeNameID: Missing required option 'Format'.");
+            throw new \SimpleSAML\Error\Exception("AttributeNameID: Missing required option 'Format'.");
         }
         $this->format = (string) $config['Format'];
 
         if (!isset($config['attribute'])) {
-            throw new SimpleSAML_Error_Exception("AttributeNameID: Missing required option 'attribute'.");
+            throw new \SimpleSAML\Error\Exception("AttributeNameID: Missing required option 'attribute'.");
         }
         $this->attribute = (string) $config['attribute'];
     }
@@ -52,14 +53,14 @@ class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGen
     {
 
         if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Missing attribute '.var_export($this->attribute, true).
                 ' on user - not generating attribute NameID.'
             );
             return null;
         }
         if (count($state['Attributes'][$this->attribute]) > 1) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'More than one value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating attribute NameID.'
             );
@@ -69,7 +70,7 @@ class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGen
         $value = $value[0];
 
         if (empty($value)) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Empty value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
@@ -78,5 +79,4 @@ class sspmod_saml_Auth_Process_AttributeNameID extends sspmod_saml_BaseNameIDGen
 
         return $value;
     }
-
 }
diff --git a/modules/saml/lib/Auth/Process/AuthnContextClassRef.php b/modules/saml/lib/Auth/Process/AuthnContextClassRef.php
index d1ebbf0efe3dc582a02bf92cd5d9e37b27504dbd..106d7b51f06f7472ece5bc013f6f38e3fa938958 100644
--- a/modules/saml/lib/Auth/Process/AuthnContextClassRef.php
+++ b/modules/saml/lib/Auth/Process/AuthnContextClassRef.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Filter for setting the AuthnContextClassRef in the response.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_AuthnContextClassRef extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class AuthnContextClassRef extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * The URI we should set as the AuthnContextClassRef in the login response.
      *
@@ -23,7 +24,7 @@ class sspmod_saml_Auth_Process_AuthnContextClassRef extends SimpleSAML_Auth_Proc
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception if the mandatory 'AuthnContextClassRef' option is missing.
+     * @throws \SimpleSAML\Error\_Exception if the mandatory 'AuthnContextClassRef' option is missing.
      */
     public function __construct($config, $reserved)
     {
@@ -31,7 +32,7 @@ class sspmod_saml_Auth_Process_AuthnContextClassRef extends SimpleSAML_Auth_Proc
         assert(is_array($config));
 
         if (!isset($config['AuthnContextClassRef'])) {
-            throw new SimpleSAML_Error_Exception('Missing AuthnContextClassRef option in processing filter.');
+            throw new \SimpleSAML\Error\Exception('Missing AuthnContextClassRef option in processing filter.');
         }
 
         $this->authnContextClassRef = (string) $config['AuthnContextClassRef'];
diff --git a/modules/saml/lib/Auth/Process/ExpectedAuthnContextClassRef.php b/modules/saml/lib/Auth/Process/ExpectedAuthnContextClassRef.php
index b8e77dc709c354a7d9ed0b4a0583bed1604fa80a..fd6277732326b7bfad1cc82bce053b7f3d217b85 100644
--- a/modules/saml/lib/Auth/Process/ExpectedAuthnContextClassRef.php
+++ b/modules/saml/lib/Auth/Process/ExpectedAuthnContextClassRef.php
@@ -1,5 +1,6 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Attribute filter to validate AuthnContextClassRef values.
@@ -16,9 +17,9 @@
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_ExpectedAuthnContextClassRef extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class ExpectedAuthnContextClassRef extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * Array of accepted AuthnContextClassRef
      * @var array
@@ -39,7 +40,7 @@ class sspmod_saml_Auth_Process_ExpectedAuthnContextClassRef extends SimpleSAML_A
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception if the mandatory 'accepted' configuration option is missing.
+     * @throws \SimpleSAML\Error\Exception if the mandatory 'accepted' configuration option is missing.
      */
     public function __construct($config, $reserved)
     {
@@ -47,10 +48,10 @@ class sspmod_saml_Auth_Process_ExpectedAuthnContextClassRef extends SimpleSAML_A
 
         assert(is_array($config));
         if (empty($config['accepted'])) {
-            SimpleSAML\Logger::error(
+            \SimpleSAML\Logger::error(
                 'ExpectedAuthnContextClassRef: Configuration error. There is no accepted AuthnContextClassRef.'
             );
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'ExpectedAuthnContextClassRef: Configuration error. There is no accepted AuthnContextClassRef.'
             );
         }
@@ -89,15 +90,15 @@ class sspmod_saml_Auth_Process_ExpectedAuthnContextClassRef extends SimpleSAML_A
      */
     protected function unauthorized(&$request)
     {
-        SimpleSAML\Logger::error(
+        \SimpleSAML\Logger::error(
             'ExpectedAuthnContextClassRef: Invalid authentication context: '.$this->AuthnContextClassRef.
             '. Accepted values are: '.var_export($this->accepted, true)
         );
 
-        $id = SimpleSAML_Auth_State::saveState($request, 'saml:ExpectedAuthnContextClassRef:unauthorized');
-        $url = SimpleSAML\Module::getModuleURL(
+        $id = \SimpleSAML\Auth\State::saveState($request, 'saml:ExpectedAuthnContextClassRef:unauthorized');
+        $url = \SimpleSAML\Module::getModuleURL(
             'saml/sp/wrong_authncontextclassref.php'
         );
-        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('StateId' => $id));
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['StateId' => $id]);
     }
 }
diff --git a/modules/saml/lib/Auth/Process/FilterScopes.php b/modules/saml/lib/Auth/Process/FilterScopes.php
index 3f497e1e96cdc9d7ab404ba636271a89d9df23e7..67ef886df09e4dec683df2fbced1bf02d6c1ca44 100644
--- a/modules/saml/lib/Auth/Process/FilterScopes.php
+++ b/modules/saml/lib/Auth/Process/FilterScopes.php
@@ -11,16 +11,16 @@ use SimpleSAML\Logger;
  * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no>
  * @package SimpleSAMLphp
  */
-class FilterScopes extends \SimpleSAML_Auth_ProcessingFilter
-{
 
+class FilterScopes extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * Stores any pre-configured scoped attributes which come from the filter configuration.
      */
-    private $scopedAttributes = array(
+    private $scopedAttributes = [
         'eduPersonScopedAffiliation',
         'eduPersonPrincipalName'
-    );
+    ];
 
 
     /**
@@ -53,7 +53,7 @@ class FilterScopes extends \SimpleSAML_Auth_ProcessingFilter
             Logger::warning('No scoped attributes configured.');
             return;
         }
-        $validScopes = array();
+        $validScopes = [];
         if (array_key_exists('scope', $src) && is_array($src['scope']) && !empty($src['scope'])) {
             $validScopes = $src['scope'];
         }
@@ -64,7 +64,7 @@ class FilterScopes extends \SimpleSAML_Auth_ProcessingFilter
             }
 
             $values = $request['Attributes'][$attribute];
-            $newValues = array();
+            $newValues = [];
             foreach ($values as $value) {
                 $ep = \SimpleSAML\Utils\Config\Metadata::getDefaultEndpoint($request['Source']['SingleSignOnService']);
                 $loc = $ep['Location'];
diff --git a/modules/saml/lib/Auth/Process/NameIDAttribute.php b/modules/saml/lib/Auth/Process/NameIDAttribute.php
index c3c6bf4706130939ee5c789dae26b037434d097e..e1455b214d4e6bd3604b762eef6868362f39f3b6 100644
--- a/modules/saml/lib/Auth/Process/NameIDAttribute.php
+++ b/modules/saml/lib/Auth/Process/NameIDAttribute.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to create an attribute from a NameID.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_NameIDAttribute extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class NameIDAttribute extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * The attribute we should save the NameID in.
      *
@@ -58,13 +59,13 @@ class sspmod_saml_Auth_Process_NameIDAttribute extends SimpleSAML_Auth_Processin
      * @param string $format The format string.
      * @return array The format string broken into its individual components.
      *
-     * @throws SimpleSAML_Error_Exception if the replacement is invalid.
+     * @throws \SimpleSAML\Error\Exception if the replacement is invalid.
      */
     private static function parseFormat($format)
     {
         assert(is_string($format));
 
-        $ret = array();
+        $ret = [];
         $pos = 0;
         while (($next = strpos($format, '%', $pos)) !== false) {
             $ret[] = substr($format, $pos, $next - $pos);
@@ -87,7 +88,7 @@ class sspmod_saml_Auth_Process_NameIDAttribute extends SimpleSAML_Auth_Processin
                     $ret[] = '%';
                     break;
                 default:
-                    throw new SimpleSAML_Error_Exception('NameIDAttribute: Invalid replacement: "%'.$replacement.'"');
+                    throw new \SimpleSAML\Error\Exception('NameIDAttribute: Invalid replacement: "%'.$replacement.'"');
             }
 
             $pos = $next + 2;
@@ -138,6 +139,6 @@ class sspmod_saml_Auth_Process_NameIDAttribute extends SimpleSAML_Auth_Processin
             $isString = !$isString;
         }
 
-        $state['Attributes'][$this->attribute] = array($value);
+        $state['Attributes'][$this->attribute] = [$value];
     }
 }
diff --git a/modules/saml/lib/Auth/Process/PersistentNameID.php b/modules/saml/lib/Auth/Process/PersistentNameID.php
index 4d6d0bc2260ac4e8e72a458066cb888f4f9f6539..a70c7493291050a32e215c20e888017d3ad4748b 100644
--- a/modules/saml/lib/Auth/Process/PersistentNameID.php
+++ b/modules/saml/lib/Auth/Process/PersistentNameID.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to generate a persistent NameID.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_PersistentNameID extends sspmod_saml_BaseNameIDGenerator
-{
 
+class PersistentNameID extends \SimpleSAML\Module\saml\BaseNameIDGenerator
+{
     /**
      * Which attribute contains the unique identifier of the user.
      *
@@ -23,7 +24,7 @@ class sspmod_saml_Auth_Process_PersistentNameID extends sspmod_saml_BaseNameIDGe
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception If the required option 'attribute' is missing.
+     * @throws \SimpleSAML\Error\Exception If the required option 'attribute' is missing.
      */
     public function __construct($config, $reserved)
     {
@@ -33,7 +34,7 @@ class sspmod_saml_Auth_Process_PersistentNameID extends sspmod_saml_BaseNameIDGe
         $this->format = \SAML2\Constants::NAMEID_PERSISTENT;
 
         if (!isset($config['attribute'])) {
-            throw new SimpleSAML_Error_Exception("PersistentNameID: Missing required option 'attribute'.");
+            throw new \SimpleSAML\Error\Exception("PersistentNameID: Missing required option 'attribute'.");
         }
         $this->attribute = $config['attribute'];
     }
@@ -47,28 +48,27 @@ class sspmod_saml_Auth_Process_PersistentNameID extends sspmod_saml_BaseNameIDGe
      */
     protected function getValue(array &$state)
     {
-
         if (!isset($state['Destination']['entityid'])) {
-            SimpleSAML\Logger::warning('No SP entity ID - not generating persistent NameID.');
+            \SimpleSAML\Logger::warning('No SP entity ID - not generating persistent NameID.');
             return null;
         }
         $spEntityId = $state['Destination']['entityid'];
 
         if (!isset($state['Source']['entityid'])) {
-            SimpleSAML\Logger::warning('No IdP entity ID - not generating persistent NameID.');
+            \SimpleSAML\Logger::warning('No IdP entity ID - not generating persistent NameID.');
             return null;
         }
         $idpEntityId = $state['Source']['entityid'];
 
         if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Missing attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
             return null;
         }
         if (count($state['Attributes'][$this->attribute]) > 1) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'More than one value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
@@ -78,14 +78,14 @@ class sspmod_saml_Auth_Process_PersistentNameID extends sspmod_saml_BaseNameIDGe
         $uid = $uid[0];
 
         if (empty($uid)) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Empty value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
             return null;
         }
 
-        $secretSalt = SimpleSAML\Utils\Config::getSecretSalt();
+        $secretSalt = \SimpleSAML\Utils\Config::getSecretSalt();
 
         $uidData = 'uidhashbase'.$secretSalt;
         $uidData .= strlen($idpEntityId).':'.$idpEntityId;
diff --git a/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
index 604c2214713adf5edee4694b93289b6e845bf13d..d07d8ee0a0245a76582ccf08589ca8e944526ba8 100644
--- a/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
+++ b/modules/saml/lib/Auth/Process/PersistentNameID2TargetedID.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to create the eduPersonTargetedID attribute from the persistent NameID.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_PersistentNameID2TargetedID extends SimpleSAML_Auth_ProcessingFilter
-{
 
+class PersistentNameID2TargetedID extends \SimpleSAML\Auth\ProcessingFilter
+{
     /**
      * The attribute we should save the NameID in.
      *
@@ -60,7 +61,7 @@ class sspmod_saml_Auth_Process_PersistentNameID2TargetedID extends SimpleSAML_Au
         assert(is_array($state));
 
         if (!isset($state['saml:NameID'][\SAML2\Constants::NAMEID_PERSISTENT])) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Unable to generate eduPersonTargetedID because no persistent NameID was available.'
             );
             return;
@@ -69,6 +70,6 @@ class sspmod_saml_Auth_Process_PersistentNameID2TargetedID extends SimpleSAML_Au
         /** @var \SAML2\XML\saml\NameID $nameID */
         $nameID = $state['saml:NameID'][\SAML2\Constants::NAMEID_PERSISTENT];
 
-        $state['Attributes'][$this->attribute] = array((!$this->nameId) ? $nameID->value : $nameID);
+        $state['Attributes'][$this->attribute] = [(!$this->nameId) ? $nameID->value : $nameID];
     }
 }
diff --git a/modules/saml/lib/Auth/Process/SQLPersistentNameID.php b/modules/saml/lib/Auth/Process/SQLPersistentNameID.php
index ecbb5a69ae974fb89333920e0f8755788e8e2e1a..172aace1c243957996a2c5677b49f49d7a1aff1b 100644
--- a/modules/saml/lib/Auth/Process/SQLPersistentNameID.php
+++ b/modules/saml/lib/Auth/Process/SQLPersistentNameID.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to generate a persistent NameID.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameIDGenerator
-{
 
+class SQLPersistentNameID extends \SimpleSAML\Module\saml\BaseNameIDGenerator
+{
     /**
      * Which attribute contains the unique identifier of the user.
      *
@@ -44,7 +45,7 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
      * @param array $config Configuration information about this filter.
      * @param mixed $reserved For future use.
      *
-     * @throws SimpleSAML_Error_Exception If the 'attribute' option is not specified.
+     * @throws \SimpleSAML\Error\Exception If the 'attribute' option is not specified.
      */
     public function __construct($config, $reserved)
     {
@@ -54,7 +55,7 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
         $this->format = \SAML2\Constants::NAMEID_PERSISTENT;
 
         if (!isset($config['attribute'])) {
-            throw new SimpleSAML_Error_Exception("PersistentNameID: Missing required option 'attribute'.");
+            throw new \SimpleSAML\Error\Exception("PersistentNameID: Missing required option 'attribute'.");
         }
         $this->attribute = $config['attribute'];
 
@@ -78,27 +79,27 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
      * @param array $state The state array.
      * @return string|null The NameID value.
      *
-     * @throws sspmod_saml_Error if the NameID creation policy is invalid.
+     * @throws \SimpleSAML\Module\saml\Error if the NameID creation policy is invalid.
      */
     protected function getValue(array &$state)
     {
 
         if (!isset($state['saml:NameIDFormat']) && !$this->allowUnspecified) {
-            SimpleSAML\Logger::debug(
+            \SimpleSAML\Logger::debug(
                 'SQLPersistentNameID: Request did not specify persistent NameID format, '.
                 'not generating persistent NameID.'
             );
             return null;
         }
 
-        $validNameIdFormats = @array_filter(array(
+        $validNameIdFormats = @array_filter([
             $state['saml:NameIDFormat'],
             $state['SPMetadata']['NameIDFormat']
-        ));
+        ]);
         if (count($validNameIdFormats) && !in_array($this->format, $validNameIdFormats, true) &&
             !$this->allowDifferent
         ) {
-            SimpleSAML\Logger::debug(
+            \SimpleSAML\Logger::debug(
                 'SQLPersistentNameID: SP expects different NameID format ('.
                 implode(', ', $validNameIdFormats).'),  not generating persistent NameID.'
             );
@@ -106,26 +107,26 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
         }
 
         if (!isset($state['Destination']['entityid'])) {
-            SimpleSAML\Logger::warning('SQLPersistentNameID: No SP entity ID - not generating persistent NameID.');
+            \SimpleSAML\Logger::warning('SQLPersistentNameID: No SP entity ID - not generating persistent NameID.');
             return null;
         }
         $spEntityId = $state['Destination']['entityid'];
 
         if (!isset($state['Source']['entityid'])) {
-            SimpleSAML\Logger::warning('SQLPersistentNameID: No IdP entity ID - not generating persistent NameID.');
+            \SimpleSAML\Logger::warning('SQLPersistentNameID: No IdP entity ID - not generating persistent NameID.');
             return null;
         }
         $idpEntityId = $state['Source']['entityid'];
 
         if (!isset($state['Attributes'][$this->attribute]) || count($state['Attributes'][$this->attribute]) === 0) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'SQLPersistentNameID: Missing attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
             return null;
         }
         if (count($state['Attributes'][$this->attribute]) > 1) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'SQLPersistentNameID: More than one value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
@@ -135,16 +136,16 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
         $uid = $uid[0];
 
         if (empty($uid)) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'Empty value in attribute '.var_export($this->attribute, true).
                 ' on user - not generating persistent NameID.'
             );
             return null;
         }
 
-        $value = sspmod_saml_IdP_SQLNameID::get($idpEntityId, $spEntityId, $uid);
+        $value = \SimpleSAML\Module\saml\IdP\SQLNameID::get($idpEntityId, $spEntityId, $uid);
         if ($value !== null) {
-            SimpleSAML\Logger::debug(
+            \SimpleSAML\Logger::debug(
                 'SQLPersistentNameID: Found persistent NameID '.var_export($value, true).' for user '.
                 var_export($uid, true).'.'
             );
@@ -152,21 +153,21 @@ class sspmod_saml_Auth_Process_SQLPersistentNameID extends sspmod_saml_BaseNameI
         }
 
         if ((!isset($state['saml:AllowCreate']) || !$state['saml:AllowCreate']) && !$this->alwaysCreate) {
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 'SQLPersistentNameID: Did not find persistent NameID for user, and not allowed to create new NameID.'
             );
-            throw new sspmod_saml_Error(
+            throw new \SimpleSAML\Module\saml\Error(
                 \SAML2\Constants::STATUS_RESPONDER,
                 'urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy'
             );
         }
 
         $value = bin2hex(openssl_random_pseudo_bytes(20));
-        SimpleSAML\Logger::debug(
+        \SimpleSAML\Logger::debug(
             'SQLPersistentNameID: Created persistent NameID '.var_export($value, true).' for user '.
             var_export($uid, true).'.'
         );
-        sspmod_saml_IdP_SQLNameID::add($idpEntityId, $spEntityId, $uid, $value);
+        \SimpleSAML\Module\saml\IdP\SQLNameID::add($idpEntityId, $spEntityId, $uid, $value);
 
         return $value;
     }
diff --git a/modules/saml/lib/Auth/Process/TransientNameID.php b/modules/saml/lib/Auth/Process/TransientNameID.php
index c43c19a00a6501c3a91f4abb9d2ec31800640797..b4a24de5ecc08fa5d1cc41d1561460f107c5a28b 100644
--- a/modules/saml/lib/Auth/Process/TransientNameID.php
+++ b/modules/saml/lib/Auth/Process/TransientNameID.php
@@ -1,14 +1,15 @@
 <?php
 
+namespace SimpleSAML\Module\saml\Auth\Process;
 
 /**
  * Authentication processing filter to generate a transient NameID.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Auth_Process_TransientNameID extends sspmod_saml_BaseNameIDGenerator
-{
 
+class TransientNameID extends \SimpleSAML\Module\saml\BaseNameIDGenerator
+{
     /**
      * Initialize this filter, parse configuration
      *
@@ -32,6 +33,6 @@ class sspmod_saml_Auth_Process_TransientNameID extends sspmod_saml_BaseNameIDGen
      */
     protected function getValue(array &$state)
     {
-        return SimpleSAML\Utils\Random::generateID();
+        return \SimpleSAML\Utils\Random::generateID();
     }
 }
diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php
index 6f14f5c55b9c7becece9c8d3ac574e3da92f89b1..791fe76213a4a8bf94dc82245818645c80c188dd 100644
--- a/modules/saml/lib/Auth/Source/SP.php
+++ b/modules/saml/lib/Auth/Source/SP.php
@@ -1,6 +1,11 @@
 <?php
 
-class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
+namespace SimpleSAML\Module\saml\Auth\Source;
+
+use SimpleSAML\Auth\Source;
+use SimpleSAML\Auth\State;
+
+class SP extends Source
 {
     /**
      * The entity ID of this SP.
@@ -12,7 +17,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
     /**
      * The metadata of this SP.
      *
-     * @var SimpleSAML_Configuration.
+     * @var \SimpleSAML\Configuration
      */
     private $metadata;
 
@@ -52,14 +57,16 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
          * gives the entity id. */
         $config['entityid'] = $config['entityID'];
 
-        $this->metadata = SimpleSAML_Configuration::loadFromArray($config,
-            'authsources[' . var_export($this->authId, true) . ']');
+        $this->metadata = \SimpleSAML\Configuration::loadFromArray(
+            $config,
+            'authsources['.var_export($this->authId, true).']'
+        );
         $this->entityId = $this->metadata->getString('entityID');
         $this->idp = $this->metadata->getString('idp', null);
         $this->discoURL = $this->metadata->getString('discoURL', null);
 
-        if (empty($this->discoURL) && SimpleSAML\Module::isModuleEnabled('discojuice')) {
-            $this->discoURL = SimpleSAML\Module::getModuleURL('discojuice/central.php');
+        if (empty($this->discoURL) && \SimpleSAML\Module::isModuleEnabled('discojuice')) {
+            $this->discoURL = \SimpleSAML\Module::getModuleURL('discojuice/central.php');
         }
     }
 
@@ -70,7 +77,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      */
     public function getMetadataURL()
     {
-        return SimpleSAML\Module::getModuleURL('saml/sp/metadata.php/' . urlencode($this->authId));
+        return \SimpleSAML\Module::getModuleURL('saml/sp/metadata.php/'.urlencode($this->authId));
     }
 
     /**
@@ -86,7 +93,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
     /**
      * Retrieve the metadata of this SP.
      *
-     * @return SimpleSAML_Configuration  The metadata of this SP.
+     * @return \SimpleSAML\Configuration  The metadata of this SP.
      */
     public function getMetadata()
     {
@@ -97,48 +104,47 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      * Retrieve the metadata of an IdP.
      *
      * @param string $entityId  The entity id of the IdP.
-     * @return SimpleSAML_Configuration  The metadata of the IdP.
+     * @return \SimpleSAML\Configuration  The metadata of the IdP.
      */
     public function getIdPMetadata($entityId)
     {
         assert(is_string($entityId));
 
         if ($this->idp !== null && $this->idp !== $entityId) {
-            throw new SimpleSAML_Error_Exception('Cannot retrieve metadata for IdP ' .
-                var_export($entityId, true) .
-                ' because it isn\'t a valid IdP for this SP.');
+            throw new \SimpleSAML\Error\Exception('Cannot retrieve metadata for IdP '.
+                var_export($entityId, true).' because it isn\'t a valid IdP for this SP.');
         }
 
-        $metadataHandler = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadataHandler = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
         // First, look in saml20-idp-remote.
         try {
             return $metadataHandler->getMetaDataConfig($entityId, 'saml20-idp-remote');
-        } catch (Exception $e) {
-            /* Metadata wasn't found. */
-            SimpleSAML\Logger::debug('getIdpMetadata: ' . $e->getMessage());
+        } catch (\Exception $e) {
+            // Metadata wasn't found
+            \SimpleSAML\Logger::debug('getIdpMetadata: '.$e->getMessage());
         }
 
-        /* Not found in saml20-idp-remote, look in shib13-idp-remote. */
+        // Not found in saml20-idp-remote, look in shib13-idp-remote
         try {
             return $metadataHandler->getMetaDataConfig($entityId, 'shib13-idp-remote');
-        } catch (Exception $e) {
-            /* Metadata wasn't found. */
-            SimpleSAML\Logger::debug('getIdpMetadata: ' . $e->getMessage());
+        } catch (\Exception $e) {
+            // Metadata wasn't found
+            \SimpleSAML\Logger::debug('getIdpMetadata: '.$e->getMessage());
         }
 
-        /* Not found. */
-        throw new SimpleSAML_Error_Exception('Could not find the metadata of an IdP with entity ID ' .
+        // Not found
+        throw new \SimpleSAML\Error\Exception('Could not find the metadata of an IdP with entity ID '.
             var_export($entityId, true));
     }
 
     /**
      * Send a SAML1 SSO request to an IdP.
      *
-     * @param SimpleSAML_Configuration $idpMetadata  The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $idpMetadata  The metadata of the IdP.
      * @param array $state  The state array for the current authentication.
      */
-    private function startSSO1(SimpleSAML_Configuration $idpMetadata, array $state)
+    private function startSSO1(\SimpleSAML\Configuration $idpMetadata, array $state)
     {
         $idpEntityId = $idpMetadata->getString('entityid');
 
@@ -147,7 +153,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         $ar = new \SimpleSAML\XML\Shib13\AuthnRequest();
         $ar->setIssuer($this->entityId);
 
-        $id = SimpleSAML_Auth_State::saveState($state, 'saml:sp:sso');
+        $id = State::saveState($state, 'saml:sp:sso');
         $ar->setRelayState($id);
 
         $useArtifact = $idpMetadata->getBoolean('saml1.useartifact', null);
@@ -156,66 +162,67 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         }
 
         if ($useArtifact) {
-            $shire = SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/' . $this->authId . '/artifact');
+            $shire = \SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$this->authId.'/artifact');
         } else {
-            $shire = SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/' . $this->authId);
+            $shire = \SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$this->authId);
         }
 
         $url = $ar->createRedirect($idpEntityId, $shire);
 
-        SimpleSAML\Logger::debug('Starting SAML 1 SSO to ' . var_export($idpEntityId, true) .
-            ' from ' . var_export($this->entityId, true) . '.');
+        \SimpleSAML\Logger::debug('Starting SAML 1 SSO to '.var_export($idpEntityId, true).
+            ' from '.var_export($this->entityId, true).'.');
         \SimpleSAML\Utils\HTTP::redirectTrustedURL($url);
     }
 
     /**
-     * Send a SAML2 SSO request to an IdP.
+     * Send a SAML2 SSO request to an IdP
      *
-     * @param SimpleSAML_Configuration $idpMetadata  The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $idpMetadata  The metadata of the IdP.
      * @param array $state  The state array for the current authentication.
      */
-    private function startSSO2(SimpleSAML_Configuration $idpMetadata, array $state)
+    private function startSSO2(\SimpleSAML\Configuration $idpMetadata, array $state)
     {
         if (isset($state['saml:ProxyCount']) && $state['saml:ProxyCount'] < 0) {
-            SimpleSAML_Auth_State::throwException(
+            State::throwException(
                 $state,
                 new \SimpleSAML\Module\saml\Error\ProxyCountExceeded(\SAML2\Constants::STATUS_RESPONDER)
             );
         }
 
-        $ar = sspmod_saml_Message::buildAuthnRequest($this->metadata, $idpMetadata);
+        $ar = \SimpleSAML\Module\saml\Message::buildAuthnRequest($this->metadata, $idpMetadata);
 
-        $ar->setAssertionConsumerServiceURL(SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/' . $this->authId));
+        $ar->setAssertionConsumerServiceURL(\SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$this->authId));
 
-        if (isset($state['SimpleSAML_Auth_Source.ReturnURL'])) {
-            $ar->setRelayState($state['SimpleSAML_Auth_Source.ReturnURL']);
+        if (isset($state['\SimpleSAML\Auth\Source.ReturnURL'])) {
+            $ar->setRelayState($state['\SimpleSAML\Auth\Source.ReturnURL']);
         }
 
         if (isset($state['saml:AuthnContextClassRef'])) {
-            $accr = SimpleSAML\Utils\Arrays::arrayize($state['saml:AuthnContextClassRef']);
-            $comp = SAML2\Constants::COMPARISON_EXACT;
-            if (isset($state['saml:AuthnContextComparison']) && in_array($state['AuthnContextComparison'], array(
-                        SAML2\Constants::COMPARISON_EXACT,
-                        SAML2\Constants::COMPARISON_MINIMUM,
-                        SAML2\Constants::COMPARISON_MAXIMUM,
-                        SAML2\Constants::COMPARISON_BETTER,
-            ), true)) {
+            $accr = \SimpleSAML\Utils\Arrays::arrayize($state['saml:AuthnContextClassRef']);
+            $comp = \SAML2\Constants::COMPARISON_EXACT;
+            if (isset($state['saml:AuthnContextComparison'])
+                && in_array($state['AuthnContextComparison'], [
+                    \SAML2\Constants::COMPARISON_EXACT,
+                    \SAML2\Constants::COMPARISON_MINIMUM,
+                    \SAML2\Constants::COMPARISON_MAXIMUM,
+                    \SAML2\Constants::COMPARISON_BETTER,
+                ], true)) {
                 $comp = $state['saml:AuthnContextComparison'];
             }
-            $ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
+            $ar->setRequestedAuthnContext(['AuthnContextClassRef' => $accr, 'Comparison' => $comp]);
         }
 
         if (isset($state['ForceAuthn'])) {
-            $ar->setForceAuthn((bool)$state['ForceAuthn']);
+            $ar->setForceAuthn((bool) $state['ForceAuthn']);
         }
 
         if (isset($state['isPassive'])) {
-            $ar->setIsPassive((bool)$state['isPassive']);
+            $ar->setIsPassive((bool) $state['isPassive']);
         }
 
         if (isset($state['saml:NameID'])) {
             if (!is_array($state['saml:NameID']) && !is_a($state['saml:NameID'], '\SAML2\XML\saml\NameID')) {
-                throw new SimpleSAML_Error_Exception('Invalid value of $state[\'saml:NameID\'].');
+                throw new \SimpleSAML\Error\Exception('Invalid value of $state[\'saml:NameID\'].');
             }
             $ar->setNameId($state['saml:NameID']);
         }
@@ -223,10 +230,10 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         if (isset($state['saml:NameIDPolicy'])) {
             $policy = null;
             if (is_string($state['saml:NameIDPolicy'])) {
-                $policy = array(
-                    'Format' => (string)$state['saml:NameIDPolicy'],
+                $policy = [
+                    'Format' => (string) $state['saml:NameIDPolicy'],
                     'AllowCreate' => true,
-                );
+                ];
             } elseif (is_array($state['saml:NameIDPolicy'])) {
                 $policy = $state['saml:NameIDPolicy'];
             } elseif ($state['saml:NameIDPolicy'] === null) {
@@ -240,12 +247,18 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         if (isset($state['saml:IDPList'])) {
             $IDPList = $state['saml:IDPList'];
         } else {
-            $IDPList = array();
+            $IDPList = [];
         }
 
-        $ar->setIDPList(array_unique(array_merge($this->metadata->getArray('IDPList', array()), 
-                                                $idpMetadata->getArray('IDPList', array()),
-                                                (array) $IDPList)));
+        $ar->setIDPList(
+            array_unique(
+                array_merge(
+                    $this->metadata->getArray('IDPList', []),
+                    $idpMetadata->getArray('IDPList', []),
+                    (array) $IDPList
+                )
+            )
+        );
 
         if (isset($state['saml:ProxyCount']) && $state['saml:ProxyCount'] !== null) {
             $ar->setProxyCount($state['saml:ProxyCount']);
@@ -255,7 +268,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
             $ar->setProxyCount($this->metadata->getInteger('ProxyCount', null));
         }
 
-        $requesterID = array();
+        $requesterID = [];
         if (isset($state['saml:RequesterID'])) {
             $requesterID = $state['saml:RequesterID'];
         }
@@ -273,21 +286,28 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         // save IdP entity ID as part of the state
         $state['ExpectedIssuer'] = $idpMetadata->getString('entityid');
 
-        $id = SimpleSAML_Auth_State::saveState($state, 'saml:sp:sso', true);
+        $id = State::saveState($state, 'saml:sp:sso', true);
         $ar->setId($id);
 
-        SimpleSAML\Logger::debug('Sending SAML 2 AuthnRequest to ' .
-            var_export($idpMetadata->getString('entityid'), true));
+        \SimpleSAML\Logger::debug(
+            'Sending SAML 2 AuthnRequest to '.var_export($idpMetadata->getString('entityid'), true)
+        );
 
-        /* Select appropriate SSO endpoint */
+        // Select appropriate SSO endpoint
         if ($ar->getProtocolBinding() === \SAML2\Constants::BINDING_HOK_SSO) {
-            $dst = $idpMetadata->getDefaultEndpoint('SingleSignOnService', array(
-                \SAML2\Constants::BINDING_HOK_SSO)
+            $dst = $idpMetadata->getDefaultEndpoint(
+                'SingleSignOnService',
+                [
+                    \SAML2\Constants::BINDING_HOK_SSO
+                ]
             );
         } else {
-            $dst = $idpMetadata->getDefaultEndpoint('SingleSignOnService', array(
-                \SAML2\Constants::BINDING_HTTP_REDIRECT,
-                \SAML2\Constants::BINDING_HTTP_POST)
+            $dst = $idpMetadata->getEndpointPrioritizedByBinding(
+                'SingleSignOnService',
+                [
+                    \SAML2\Constants::BINDING_HTTP_REDIRECT,
+                    \SAML2\Constants::BINDING_HTTP_POST,
+                ]
             );
         }
         $ar->setDestination($dst['Location']);
@@ -328,15 +348,15 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
 
         $type = $idpMetadata->getString('metadata-set');
         switch ($type) {
-        case 'shib13-idp-remote':
-            $this->startSSO1($idpMetadata, $state);
-            assert(false); /* Should not return. */
-        case 'saml20-idp-remote':
-            $this->startSSO2($idpMetadata, $state);
-            assert(false); /* Should not return. */
-        default:
-            /* Should only be one of the known types. */
-            assert(false);
+            case 'shib13-idp-remote':
+                $this->startSSO1($idpMetadata, $state);
+                assert(false); // Should not return
+            case 'saml20-idp-remote':
+                $this->startSSO2($idpMetadata, $state);
+                assert(false); // Should not return
+            default:
+                // Should only be one of the known types
+                assert(false);
         }
     }
 
@@ -347,23 +367,23 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      */
     private function startDisco(array $state)
     {
-        $id = SimpleSAML_Auth_State::saveState($state, 'saml:sp:sso');
+        $id = State::saveState($state, 'saml:sp:sso');
 
         $discoURL = $this->discoURL;
         if ($discoURL === null) {
-            /* Fallback to internal discovery service. */
-            $discoURL = SimpleSAML\Module::getModuleURL('saml/disco.php');
+            // Fallback to internal discovery service
+            $discoURL = \SimpleSAML\Module::getModuleURL('saml/disco.php');
         }
 
-        $returnTo = SimpleSAML\Module::getModuleURL('saml/sp/discoresp.php', array('AuthID' => $id));
+        $returnTo = \SimpleSAML\Module::getModuleURL('saml/sp/discoresp.php', ['AuthID' => $id]);
 
-        $params = array(
+        $params = [
             'entityID' => $this->entityId,
             'return' => $returnTo,
             'returnIDParam' => 'idpentityid'
-        );
+        ];
 
-        if(isset($state['saml:IDPList'])) {
+        if (isset($state['saml:IDPList'])) {
             $params['IDPList'] = $state['saml:IDPList'];
         }
 
@@ -385,24 +405,24 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
     {
         assert(is_array($state));
 
-        /* We are going to need the authId in order to retrieve this authentication source later. */
+        // We are going to need the authId in order to retrieve this authentication source later
         $state['saml:sp:AuthId'] = $this->authId;
 
         $idp = $this->idp;
 
         if (isset($state['saml:idp'])) {
-            $idp = (string)$state['saml:idp'];
+            $idp = (string) $state['saml:idp'];
         }
 
         if (isset($state['saml:IDPList']) && sizeof($state['saml:IDPList']) > 0) {
             // we have a SAML IDPList (we are a proxy): filter the list of IdPs available
-            $mdh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+            $mdh = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
             $known_idps = $mdh->getList();
             $intersection = array_intersect($state['saml:IDPList'], array_keys($known_idps));
 
             if (empty($intersection)) {
                 // all requested IdPs are unknown
-                throw new SimpleSAML\Module\saml\Error\NoSupportedIDP(
+                throw new \SimpleSAML\Module\saml\Error\NoSupportedIDP(
                     \SAML2\Constants::STATUS_REQUESTER,
                     'None of the IdPs requested are supported by this proxy.'
                 );
@@ -410,7 +430,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
 
             if (!is_null($idp) && !in_array($idp, $intersection, true)) {
                 // the IdP is enforced but not in the IDPList
-                throw new SimpleSAML\Module\saml\Error\NoAvailableIDP(
+                throw new \SimpleSAML\Module\saml\Error\NoAvailableIDP(
                     \SAML2\Constants::STATUS_REQUESTER,
                     'None of the IdPs requested are available to this proxy.'
                 );
@@ -443,7 +463,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
     {
         assert(is_array($state));
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $data = $session->getAuthState($this->authId);
         foreach ($data as $k => $v) {
             $state[$k] = $v;
@@ -451,8 +471,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
 
         // check if we have an IDPList specified in the request
         if (isset($state['saml:IDPList']) && sizeof($state['saml:IDPList']) > 0 &&
-            !in_array($state['saml:sp:IdP'], $state['saml:IDPList'], true))
-        {
+            !in_array($state['saml:sp:IdP'], $state['saml:IDPList'], true)) {
             /*
              * The user has an existing, valid session. However, the SP
              * provided a list of IdPs it accepts for authentication, and
@@ -461,13 +480,13 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
              * First, check if we recognize any of the IdPs requested.
              */
 
-            $mdh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+            $mdh = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
             $known_idps = $mdh->getList();
             $intersection = array_intersect($state['saml:IDPList'], array_keys($known_idps));
 
             if (empty($intersection)) {
                 // all requested IdPs are unknown
-                throw new SimpleSAML\Module\saml\Error\NoSupportedIDP(
+                throw new \SimpleSAML\Module\saml\Error\NoSupportedIDP(
                     \SAML2\Constants::STATUS_REQUESTER,
                     'None of the IdPs requested are supported by this proxy.'
                 );
@@ -480,7 +499,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
              */
             if (!is_null($this->idp) && !in_array($this->idp, $intersection, true)) {
                 // an IdP is enforced but not requested
-                throw new SimpleSAML\Module\saml\Error\NoAvailableIDP(
+                throw new \SimpleSAML\Module\saml\Error\NoAvailableIDP(
                     \SAML2\Constants::STATUS_REQUESTER,
                     'None of the IdPs requested are available to this proxy.'
                 );
@@ -491,7 +510,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
              * starting the authentication process again with a different IdP, or
              * cancel the current SSO attempt.
              */
-            SimpleSAML\Logger::warning(
+            \SimpleSAML\Logger::warning(
                 "Reauthentication after logout is needed. The IdP '${state['saml:sp:IdP']}' is not in the IDPList ".
                 "provided by the Service Provider '${state['core:SP']}'."
             );
@@ -513,14 +532,14 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      *
      * @param array $state The state array.
      * The following keys must be defined in the array:
-     * - 'saml:sp:IdPMetadata': a SimpleSAML_Configuration object containing
+     * - 'saml:sp:IdPMetadata': a \SimpleSAML\Configuration object containing
      *   the metadata of the IdP that authenticated the user in the current
      *   session.
      * - 'saml:sp:AuthId': the identifier of the current authentication source.
      * - 'core:IdP': the identifier of the local IdP.
      * - 'SPMetadata': an array with the metadata of this local SP.
      *
-     * @throws SimpleSAML_Error_NoPassive In case the authentication request was passive.
+     * @throws \SimpleSAML\Error\NoPassive In case the authentication request was passive.
      */
     public static function askForIdPChange(array &$state)
     {
@@ -529,18 +548,18 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         assert(array_key_exists('core:IdP', $state));
         assert(array_key_exists('SPMetadata', $state));
 
-        if (isset($state['isPassive']) && (bool)$state['isPassive']) {
+        if (isset($state['isPassive']) && (bool) $state['isPassive']) {
             // passive request, we cannot authenticate the user
-            throw new SimpleSAML\Module\saml\Error\NoPassive(
-                    \SAML2\Constants::STATUS_REQUESTER,
-                    'Reauthentication required'
+            throw new \SimpleSAML\Module\saml\Error\NoPassive(
+                \SAML2\Constants::STATUS_REQUESTER,
+                'Reauthentication required'
             );
         }
 
         // save the state WITHOUT a restart URL, so that we don't try an IdP-initiated login if something goes wrong
-        $id = SimpleSAML_Auth_State::saveState($state, 'saml:proxy:invalid_idp', true);
-        $url = SimpleSAML\Module::getModuleURL('saml/proxy/invalid_session.php');
-        SimpleSAML\Utils\HTTP::redirectTrustedURL($url, array('AuthState' => $id));
+        $id = State::saveState($state, 'saml:proxy:invalid_idp', true);
+        $url = \SimpleSAML\Module::getModuleURL('saml/proxy/invalid_session.php');
+        \SimpleSAML\Utils\HTTP::redirectTrustedURL($url, ['AuthState' => $id]);
         assert(false);
     }
 
@@ -553,14 +572,14 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      */
     public static function reauthLogout(array $state)
     {
-        SimpleSAML\Logger::debug('Proxy: logging the user out before re-authentication.');
+        \SimpleSAML\Logger::debug('Proxy: logging the user out before re-authentication.');
 
         if (isset($state['Responder'])) {
             $state['saml:proxy:reauthLogout:PrevResponder'] = $state['Responder'];
         }
-        $state['Responder'] = array('sspmod_saml_Auth_Source_SP', 'reauthPostLogout');
+        $state['Responder'] = ['\SimpleSAML\Module\saml\Auth\Source\SP', 'reauthPostLogout'];
 
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = \SimpleSAML\IdP::getByState($state);
         $idp->handleLogoutRequest($state, null);
         assert(false);
     }
@@ -575,9 +594,9 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         assert(isset($state['ReturnCallback']));
 
         // Update session state
-        $session = SimpleSAML_Session::getSessionFromRequest();
+        $session = \SimpleSAML\Session::getSessionFromRequest();
         $authId = $state['saml:sp:AuthId'];
-        $session->doLogin($authId, SimpleSAML_Auth_State::getPersistentAuthData($state));
+        $session->doLogin($authId, State::getPersistentAuthData($state));
 
         // resume the login process
         call_user_func($state['ReturnCallback'], $state);
@@ -589,22 +608,22 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
      *
      * This method will never return.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are logging out from.
+     * @param \SimpleSAML\IdP $idp The IdP we are logging out from.
      * @param array &$state The state array with the state during logout.
      */
-    public static function reauthPostLogout(SimpleSAML_IdP $idp, array $state)
+    public static function reauthPostLogout(\SimpleSAML\IdP $idp, array $state)
     {
         assert(isset($state['saml:sp:AuthId']));
 
-        SimpleSAML\Logger::debug('Proxy: logout completed.');
+        \SimpleSAML\Logger::debug('Proxy: logout completed.');
 
         if (isset($state['saml:proxy:reauthLogout:PrevResponder'])) {
             $state['Responder'] = $state['saml:proxy:reauthLogout:PrevResponder'];
         }
 
-        $sp = SimpleSAML_Auth_Source::getById($state['saml:sp:AuthId'], 'sspmod_saml_Auth_Source_SP');
-        /** @var sspmod_saml_Auth_Source_SP $authSource */
-        SimpleSAML\Logger::debug('Proxy: logging in again.');
+        $sp = Source::getById($state['saml:sp:AuthId'], '\SimpleSAML\Module\saml\Auth\Source\SP');
+        /** @var \SimpleSAML\Module\saml\Auth\Source\SP $authSource */
+        \SimpleSAML\Logger::debug('Proxy: logging in again.');
         $sp->authenticate($state);
         assert(false);
     }
@@ -621,7 +640,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         assert(array_key_exists('saml:logout:NameID', $state));
         assert(array_key_exists('saml:logout:SessionIndex', $state));
 
-        $id = SimpleSAML_Auth_State::saveState($state, 'saml:slosent');
+        $id = State::saveState($state, 'saml:slosent');
 
         $idp = $state['saml:logout:IdP'];
         $nameId = $state['saml:logout:NameID'];
@@ -629,15 +648,15 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
 
         $idpMetadata = $this->getIdPMetadata($idp);
 
-        $endpoint = $idpMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', array(
+        $endpoint = $idpMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', [
             \SAML2\Constants::BINDING_HTTP_REDIRECT,
-            \SAML2\Constants::BINDING_HTTP_POST), false);
+            \SAML2\Constants::BINDING_HTTP_POST], false);
         if ($endpoint === false) {
-            SimpleSAML\Logger::info('No logout endpoint for IdP ' . var_export($idp, true) . '.');
+            \SimpleSAML\Logger::info('No logout endpoint for IdP '.var_export($idp, true).'.');
             return;
         }
 
-        $lr = sspmod_saml_Message::buildLogoutRequest($this->metadata, $idpMetadata);
+        $lr = \SimpleSAML\Module\saml\Message::buildLogoutRequest($this->metadata, $idpMetadata);
         $lr->setNameId($nameId);
         $lr->setSessionIndex($sessionIndex);
         $lr->setRelayState($id);
@@ -648,7 +667,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
             $encryptNameId = $this->metadata->getBoolean('nameid.encryption', false);
         }
         if ($encryptNameId) {
-            $lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($idpMetadata));
+            $lr->encryptNameId(\SimpleSAML\Module\saml\Message::getEncryptionKey($idpMetadata));
         }
 
         $b = \SAML2\Binding::getBinding($endpoint['Binding']);
@@ -669,15 +688,15 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
 
         $logoutType = $state['saml:logout:Type'];
         switch ($logoutType) {
-        case 'saml1':
-            /* Nothing to do. */
-            return;
-        case 'saml2':
-            $this->startSLO2($state);
-            return;
-        default:
-            /* Should never happen. */
-            assert(false);
+            case 'saml1':
+                // Nothing to do
+                return;
+            case 'saml2':
+                $this->startSLO2($state);
+                return;
+            default:
+                // Should never happen
+                assert(false);
         }
     }
 
@@ -694,7 +713,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         assert(array_key_exists('LogoutState', $state));
         assert(array_key_exists('saml:logout:Type', $state['LogoutState']));
 
-        $idpMetadata = $this->getIdpMetadata($idp);
+        $idpMetadata = $this->getIdPMetadata($idp);
 
         $spMetadataArray = $this->metadata->toArray();
         $idpMetadataArray = $idpMetadata->toArray();
@@ -703,15 +722,15 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         $state['saml:sp:IdP'] = $idp;
         $state['PersistentAuthData'][] = 'saml:sp:IdP';
 
-        $authProcState = array(
+        $authProcState = [
             'saml:sp:IdP' => $idp,
             'saml:sp:State' => $state,
-            'ReturnCall' => array('sspmod_saml_Auth_Source_SP', 'onProcessingCompleted'),
+            'ReturnCall' => ['\SimpleSAML\Module\saml\Auth\Source\SP', 'onProcessingCompleted'],
 
             'Attributes' => $attributes,
             'Destination' => $spMetadataArray,
             'Source' => $idpMetadataArray,
-        );
+        ];
 
         if (isset($state['saml:sp:NameID'])) {
             $authProcState['saml:sp:NameID'] = $state['saml:sp:NameID'];
@@ -720,7 +739,7 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
             $authProcState['saml:sp:SessionIndex'] = $state['saml:sp:SessionIndex'];
         }
 
-        $pc = new SimpleSAML_Auth_ProcessingChain($idpMetadataArray, $spMetadataArray, 'sp');
+        $pc = new \SimpleSAML\Auth\ProcessingChain($idpMetadataArray, $spMetadataArray, 'sp');
         $pc->processState($authProcState);
 
         self::onProcessingCompleted($authProcState);
@@ -758,8 +777,8 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         assert(is_string($authId));
         assert(is_string($redirectTo));
 
-        $session = SimpleSAML_Session::getSessionFromRequest();
-        $session->doLogin($authId, SimpleSAML_Auth_State::getPersistentAuthData($state));
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $session->doLogin($authId, State::getPersistentAuthData($state));
 
         \SimpleSAML\Utils\HTTP::redirectUntrustedURL($redirectTo);
     }
@@ -779,17 +798,17 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
         $state = $authProcState['saml:sp:State'];
 
         $sourceId = $state['saml:sp:AuthId'];
-        $source = SimpleSAML_Auth_Source::getById($sourceId);
+        $source = Source::getById($sourceId);
         if ($source === null) {
-            throw new Exception('Could not find authentication source with id ' . $sourceId);
+            throw new \Exception('Could not find authentication source with id '.$sourceId);
         }
 
-        /* Register a callback that we can call if we receive a logout request from the IdP. */
+        // Register a callback that we can call if we receive a logout request from the IdP
         $source->addLogoutCallback($idp, $state);
 
         $state['Attributes'] = $authProcState['Attributes'];
 
-        if (isset($state['saml:sp:isUnsolicited']) && (bool)$state['saml:sp:isUnsolicited']) {
+        if (isset($state['saml:sp:isUnsolicited']) && (bool) $state['saml:sp:isUnsolicited']) {
             if (!empty($state['saml:sp:RelayState'])) {
                 $redirectTo = $state['saml:sp:RelayState'];
             } else {
@@ -798,6 +817,6 @@ class sspmod_saml_Auth_Source_SP extends SimpleSAML_Auth_Source
             self::handleUnsolicitedAuth($sourceId, $state, $redirectTo);
         }
 
-        SimpleSAML_Auth_Source::completeAuth($state);
+        Source::completeAuth($state);
     }
 }
diff --git a/modules/saml/lib/BaseNameIDGenerator.php b/modules/saml/lib/BaseNameIDGenerator.php
index 342c51d6619f78386fe8c96bdc1ef05bd0b1d35f..c5360854e7904bb1ba721eafd5d5937093f0080b 100644
--- a/modules/saml/lib/BaseNameIDGenerator.php
+++ b/modules/saml/lib/BaseNameIDGenerator.php
@@ -1,116 +1,120 @@
 <?php
 
+namespace SimpleSAML\Module\saml;
+
 /**
  * Base filter for generating NameID values.
  *
  * @package SimpleSAMLphp
  */
-abstract class sspmod_saml_BaseNameIDGenerator extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * What NameQualifier should be used.
-	 * Can be one of:
-	 *  - a string: The qualifier to use.
-	 *  - FALSE: Do not include a NameQualifier. This is the default.
-	 *  - TRUE: Use the IdP entity ID.
-	 *
-	 * @var string|bool
-	 */
-	private $nameQualifier;
-
-
-	/**
-	 * What SPNameQualifier should be used.
-	 * Can be one of:
-	 *  - a string: The qualifier to use.
-	 *  - FALSE: Do not include a SPNameQualifier.
-	 *  - TRUE: Use the SP entity ID. This is the default.
-	 *
-	 * @var string|bool
-	 */
-	private $spNameQualifier;
-
-
-	/**
-	 * The format of this NameID.
-	 *
-	 * This property must be initialized the subclass.
-	 *
-	 * @var string
-	 */
-	protected $format;
-
-
-	/**
-	 * Initialize this filter, parse configuration.
-	 *
-	 * @param array $config  Configuration information about this filter.
-	 * @param mixed $reserved  For future use.
-	 */
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-		assert(is_array($config));
-
-		if (isset($config['NameQualifier'])) {
-			$this->nameQualifier = $config['NameQualifier'];
-		} else {
-			$this->nameQualifier = FALSE;
-		}
-
-		if (isset($config['SPNameQualifier'])) {
-			$this->spNameQualifier = $config['SPNameQualifier'];
-		} else {
-			$this->spNameQualifier = TRUE;
-		}
-	}
-
-
-	/**
-	 * Get the NameID value.
-	 *
-	 * @return string|NULL  The NameID value.
-	 */
-	abstract protected function getValue(array &$state);
-
-
-	/**
-	 * Generate transient NameID.
-	 *
-	 * @param array &$state  The request state.
-	 */
-	public function process(&$state) {
-		assert(is_array($state));
-		assert(is_string($this->format));
-
-		$value = $this->getValue($state);
-		if ($value === NULL) {
-			return;
-		}
-
-		$nameId = new \SAML2\XML\saml\NameID();
-		$nameId->value = $value;
-
-		if ($this->nameQualifier === TRUE) {
-			if (isset($state['IdPMetadata']['entityid'])) {
-				$nameId->NameQualifier = $state['IdPMetadata']['entityid'];
-			} else {
-				SimpleSAML\Logger::warning('No IdP entity ID, unable to set NameQualifier.');
-			}
-		} elseif (is_string($this->nameQualifier)) {
-			$nameId->NameQualifier = $this->nameQualifier;
-		}
-
-		if ($this->spNameQualifier === TRUE) {
-			if (isset($state['SPMetadata']['entityid'])) {
-				$nameId->SPNameQualifier = $state['SPMetadata']['entityid'];
-			} else {
-				SimpleSAML\Logger::warning('No SP entity ID, unable to set SPNameQualifier.');
-			}
-		} elseif (is_string($this->spNameQualifier)) {
-			$nameId->SPNameQualifier = $this->spNameQualifier;
-		}
-
-		$state['saml:NameID'][$this->format] = $nameId;
-	}
 
+abstract class BaseNameIDGenerator extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * What NameQualifier should be used.
+     * Can be one of:
+     *  - a string: The qualifier to use.
+     *  - FALSE: Do not include a NameQualifier. This is the default.
+     *  - TRUE: Use the IdP entity ID.
+     *
+     * @var string|bool
+     */
+    private $nameQualifier;
+
+
+    /**
+     * What SPNameQualifier should be used.
+     * Can be one of:
+     *  - a string: The qualifier to use.
+     *  - FALSE: Do not include a SPNameQualifier.
+     *  - TRUE: Use the SP entity ID. This is the default.
+     *
+     * @var string|bool
+     */
+    private $spNameQualifier;
+
+
+    /**
+     * The format of this NameID.
+     *
+     * This property must be initialized the subclass.
+     *
+     * @var string
+     */
+    protected $format;
+
+
+    /**
+     * Initialize this filter, parse configuration.
+     *
+     * @param array $config  Configuration information about this filter.
+     * @param mixed $reserved  For future use.
+     */
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+        assert(is_array($config));
+
+        if (isset($config['NameQualifier'])) {
+            $this->nameQualifier = $config['NameQualifier'];
+        } else {
+            $this->nameQualifier = false;
+        }
+
+        if (isset($config['SPNameQualifier'])) {
+            $this->spNameQualifier = $config['SPNameQualifier'];
+        } else {
+            $this->spNameQualifier = true;
+        }
+    }
+
+
+    /**
+     * Get the NameID value.
+     *
+     * @return string|null  The NameID value.
+     */
+    abstract protected function getValue(array &$state);
+
+
+    /**
+     * Generate transient NameID.
+     *
+     * @param array &$state  The request state.
+     */
+    public function process(&$state)
+    {
+        assert(is_array($state));
+        assert(is_string($this->format));
+
+        $value = $this->getValue($state);
+        if ($value === null) {
+            return;
+        }
+
+        $nameId = new \SAML2\XML\saml\NameID();
+        $nameId->value = $value;
+
+        if ($this->nameQualifier === true) {
+            if (isset($state['IdPMetadata']['entityid'])) {
+                $nameId->NameQualifier = $state['IdPMetadata']['entityid'];
+            } else {
+                \SimpleSAML\Logger::warning('No IdP entity ID, unable to set NameQualifier.');
+            }
+        } elseif (is_string($this->nameQualifier)) {
+            $nameId->NameQualifier = $this->nameQualifier;
+        }
+
+        if ($this->spNameQualifier === true) {
+            if (isset($state['SPMetadata']['entityid'])) {
+                $nameId->SPNameQualifier = $state['SPMetadata']['entityid'];
+            } else {
+                \SimpleSAML\Logger::warning('No SP entity ID, unable to set SPNameQualifier.');
+            }
+        } elseif (is_string($this->spNameQualifier)) {
+            $nameId->SPNameQualifier = $this->spNameQualifier;
+        }
+
+        $state['saml:NameID'][$this->format] = $nameId;
+    }
 }
diff --git a/modules/saml/lib/Error.php b/modules/saml/lib/Error.php
index 0a28d6b6108b3702247bf160470e0f54fa115d40..e45b846ff89c99987927d99907da775750c7a43d 100644
--- a/modules/saml/lib/Error.php
+++ b/modules/saml/lib/Error.php
@@ -1,196 +1,199 @@
 <?php
 
+namespace SimpleSAML\Module\saml;
+
 /**
  * Class for representing a SAML 2 error.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Error extends SimpleSAML_Error_Exception
+
+class Error extends \SimpleSAML\Error\Exception
 {
-	/**
-	 * The top-level status code.
-	 *
-	 * @var string
-	 */
-	private $status;
-
-
-	/**
-	 * The second-level status code, or NULL if no second-level status code is defined.
-	 *
-	 * @var string|NULL
-	 */
-	private $subStatus;
-
-
-	/**
-	 * The status message, or NULL if no status message is defined.
-	 *
-	 * @var string|NULL
-	 */
-	private $statusMessage;
-
-
-	/**
-	 * Create a SAML 2 error.
-	 *
-	 * @param string $status  The top-level status code.
-	 * @param string|NULL $subStatus  The second-level status code. Can be NULL, in which case there is no second-level status code.
-	 * @param string|NULL $statusMessage  The status message. Can be NULL, in which case there is no status message.
-	 * @param Exception|NULL $cause  The cause of this exception. Can be NULL.
-	 */
-	public function __construct($status, $subStatus = null, $statusMessage = null, Exception $cause = null)
+    /**
+     * The top-level status code.
+     *
+     * @var string
+     */
+    private $status;
+
+    /**
+     * The second-level status code, or NULL if no second-level status code is defined.
+     *
+     * @var string|null
+     */
+    private $subStatus;
+
+    /**
+     * The status message, or NULL if no status message is defined.
+     *
+     * @var string|null
+     */
+    private $statusMessage;
+
+
+    /**
+     * Create a SAML 2 error.
+     *
+     * @param string $status  The top-level status code.
+     * @param string|null $subStatus  The second-level status code.
+     * Can be NULL, in which case there is no second-level status code.
+     * @param string|null $statusMessage  The status message.
+     * Can be NULL, in which case there is no status message.
+     * @param \Exception|null $cause  The cause of this exception. Can be NULL.
+     */
+    public function __construct($status, $subStatus = null, $statusMessage = null, \Exception $cause = null)
     {
-		assert(is_string($status));
-		assert($subStatus === null || is_string($subStatus));
-		assert($statusMessage === null || is_string($statusMessage));
-
-		$st = self::shortStatus($status);
-		if ($subStatus !== null) {
-			$st .= '/' . self::shortStatus($subStatus);
-		}
-		if ($statusMessage !== null) {
-			$st .= ': ' . $statusMessage;
-		}
-		parent::__construct($st, 0, $cause);
-
-		$this->status = $status;
-		$this->subStatus = $subStatus;
-		$this->statusMessage = $statusMessage;
-	}
-
-
-	/**
-	 * Get the top-level status code.
-	 *
-	 * @return string  The top-level status code.
-	 */
-	public function getStatus()
+        assert(is_string($status));
+        assert($subStatus === null || is_string($subStatus));
+        assert($statusMessage === null || is_string($statusMessage));
+
+        $st = self::shortStatus($status);
+        if ($subStatus !== null) {
+            $st .= '/'.self::shortStatus($subStatus);
+        }
+        if ($statusMessage !== null) {
+            $st .= ': '.$statusMessage;
+        }
+        parent::__construct($st, 0, $cause);
+
+        $this->status = $status;
+        $this->subStatus = $subStatus;
+        $this->statusMessage = $statusMessage;
+    }
+
+
+    /**
+     * Get the top-level status code.
+     *
+     * @return string  The top-level status code.
+     */
+    public function getStatus()
     {
-		return $this->status;
-	}
+        return $this->status;
+    }
 
 
-	/**
-	 * Get the second-level status code.
-	 *
-	 * @return string|NULL  The second-level status code or NULL if no second-level status code is present.
-	 */
-	public function getSubStatus()
+    /**
+     * Get the second-level status code.
+     *
+     * @return string|null  The second-level status code or NULL if no second-level status code is present.
+     */
+    public function getSubStatus()
     {
-		return $this->subStatus;
-	}
+        return $this->subStatus;
+    }
 
 
-	/**
-	 * Get the status message.
-	 *
-	 * @return string|NULL  The status message or NULL if no status message is present.
-	 */
-	public function getStatusMessage()
+    /**
+     * Get the status message.
+     *
+     * @return string|null  The status message or NULL if no status message is present.
+     */
+    public function getStatusMessage()
     {
-		return $this->statusMessage;
-	}
-
-
-	/**
-	 * Create a SAML2 error from an exception.
-	 *
-	 * This function attempts to create a SAML2 error with the appropriate
-	 * status codes from an arbitrary exception.
-	 *
-	 * @param Exception $exception  The original exception.
-	 * @return sspmod_saml_Error  The new exception.
-	 */
-	public static function fromException(Exception $exception)
+        return $this->statusMessage;
+    }
+
+
+    /**
+     * Create a SAML2 error from an exception.
+     *
+     * This function attempts to create a SAML2 error with the appropriate
+     * status codes from an arbitrary exception.
+     *
+     * @param \Exception $exception  The original exception.
+     * @return \SimpleSAML\Module\saml\Error  The new exception.
+     */
+    public static function fromException(\Exception $exception)
     {
-		if ($exception instanceof sspmod_saml_Error) {
-			// Return the original exception unchanged
-			return $exception;
-
-		// TODO: remove this branch in 2.0
-		} elseif ($exception instanceof SimpleSAML_Error_NoPassive) {
-			$e = new self(
-				\SAML2\Constants::STATUS_RESPONDER,
-				\SAML2\Constants::STATUS_NO_PASSIVE,
-				$exception->getMessage(),
-				$exception
-				);
-		// TODO: remove this branch in 2.0
-		} elseif ($exception instanceof SimpleSAML_Error_ProxyCountExceeded) {
-			$e = new self(
-				\SAML2\Constants::STATUS_RESPONDER,
-				\SAML2\Constants::STATUS_PROXY_COUNT_EXCEEDED,
-				$exception->getMessage(),
-				$exception
-			);
-		} else {
-			$e = new self(
-				\SAML2\Constants::STATUS_RESPONDER,
-				null,
-				get_class($exception) . ': ' . $exception->getMessage(),
-				$exception
-				);
-		}
-
-		return $e;
-	}
-
-
-	/**
-	 * Create a normal exception from a SAML2 error.
-	 *
-	 * This function attempts to reverse the operation of the fromException() function.
-	 * If it is unable to create a more specific exception, it will return the current
-	 * object.
-	 *
-	 * @see sspmod_saml_Error::fromException()
-	 *
-	 * @return SimpleSAML_Error_Exception  An exception representing this error.
-	 */
-	public function toException()
+        if ($exception instanceof \SimpleSAML\Module\saml\Error) {
+            // Return the original exception unchanged
+            return $exception;
+
+        // TODO: remove this branch in 2.0
+        } elseif ($exception instanceof \SimpleSAML\Error\NoPassive) {
+            $e = new self(
+                \SAML2\Constants::STATUS_RESPONDER,
+                \SAML2\Constants::STATUS_NO_PASSIVE,
+                $exception->getMessage(),
+                $exception
+            );
+        // TODO: remove this branch in 2.0
+        } elseif ($exception instanceof \SimpleSAML\Error\ProxyCountExceeded) {
+            $e = new self(
+                \SAML2\Constants::STATUS_RESPONDER,
+                \SAML2\Constants::STATUS_PROXY_COUNT_EXCEEDED,
+                $exception->getMessage(),
+                $exception
+            );
+        } else {
+            $e = new self(
+                \SAML2\Constants::STATUS_RESPONDER,
+                null,
+                get_class($exception).': '.$exception->getMessage(),
+                $exception
+            );
+        }
+
+        return $e;
+    }
+
+
+    /**
+     * Create a normal exception from a SAML2 error.
+     *
+     * This function attempts to reverse the operation of the fromException() function.
+     * If it is unable to create a more specific exception, it will return the current
+     * object.
+     *
+     * @see \SimpleSAML\Module\saml\Error::fromException()
+     *
+     * @return \SimpleSAML\Error\Exception  An exception representing this error.
+     */
+    public function toException()
     {
-		$e = null;
-
-		switch ($this->status) {
-		case \SAML2\Constants::STATUS_RESPONDER:
-			switch ($this->subStatus) {
-			case \SAML2\Constants::STATUS_NO_PASSIVE:
-                $e = new SimpleSAML\Module\saml\Error\NoPassive(
-                    \SAML2\Constants::STATUS_RESPONDER,
-                    $this->statusMessage
-                );
-				break;
-			}
-			break;
-		}
-
-		if ($e === null) {
-			return $this;
-		}
-
-		return $e;
-	}
-
-
-	/**
-	 * Create a short version of the status code.
-	 *
-	 * Remove the 'urn:oasis:names:tc:SAML:2.0:status:'-prefix of status codes
-	 * if it is present.
-	 *
-	 * @param string $status  The status code.
-	 * @return string  A shorter version of the status code.
-	 */
-	private static function shortStatus($status)
+        $e = null;
+
+        switch ($this->status) {
+            case \SAML2\Constants::STATUS_RESPONDER:
+                switch ($this->subStatus) {
+                    case \SAML2\Constants::STATUS_NO_PASSIVE:
+                        $e = new \SimpleSAML\Module\saml\Error\NoPassive(
+                            \SAML2\Constants::STATUS_RESPONDER,
+                            $this->statusMessage
+                        );
+                        break;
+                }
+                break;
+        }
+
+        if ($e === null) {
+            return $this;
+        }
+
+        return $e;
+    }
+
+
+    /**
+     * Create a short version of the status code.
+     *
+     * Remove the 'urn:oasis:names:tc:SAML:2.0:status:'-prefix of status codes
+     * if it is present.
+     *
+     * @param string $status  The status code.
+     * @return string  A shorter version of the status code.
+     */
+    private static function shortStatus($status)
     {
-		assert(is_string($status));
+        assert(is_string($status));
 
-		$t = 'urn:oasis:names:tc:SAML:2.0:status:';
-		if (substr($status, 0, strlen($t)) === $t) {
-			return substr($status, strlen($t));
-		}
+        $t = 'urn:oasis:names:tc:SAML:2.0:status:';
+        if (substr($status, 0, strlen($t)) === $t) {
+            return substr($status, strlen($t));
+        }
 
-		return $status;
-	}
+        return $status;
+    }
 }
diff --git a/modules/saml/lib/Error/NoAuthnContext.php b/modules/saml/lib/Error/NoAuthnContext.php
index 27f5ecf559c6c67e6786e55b6ddb0ba82ed925b4..54a147463ba3dca10f7ac8eeb15c702b3a92257a 100644
--- a/modules/saml/lib/Error/NoAuthnContext.php
+++ b/modules/saml/lib/Error/NoAuthnContext.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\saml\Error;
+
 /**
  * A SAML error indicating that none of the requested Authentication Contexts can be used.
  *
@@ -6,11 +9,9 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Module\saml\Error;
-
 use SAML2\Constants;
 
-class NoAuthnContext extends \sspmod_saml_Error
+class NoAuthnContext extends \SimpleSAML\Module\saml\Error
 {
     /**
      * NoAuthnContext error constructor.
diff --git a/modules/saml/lib/Error/NoAvailableIDP.php b/modules/saml/lib/Error/NoAvailableIDP.php
index 9245ef993498164a083fa53654cea01f9d18d73d..92f78d00b539c5208e978bed6f9d9a3c2d94c41f 100644
--- a/modules/saml/lib/Error/NoAvailableIDP.php
+++ b/modules/saml/lib/Error/NoAvailableIDP.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\saml\Error;
+
 /**
  * A SAML error indicating that none of the requested IdPs can be used.
  *
@@ -6,11 +9,9 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Module\saml\Error;
-
 use SAML2\Constants;
 
-class NoAvailableIDP extends \sspmod_saml_Error
+class NoAvailableIDP extends \SimpleSAML\Module\saml\Error
 {
     /**
      * NoAvailableIDP error constructor.
diff --git a/modules/saml/lib/Error/NoPassive.php b/modules/saml/lib/Error/NoPassive.php
index 2fa30be6bd13b376d62fef2cad2dbc7ffe3cf823..8602bce1fc30db10426bb1d5de5557a3412f9baa 100644
--- a/modules/saml/lib/Error/NoPassive.php
+++ b/modules/saml/lib/Error/NoPassive.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\saml\Error;
+
 /**
  * A SAML error indicating that passive authentication cannot be used.
  *
@@ -6,11 +9,9 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Module\saml\Error;
-
 use SAML2\Constants;
 
-class NoPassive extends \sspmod_saml_Error
+class NoPassive extends \SimpleSAML\Module\saml\Error
 {
     /**
      * NoPassive error constructor.
diff --git a/modules/saml/lib/Error/NoSupportedIDP.php b/modules/saml/lib/Error/NoSupportedIDP.php
index 0e1e6d7f78abb6eab55902cfa5f177c00733354c..5eedd1d27ae13a3e10c84af65fc67da117ec385c 100644
--- a/modules/saml/lib/Error/NoSupportedIDP.php
+++ b/modules/saml/lib/Error/NoSupportedIDP.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\saml\Error;
+
 /**
  * A SAML error indicating that none of the IdPs requested are supported.
  *
@@ -6,11 +9,9 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Module\saml\Error;
-
 use SAML2\Constants;
 
-class NoSupportedIDP extends \sspmod_saml_Error
+class NoSupportedIDP extends \SimpleSAML\Module\saml\Error
 {
     /**
      * NoSupportedIDP error constructor.
diff --git a/modules/saml/lib/Error/ProxyCountExceeded.php b/modules/saml/lib/Error/ProxyCountExceeded.php
index 7ded7b61b7f99459b53c2464e0978f7d8d00ed2a..f85216d82298252dd4a7b9f3154bd5ae2c3702a2 100644
--- a/modules/saml/lib/Error/ProxyCountExceeded.php
+++ b/modules/saml/lib/Error/ProxyCountExceeded.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Module\saml\Error;
+
 /**
  * A SAML error indicating that the maximum amount of proxies traversed has been reached.
  *
@@ -6,11 +9,9 @@
  * @package SimpleSAMLphp
  */
 
-namespace SimpleSAML\Module\saml\Error;
-
 use SAML2\Constants;
 
-class ProxyCountExceeded extends \sspmod_saml_Error
+class ProxyCountExceeded extends \SimpleSAML\Module\saml\Error
 {
     /**
      * ProxyCountExceeded error constructor.
diff --git a/modules/saml/lib/IdP/SAML1.php b/modules/saml/lib/IdP/SAML1.php
index 68fb13ed84fbbc944cdedc4f8869789beeab0503..3f1d734d4331da523cf0d5301d9737004cf8ad14 100644
--- a/modules/saml/lib/IdP/SAML1.php
+++ b/modules/saml/lib/IdP/SAML1.php
@@ -1,12 +1,17 @@
 <?php
+
+namespace SimpleSAML\Module\saml\IdP;
+
 use SimpleSAML\Bindings\Shib13\HTTPPost;
+use SimpleSAML\Utils\HTTP;
 
 /**
  * IdP implementation for SAML 1.1 protocol.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_IdP_SAML1
+
+class SAML1
 {
     /**
      * Send a response to the SP.
@@ -22,31 +27,33 @@ class sspmod_saml_IdP_SAML1
 
         $spMetadata = $state["SPMetadata"];
         $spEntityId = $spMetadata['entityid'];
-        $spMetadata = SimpleSAML_Configuration::loadFromArray($spMetadata,
-            '$metadata[' . var_export($spEntityId, true) . ']');
+        $spMetadata = \SimpleSAML\Configuration::loadFromArray(
+            $spMetadata,
+            '$metadata['.var_export($spEntityId, true).']'
+        );
 
-        SimpleSAML\Logger::info('Sending SAML 1.1 Response to ' . var_export($spEntityId, true));
+        \SimpleSAML\Logger::info('Sending SAML 1.1 Response to '.var_export($spEntityId, true));
 
         $attributes = $state['Attributes'];
         $shire = $state['saml:shire'];
         $target = $state['saml:target'];
 
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = \SimpleSAML\IdP::getByState($state);
 
         $idpMetadata = $idp->getConfig();
 
-        $config = SimpleSAML_Configuration::getInstance();
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $config = \SimpleSAML\Configuration::getInstance();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
-        $statsData = array(
+        $statsData = [
             'spEntityID' => $spEntityId,
             'idpEntityID' => $idpMetadata->getString('entityid'),
             'protocol' => 'saml1',
-        );
+        ];
         if (isset($state['saml:AuthnRequestReceivedAt'])) {
             $statsData['logintime'] = microtime(true) - $state['saml:AuthnRequestReceivedAt'];
         }
-        SimpleSAML_Stats::log('saml:idp:Response', $statsData);
+        \SimpleSAML\Stats::log('saml:idp:Response', $statsData);
 
         // Generate and send response.
         $ar = new \SimpleSAML\XML\Shib13\AuthnResponse();
@@ -60,30 +67,30 @@ class sspmod_saml_IdP_SAML1
     /**
      * Receive an authentication request.
      *
-     * @param SimpleSAML_IdP $idp  The IdP we are receiving it for.
+     * @param \SimpleSAML\IdP $idp  The IdP we are receiving it for.
      */
-    public static function receiveAuthnRequest(SimpleSAML_IdP $idp)
+    public static function receiveAuthnRequest(\SimpleSAML\IdP $idp)
     {
         if (isset($_REQUEST['cookieTime'])) {
-            $cookieTime = (int)$_REQUEST['cookieTime'];
+            $cookieTime = (int) $_REQUEST['cookieTime'];
             if ($cookieTime + 5 > time()) {
                 /*
                  * Less than five seconds has passed since we were
                  * here the last time. Cookies are probably disabled.
                  */
-                \SimpleSAML\Utils\HTTP::checkSessionCookie(\SimpleSAML\Utils\HTTP::getSelfURL());
+                HTTP::checkSessionCookie(HTTP::getSelfURL());
             }
         }
 
         if (!isset($_REQUEST['providerId'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing providerId parameter.');
+            throw new \SimpleSAML\Error\BadRequest('Missing providerId parameter.');
         }
-        $spEntityId = (string)$_REQUEST['providerId'];
+        $spEntityId = (string) $_REQUEST['providerId'];
 
         if (!isset($_REQUEST['shire'])) {
-            throw new SimpleSAML_Error_BadRequest('Missing shire parameter.');
+            throw new \SimpleSAML\Error\BadRequest('Missing shire parameter.');
         }
-        $shire = (string)$_REQUEST['shire'];
+        $shire = (string) $_REQUEST['shire'];
 
         if (isset($_REQUEST['target'])) {
             $target = $_REQUEST['target'];
@@ -91,9 +98,11 @@ class sspmod_saml_IdP_SAML1
             $target = null;
         }
 
-        SimpleSAML\Logger::info('Shib1.3 - IdP.SSOService: Got incoming Shib authnRequest from ' . var_export($spEntityId, true) . '.');
+        \SimpleSAML\Logger::info(
+            'Shib1.3 - IdP.SSOService: Got incoming Shib authnRequest from '.var_export($spEntityId, true).'.'
+        );
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'shib13-sp-remote');
 
         $found = false;
@@ -108,27 +117,32 @@ class sspmod_saml_IdP_SAML1
             break;
         }
         if (!$found) {
-            throw new Exception('Invalid AssertionConsumerService for SP ' .
-                var_export($spEntityId, true) . ': ' . var_export($shire, true));
-	}
+            throw new \Exception(
+                'Invalid AssertionConsumerService for SP '.var_export($spEntityId, true).': '.var_export($shire, true)
+            );
+        }
 
-        SimpleSAML_Stats::log('saml:idp:AuthnRequest', array(
-            'spEntityID' => $spEntityId,
-            'protocol' => 'saml1',
-        ));
+        \SimpleSAML\Stats::log(
+            'saml:idp:AuthnRequest',
+            [
+                'spEntityID' => $spEntityId,
+                'protocol' => 'saml1',
+            ]
+        );
 
-        $sessionLostURL = \SimpleSAML\Utils\HTTP::addURLParameters(
-            \SimpleSAML\Utils\HTTP::getSelfURL(),
-            array('cookieTime' => time()));
+        $sessionLostURL = HTTP::addURLParameters(
+            HTTP::getSelfURL(),
+            ['cookieTime' => time()]
+        );
 
-        $state = array(
-            'Responder' => array('sspmod_saml_IdP_SAML1', 'sendResponse'),
+        $state = [
+            'Responder' => ['\SimpleSAML\Module\saml\IdP\SAML1', 'sendResponse'],
             'SPMetadata' => $spMetadata->toArray(),
-            SimpleSAML_Auth_State::RESTART => $sessionLostURL,
+            \SimpleSAML\Auth\State::RESTART => $sessionLostURL,
             'saml:shire' => $shire,
             'saml:target' => $target,
             'saml:AuthnRequestReceivedAt' => microtime(true),
-        );
+        ];
 
         $idp->handleAuthenticationRequest($state);
     }
diff --git a/modules/saml/lib/IdP/SAML2.php b/modules/saml/lib/IdP/SAML2.php
index 30d95781daa371e5b9b0151b279ab283653b7fb1..cfbb5476d66e4256833cd9a47a1ae84d1f792109 100644
--- a/modules/saml/lib/IdP/SAML2.php
+++ b/modules/saml/lib/IdP/SAML2.php
@@ -1,6 +1,10 @@
 <?php
 
+namespace SimpleSAML\Module\saml\IdP;
+
 use RobRichards\XMLSecLibs\XMLSecurityKey;
+use SimpleSAML\Configuration;
+use SimpleSAML\Logger;
 use SAML2\SOAP;
 
 /**
@@ -8,9 +12,9 @@ use SAML2\SOAP;
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_IdP_SAML2
-{
 
+class SAML2
+{
     /**
      * Send a response to the SP.
      *
@@ -26,19 +30,19 @@ class sspmod_saml_IdP_SAML2
 
         $spMetadata = $state["SPMetadata"];
         $spEntityId = $spMetadata['entityid'];
-        $spMetadata = SimpleSAML_Configuration::loadFromArray(
+        $spMetadata = Configuration::loadFromArray(
             $spMetadata,
             '$metadata['.var_export($spEntityId, true).']'
         );
 
-        SimpleSAML\Logger::info('Sending SAML 2.0 Response to '.var_export($spEntityId, true));
+        Logger::info('Sending SAML 2.0 Response to '.var_export($spEntityId, true));
 
         $requestId = $state['saml:RequestId'];
         $relayState = $state['saml:RelayState'];
         $consumerURL = $state['saml:ConsumerURL'];
         $protocolBinding = $state['saml:Binding'];
 
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = \SimpleSAML\IdP::getByState($state);
 
         $idpMetadata = $idp->getConfig();
 
@@ -49,14 +53,14 @@ class sspmod_saml_IdP_SAML2
         }
 
         // create the session association (for logout)
-        $association = array(
+        $association = [
             'id'                => 'saml:'.$spEntityId,
-            'Handler'           => 'sspmod_saml_IdP_SAML2',
+            'Handler'           => '\SimpleSAML\Module\saml\IdP\SAML2',
             'Expires'           => $assertion->getSessionNotOnOrAfter(),
             'saml:entityID'     => $spEntityId,
             'saml:NameID'       => $state['saml:idp:NameID'],
             'saml:SessionIndex' => $assertion->getSessionIndex(),
-        );
+        ];
 
         // maybe encrypt the assertion
         $assertion = self::encryptAssertion($idpMetadata, $spMetadata, $assertion);
@@ -65,20 +69,20 @@ class sspmod_saml_IdP_SAML2
         $ar = self::buildResponse($idpMetadata, $spMetadata, $consumerURL);
         $ar->setInResponseTo($requestId);
         $ar->setRelayState($relayState);
-        $ar->setAssertions(array($assertion));
+        $ar->setAssertions([$assertion]);
 
         // register the session association with the IdP
         $idp->addAssociation($association);
 
-        $statsData = array(
+        $statsData = [
             'spEntityID'  => $spEntityId,
             'idpEntityID' => $idpMetadata->getString('entityid'),
             'protocol'    => 'saml2',
-        );
+        ];
         if (isset($state['saml:AuthnRequestReceivedAt'])) {
             $statsData['logintime'] = microtime(true) - $state['saml:AuthnRequestReceivedAt'];
         }
-        SimpleSAML_Stats::log('saml:idp:Response', $statsData);
+        \SimpleSAML\Stats::log('saml:idp:Response', $statsData);
 
         // send the response
         $binding = \SAML2\Binding::getBinding($protocolBinding);
@@ -89,11 +93,11 @@ class sspmod_saml_IdP_SAML2
     /**
      * Handle authentication error.
      *
-     * SimpleSAML_Error_Exception $exception  The exception.
+     * \SimpleSAML\Error\Exception $exception  The exception.
      *
      * @param array $state The error state.
      */
-    public static function handleAuthError(SimpleSAML_Error_Exception $exception, array $state)
+    public static function handleAuthError(\SimpleSAML\Error\Exception $exception, array $state)
     {
         assert(isset($state['SPMetadata']));
         assert(isset($state['saml:ConsumerURL']));
@@ -102,7 +106,7 @@ class sspmod_saml_IdP_SAML2
 
         $spMetadata = $state["SPMetadata"];
         $spEntityId = $spMetadata['entityid'];
-        $spMetadata = SimpleSAML_Configuration::loadFromArray(
+        $spMetadata = Configuration::loadFromArray(
             $spMetadata,
             '$metadata['.var_export($spEntityId, true).']'
         );
@@ -112,36 +116,36 @@ class sspmod_saml_IdP_SAML2
         $consumerURL = $state['saml:ConsumerURL'];
         $protocolBinding = $state['saml:Binding'];
 
-        $idp = SimpleSAML_IdP::getByState($state);
+        $idp = \SimpleSAML\IdP::getByState($state);
 
         $idpMetadata = $idp->getConfig();
 
-        $error = sspmod_saml_Error::fromException($exception);
+        $error = \SimpleSAML\Module\saml\Error::fromException($exception);
 
-        SimpleSAML\Logger::warning("Returning error to SP with entity ID '".var_export($spEntityId, true)."'.");
-        $exception->log(SimpleSAML\Logger::WARNING);
+        Logger::warning("Returning error to SP with entity ID '".var_export($spEntityId, true)."'.");
+        $exception->log(Logger::WARNING);
 
         $ar = self::buildResponse($idpMetadata, $spMetadata, $consumerURL);
         $ar->setInResponseTo($requestId);
         $ar->setRelayState($relayState);
 
-        $status = array(
+        $status = [
             'Code'    => $error->getStatus(),
             'SubCode' => $error->getSubStatus(),
             'Message' => $error->getStatusMessage(),
-        );
+        ];
         $ar->setStatus($status);
 
-        $statsData = array(
+        $statsData = [
             'spEntityID'  => $spEntityId,
             'idpEntityID' => $idpMetadata->getString('entityid'),
             'protocol'    => 'saml2',
             'error'       => $status,
-        );
+        ];
         if (isset($state['saml:AuthnRequestReceivedAt'])) {
             $statsData['logintime'] = microtime(true) - $state['saml:AuthnRequestReceivedAt'];
         }
-        SimpleSAML_Stats::log('saml:idp:Response:error', $statsData);
+        \SimpleSAML\Stats::log('saml:idp:Response:error', $statsData);
 
         $binding = \SAML2\Binding::getBinding($protocolBinding);
         $binding->send($ar);
@@ -151,17 +155,17 @@ class sspmod_saml_IdP_SAML2
     /**
      * Find SP AssertionConsumerService based on parameter in AuthnRequest.
      *
-     * @param array                    $supportedBindings The bindings we allow for the response.
-     * @param SimpleSAML_Configuration $spMetadata The metadata for the SP.
-     * @param string|NULL              $AssertionConsumerServiceURL AssertionConsumerServiceURL from request.
-     * @param string|NULL              $ProtocolBinding ProtocolBinding from request.
-     * @param int|NULL                 $AssertionConsumerServiceIndex AssertionConsumerServiceIndex from request.
+     * @param array                     $supportedBindings The bindings we allow for the response.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata for the SP.
+     * @param string|NULL               $AssertionConsumerServiceURL AssertionConsumerServiceURL from request.
+     * @param string|NULL               $ProtocolBinding ProtocolBinding from request.
+     * @param int|NULL                  $AssertionConsumerServiceIndex AssertionConsumerServiceIndex from request.
      *
      * @return array  Array with the Location and Binding we should use for the response.
      */
     private static function getAssertionConsumerService(
         array $supportedBindings,
-        SimpleSAML_Configuration $spMetadata,
+        \SimpleSAML\Configuration $spMetadata,
         $AssertionConsumerServiceURL,
         $ProtocolBinding,
         $AssertionConsumerServiceIndex
@@ -221,15 +225,15 @@ class sspmod_saml_IdP_SAML2
             return $firstFalse;
         }
 
-        SimpleSAML\Logger::warning('Authentication request specifies invalid AssertionConsumerService:');
+        Logger::warning('Authentication request specifies invalid AssertionConsumerService:');
         if ($AssertionConsumerServiceURL !== null) {
-            SimpleSAML\Logger::warning('AssertionConsumerServiceURL: '.var_export($AssertionConsumerServiceURL, true));
+            Logger::warning('AssertionConsumerServiceURL: '.var_export($AssertionConsumerServiceURL, true));
         }
         if ($ProtocolBinding !== null) {
-            SimpleSAML\Logger::warning('ProtocolBinding: '.var_export($ProtocolBinding, true));
+            Logger::warning('ProtocolBinding: '.var_export($ProtocolBinding, true));
         }
         if ($AssertionConsumerServiceIndex !== null) {
-            SimpleSAML\Logger::warning(
+            Logger::warning(
                 'AssertionConsumerServiceIndex: '.var_export($AssertionConsumerServiceIndex, true)
             );
         }
@@ -242,16 +246,15 @@ class sspmod_saml_IdP_SAML2
     /**
      * Receive an authentication request.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are receiving it for.
-     * @throws SimpleSAML_Error_BadRequest In case an error occurs when trying to receive the request.
+     * @param \SimpleSAML\IdP $idp The IdP we are receiving it for.
+     * @throws \SimpleSAML\Error\BadRequest In case an error occurs when trying to receive the request.
      */
-    public static function receiveAuthnRequest(SimpleSAML_IdP $idp)
+    public static function receiveAuthnRequest(\SimpleSAML\IdP $idp)
     {
-
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpMetadata = $idp->getConfig();
 
-        $supportedBindings = array(\SAML2\Constants::BINDING_HTTP_POST);
+        $supportedBindings = [\SAML2\Constants::BINDING_HTTP_POST];
         if ($idpMetadata->getBoolean('saml20.sendartifact', false)) {
             $supportedBindings[] = \SAML2\Constants::BINDING_HTTP_ARTIFACT;
         }
@@ -262,7 +265,7 @@ class sspmod_saml_IdP_SAML2
             $supportedBindings[] = \SAML2\Constants::BINDING_PAOS;
         }
 
-        if (isset($_REQUEST['spentityid'])) {
+        if (isset($_REQUEST['spentityid']) || isset($_REQUEST['providerId'])) {
             /* IdP initiated authentication. */
 
             if (isset($_REQUEST['cookieTime'])) {
@@ -276,11 +279,13 @@ class sspmod_saml_IdP_SAML2
                 }
             }
 
-            $spEntityId = (string) $_REQUEST['spentityid'];
+            $spEntityId = (string) isset($_REQUEST['spentityid']) ? $_REQUEST['spentityid'] : $_REQUEST['providerId'];
             $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
 
             if (isset($_REQUEST['RelayState'])) {
                 $relayState = (string) $_REQUEST['RelayState'];
+            } elseif (isset($_REQUEST['target'])) {
+                $relayState = (string) $_REQUEST['target'];
             } else {
                 $relayState = null;
             }
@@ -297,13 +302,20 @@ class sspmod_saml_IdP_SAML2
                 $nameIDFormat = null;
             }
 
+            if (isset($_REQUEST['ConsumerURL'])) {
+                $consumerURL = (string)$_REQUEST['ConsumerURL'];
+            } elseif (isset($_REQUEST['shire'])) {
+                $consumerURL = (string)$_REQUEST['shire'];
+            } else {
+                $consumerURL = null;
+            }
+
             $requestId = null;
-            $IDPList = array();
+            $IDPList = [];
             $ProxyCount = null;
             $RequesterID = null;
             $forceAuthn = false;
             $isPassive = false;
-            $consumerURL = null;
             $consumerIndex = null;
             $extensions = null;
             $allowCreate = true;
@@ -312,7 +324,7 @@ class sspmod_saml_IdP_SAML2
 
             $idpInit = true;
 
-            SimpleSAML\Logger::info(
+            Logger::info(
                 'SAML2.0 - IdP.SSOService: IdP initiated authentication: '.var_export($spEntityId, true)
             );
         } else {
@@ -320,20 +332,20 @@ class sspmod_saml_IdP_SAML2
             $request = $binding->receive();
 
             if (!($request instanceof \SAML2\AuthnRequest)) {
-                throw new SimpleSAML_Error_BadRequest(
+                throw new \SimpleSAML\Error\BadRequest(
                     'Message received on authentication request endpoint wasn\'t an authentication request.'
                 );
             }
 
             $spEntityId = $request->getIssuer();
             if ($spEntityId === null) {
-                throw new SimpleSAML_Error_BadRequest(
+                throw new \SimpleSAML\Error\BadRequest(
                     'Received message on authentication request endpoint without issuer.'
                 );
             }
             $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
 
-            sspmod_saml_Message::validateMessage($spMetadata, $idpMetadata, $request);
+            \SimpleSAML\Module\saml\Message::validateMessage($spMetadata, $idpMetadata, $request);
 
             $relayState = $request->getRelayState();
 
@@ -366,19 +378,19 @@ class sspmod_saml_IdP_SAML2
 
             $idpInit = false;
 
-            SimpleSAML\Logger::info(
+            Logger::info(
                 'SAML2.0 - IdP.SSOService: incoming authentication request: '.var_export($spEntityId, true)
             );
         }
 
-        SimpleSAML_Stats::log('saml:idp:AuthnRequest', array(
+        \SimpleSAML\Stats::log('saml:idp:AuthnRequest', [
             'spEntityID'  => $spEntityId,
             'idpEntityID' => $idpMetadata->getString('entityid'),
             'forceAuthn'  => $forceAuthn,
             'isPassive'   => $isPassive,
             'protocol'    => 'saml2',
             'idpInit'     => $idpInit,
-        ));
+        ]);
 
         $acsEndpoint = self::getAssertionConsumerService(
             $supportedBindings,
@@ -388,7 +400,7 @@ class sspmod_saml_IdP_SAML2
             $consumerIndex
         );
 
-        $IDPList = array_unique(array_merge($IDPList, $spMetadata->getArrayizeString('IDPList', array())));
+        $IDPList = array_unique(array_merge($IDPList, $spMetadata->getArrayizeString('IDPList', [])));
         if ($ProxyCount === null) {
             $ProxyCount = $spMetadata->getInteger('ProxyCount', null);
         }
@@ -397,23 +409,30 @@ class sspmod_saml_IdP_SAML2
             $forceAuthn = $spMetadata->getBoolean('ForceAuthn', false);
         }
 
-        $sessionLostParams = array(
+        $sessionLostParams = [
             'spentityid' => $spEntityId,
-            'cookieTime' => time(),
-        );
+        ];
         if ($relayState !== null) {
             $sessionLostParams['RelayState'] = $relayState;
         }
+        /*
+        Putting cookieTime as the last parameter makes unit testing easier since we don't need to handle a
+        changing time component in the middle of the url
+        */
+        $sessionLostParams['cookieTime'] = time();
 
         $sessionLostURL = \SimpleSAML\Utils\HTTP::addURLParameters(
             \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(),
             $sessionLostParams
         );
 
-        $state = array(
-            'Responder'                                   => array('sspmod_saml_IdP_SAML2', 'sendResponse'),
-            SimpleSAML_Auth_State::EXCEPTION_HANDLER_FUNC => array('sspmod_saml_IdP_SAML2', 'handleAuthError'),
-            SimpleSAML_Auth_State::RESTART                => $sessionLostURL,
+        $state = [
+            'Responder'                   => ['\SimpleSAML\Module\saml\IdP\SAML2', 'sendResponse'],
+            \SimpleSAML\Auth\State::EXCEPTION_HANDLER_FUNC => [
+                '\SimpleSAML\Module\saml\IdP\SAML2',
+                'handleAuthError'
+            ],
+            \SimpleSAML\Auth\State::RESTART => $sessionLostURL,
 
             'SPMetadata'                  => $spMetadata->toArray(),
             'saml:RelayState'             => $relayState,
@@ -430,7 +449,7 @@ class sspmod_saml_IdP_SAML2
             'saml:Extensions'             => $extensions,
             'saml:AuthnRequestReceivedAt' => microtime(true),
             'saml:RequestedAuthnContext'  => $authnContext,
-        );
+        ];
 
         // ECP AuthnRequests need to supply credentials
         if ($binding instanceof SOAP) {
@@ -443,9 +462,9 @@ class sspmod_saml_IdP_SAML2
     public static function processSOAPAuthnRequest(array &$state)
     {
         if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) {
-            SimpleSAML_Logger::error("ECP AuthnRequest did not contain Basic Authentication header");
+            Logger::error("ECP AuthnRequest did not contain Basic Authentication header");
             // TODO Throw some sort of ECP-specific exception / convert this to SOAP fault
-            throw new SimpleSAML_Error_Error("WRONGUSERPASS");
+            throw new \SimpleSAML\Error\Error("WRONGUSERPASS");
         }
 
         $state['core:auth:username'] = $_SERVER['PHP_AUTH_USER'];
@@ -455,31 +474,31 @@ class sspmod_saml_IdP_SAML2
     /**
      * Send a logout request to a given association.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
-     * @param array          $association The association that should be terminated.
-     * @param string|NULL    $relayState An id that should be carried across the logout.
+     * @param \SimpleSAML\IdP $idp The IdP we are sending a logout request from.
+     * @param array           $association The association that should be terminated.
+     * @param string|NULL     $relayState An id that should be carried across the logout.
      */
-    public static function sendLogoutRequest(SimpleSAML_IdP $idp, array $association, $relayState)
+    public static function sendLogoutRequest(\SimpleSAML\IdP $idp, array $association, $relayState)
     {
         assert(is_string($relayState) || $relayState === null);
 
-        SimpleSAML\Logger::info('Sending SAML 2.0 LogoutRequest to: '.var_export($association['saml:entityID'], true));
+        Logger::info('Sending SAML 2.0 LogoutRequest to: '.var_export($association['saml:entityID'], true));
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpMetadata = $idp->getConfig();
         $spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
 
-        SimpleSAML_Stats::log('saml:idp:LogoutRequest:sent', array(
+        \SimpleSAML\Stats::log('saml:idp:LogoutRequest:sent', [
             'spEntityID'  => $association['saml:entityID'],
             'idpEntityID' => $idpMetadata->getString('entityid'),
-        ));
+        ]);
 
         $dst = $spMetadata->getEndpointPrioritizedByBinding(
             'SingleLogoutService',
-            array(
+            [
                 \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 \SAML2\Constants::BINDING_HTTP_POST
-            )
+            ]
         );
         $binding = \SAML2\Binding::getBinding($dst['Binding']);
         $lr = self::buildLogoutRequest($idpMetadata, $spMetadata, $association, $relayState);
@@ -492,10 +511,10 @@ class sspmod_saml_IdP_SAML2
     /**
      * Send a logout response.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
-     * @param array          &$state The logout state array.
+     * @param \SimpleSAML\IdP $idp The IdP we are sending a logout request from.
+     * @param array           &$state The logout state array.
      */
-    public static function sendLogoutResponse(SimpleSAML_IdP $idp, array $state)
+    public static function sendLogoutResponse(\SimpleSAML\IdP $idp, array $state)
     {
         assert(isset($state['saml:SPEntityId']));
         assert(isset($state['saml:RequestId']));
@@ -503,37 +522,37 @@ class sspmod_saml_IdP_SAML2
 
         $spEntityId = $state['saml:SPEntityId'];
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpMetadata = $idp->getConfig();
         $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
 
-        $lr = sspmod_saml_Message::buildLogoutResponse($idpMetadata, $spMetadata);
+        $lr = \SimpleSAML\Module\saml\Message::buildLogoutResponse($idpMetadata, $spMetadata);
         $lr->setInResponseTo($state['saml:RequestId']);
         $lr->setRelayState($state['saml:RelayState']);
 
         if (isset($state['core:Failed']) && $state['core:Failed']) {
             $partial = true;
-            $lr->setStatus(array(
+            $lr->setStatus([
                 'Code'    => \SAML2\Constants::STATUS_SUCCESS,
                 'SubCode' => \SAML2\Constants::STATUS_PARTIAL_LOGOUT,
-            ));
-            SimpleSAML\Logger::info('Sending logout response for partial logout to SP '.var_export($spEntityId, true));
+            ]);
+            Logger::info('Sending logout response for partial logout to SP '.var_export($spEntityId, true));
         } else {
             $partial = false;
-            SimpleSAML\Logger::debug('Sending logout response to SP '.var_export($spEntityId, true));
+            Logger::debug('Sending logout response to SP '.var_export($spEntityId, true));
         }
 
-        SimpleSAML_Stats::log('saml:idp:LogoutResponse:sent', array(
+        \SimpleSAML\Stats::log('saml:idp:LogoutResponse:sent', [
             'spEntityID'  => $spEntityId,
             'idpEntityID' => $idpMetadata->getString('entityid'),
             'partial'     => $partial
-        ));
+        ]);
         $dst = $spMetadata->getEndpointPrioritizedByBinding(
             'SingleLogoutService',
-            array(
+            [
                 \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 \SAML2\Constants::BINDING_HTTP_POST
-            )
+            ]
         );
         $binding = \SAML2\Binding::getBinding($dst['Binding']);
         if (isset($dst['ResponseLocation'])) {
@@ -550,43 +569,42 @@ class sspmod_saml_IdP_SAML2
     /**
      * Receive a logout message.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are receiving it for.
-     * @throws SimpleSAML_Error_BadRequest In case an error occurs while trying to receive the logout message.
+     * @param \SimpleSAML\IdP $idp The IdP we are receiving it for.
+     * @throws \SimpleSAML\Error\BadRequest In case an error occurs while trying to receive the logout message.
      */
-    public static function receiveLogoutMessage(SimpleSAML_IdP $idp)
+    public static function receiveLogoutMessage(\SimpleSAML\IdP $idp)
     {
-
         $binding = \SAML2\Binding::getCurrentBinding();
         $message = $binding->receive();
 
         $spEntityId = $message->getIssuer();
         if ($spEntityId === null) {
             /* Without an issuer we have no way to respond to the message. */
-            throw new SimpleSAML_Error_BadRequest('Received message on logout endpoint without issuer.');
+            throw new \SimpleSAML\Error\BadRequest('Received message on logout endpoint without issuer.');
         }
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpMetadata = $idp->getConfig();
         $spMetadata = $metadata->getMetaDataConfig($spEntityId, 'saml20-sp-remote');
 
-        sspmod_saml_Message::validateMessage($spMetadata, $idpMetadata, $message);
+        \SimpleSAML\Module\saml\Message::validateMessage($spMetadata, $idpMetadata, $message);
 
         if ($message instanceof \SAML2\LogoutResponse) {
-            SimpleSAML\Logger::info('Received SAML 2.0 LogoutResponse from: '.var_export($spEntityId, true));
-            $statsData = array(
+            Logger::info('Received SAML 2.0 LogoutResponse from: '.var_export($spEntityId, true));
+            $statsData = [
                 'spEntityID'  => $spEntityId,
                 'idpEntityID' => $idpMetadata->getString('entityid'),
-            );
+            ];
             if (!$message->isSuccess()) {
                 $statsData['error'] = $message->getStatus();
             }
-            SimpleSAML_Stats::log('saml:idp:LogoutResponse:recv', $statsData);
+            \SimpleSAML\Stats::log('saml:idp:LogoutResponse:recv', $statsData);
 
             $relayState = $message->getRelayState();
 
             if (!$message->isSuccess()) {
-                $logoutError = sspmod_saml_Message::getResponseError($message);
-                SimpleSAML\Logger::warning('Unsuccessful logout. Status was: '.$logoutError);
+                $logoutError = \SimpleSAML\Module\saml\Message::getResponseError($message);
+                Logger::warning('Unsuccessful logout. Status was: '.$logoutError);
             } else {
                 $logoutError = null;
             }
@@ -595,26 +613,26 @@ class sspmod_saml_IdP_SAML2
 
             $idp->handleLogoutResponse($assocId, $relayState, $logoutError);
         } elseif ($message instanceof \SAML2\LogoutRequest) {
-            SimpleSAML\Logger::info('Received SAML 2.0 LogoutRequest from: '.var_export($spEntityId, true));
-            SimpleSAML_Stats::log('saml:idp:LogoutRequest:recv', array(
+            Logger::info('Received SAML 2.0 LogoutRequest from: '.var_export($spEntityId, true));
+            \SimpleSAML\Stats::log('saml:idp:LogoutRequest:recv', [
                 'spEntityID'  => $spEntityId,
                 'idpEntityID' => $idpMetadata->getString('entityid'),
-            ));
+            ]);
 
             $spStatsId = $spMetadata->getString('core:statistics-id', $spEntityId);
-            SimpleSAML\Logger::stats('saml20-idp-SLO spinit '.$spStatsId.' '.$idpMetadata->getString('entityid'));
+            Logger::stats('saml20-idp-SLO spinit '.$spStatsId.' '.$idpMetadata->getString('entityid'));
 
-            $state = array(
-                'Responder'       => array('sspmod_saml_IdP_SAML2', 'sendLogoutResponse'),
+            $state = [
+                'Responder'       => ['\SimpleSAML\Module\saml\IdP\SAML2', 'sendLogoutResponse'],
                 'saml:SPEntityId' => $spEntityId,
                 'saml:RelayState' => $message->getRelayState(),
                 'saml:RequestId'  => $message->getId(),
-            );
+            ];
 
             $assocId = 'saml:'.$spEntityId;
             $idp->handleLogoutRequest($state, $assocId);
         } else {
-            throw new SimpleSAML_Error_BadRequest('Unknown message received on logout endpoint: '.get_class($message));
+            throw new \SimpleSAML\Error\BadRequest('Unknown message received on logout endpoint: '.get_class($message));
         }
     }
 
@@ -622,34 +640,34 @@ class sspmod_saml_IdP_SAML2
     /**
      * Retrieve a logout URL for a given logout association.
      *
-     * @param SimpleSAML_IdP $idp The IdP we are sending a logout request from.
-     * @param array          $association The association that should be terminated.
-     * @param string|NULL    $relayState An id that should be carried across the logout.
+     * @param \SimpleSAML\IdP $idp The IdP we are sending a logout request from.
+     * @param array           $association The association that should be terminated.
+     * @param string|NULL     $relayState An id that should be carried across the logout.
      *
      * @return string The logout URL.
      */
-    public static function getLogoutURL(SimpleSAML_IdP $idp, array $association, $relayState)
+    public static function getLogoutURL(\SimpleSAML\IdP $idp, array $association, $relayState)
     {
         assert(is_string($relayState) || $relayState === null);
 
-        SimpleSAML\Logger::info('Sending SAML 2.0 LogoutRequest to: '.var_export($association['saml:entityID'], true));
+        Logger::info('Sending SAML 2.0 LogoutRequest to: '.var_export($association['saml:entityID'], true));
 
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $idpMetadata = $idp->getConfig();
         $spMetadata = $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
 
-        $bindings = array(
+        $bindings = [
             \SAML2\Constants::BINDING_HTTP_REDIRECT,
             \SAML2\Constants::BINDING_HTTP_POST
-        );
+        ];
         $dst = $spMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', $bindings);
 
         if ($dst['Binding'] === \SAML2\Constants::BINDING_HTTP_POST) {
-            $params = array('association' => $association['id'], 'idp' => $idp->getId());
+            $params = ['association' => $association['id'], 'idp' => $idp->getId()];
             if ($relayState !== null) {
                 $params['RelayState'] = $relayState;
             }
-            return SimpleSAML\Module::getModuleURL('core/idp/logout-iframe-post.php', $params);
+            return \SimpleSAML\Module::getModuleURL('core/idp/logout-iframe-post.php', $params);
         }
 
         $lr = self::buildLogoutRequest($idpMetadata, $spMetadata, $association, $relayState);
@@ -663,18 +681,18 @@ class sspmod_saml_IdP_SAML2
     /**
      * Retrieve the metadata for the given SP association.
      *
-     * @param SimpleSAML_IdP $idp The IdP the association belongs to.
-     * @param array          $association The SP association.
+     * @param \SimpleSAML\IdP $idp The IdP the association belongs to.
+     * @param array           $association The SP association.
      *
-     * @return SimpleSAML_Configuration  Configuration object for the SP metadata.
+     * @return \SimpleSAML\Configuration  Configuration object for the SP metadata.
      */
-    public static function getAssociationConfig(SimpleSAML_IdP $idp, array $association)
+    public static function getAssociationConfig(\SimpleSAML\IdP $idp, array $association)
     {
-        $metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         try {
             return $metadata->getMetaDataConfig($association['saml:entityID'], 'saml20-sp-remote');
-        } catch (Exception $e) {
-            return SimpleSAML_Configuration::loadFromArray(array(), 'Unknown SAML 2 entity.');
+        } catch (\Exception $e) {
+            return Configuration::loadFromArray([], 'Unknown SAML 2 entity.');
         }
     }
 
@@ -682,15 +700,15 @@ class sspmod_saml_IdP_SAML2
     /**
      * Calculate the NameID value that should be used.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
-     * @param array                    &$state The authentication state of the user.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
+     * @param array                     &$state The authentication state of the user.
      *
-     * @return string  The NameID value.
+     * @return string|null The NameID value.
      */
     private static function generateNameIdValue(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         array &$state
     ) {
 
@@ -699,14 +717,14 @@ class sspmod_saml_IdP_SAML2
             $attribute = $idpMetadata->getString('simplesaml.nameidattribute', null);
             if ($attribute === null) {
                 if (!isset($state['UserID'])) {
-                    SimpleSAML\Logger::error('Unable to generate NameID. Check the userid.attribute option.');
+                    Logger::error('Unable to generate NameID. Check the userid.attribute option.');
                     return null;
                 }
                 $attributeValue = $state['UserID'];
                 $idpEntityId = $idpMetadata->getString('entityid');
                 $spEntityId = $spMetadata->getString('entityid');
 
-                $secretSalt = SimpleSAML\Utils\Config::getSecretSalt();
+                $secretSalt = \SimpleSAML\Utils\Config::getSecretSalt();
 
                 $uidData = 'uidhashbase'.$secretSalt;
                 $uidData .= strlen($idpEntityId).':'.$idpEntityId;
@@ -720,7 +738,7 @@ class sspmod_saml_IdP_SAML2
 
         $attributes = $state['Attributes'];
         if (!array_key_exists($attribute, $attributes)) {
-            SimpleSAML\Logger::error('Unable to add NameID: Missing '.var_export($attribute, true).
+            Logger::error('Unable to add NameID: Missing '.var_export($attribute, true).
                 ' in the attributes of the user.');
             return null;
         }
@@ -732,20 +750,19 @@ class sspmod_saml_IdP_SAML2
     /**
      * Helper function for encoding attributes.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
      * @param array $attributes The attributes of the user.
      *
      * @return array  The encoded attributes.
      *
-     * @throws SimpleSAML_Error_Exception In case an unsupported encoding is specified by configuration.
+     * @throws \SimpleSAML\Error\Exception In case an unsupported encoding is specified by configuration.
      */
     private static function encodeAttributes(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         array $attributes
     ) {
-
         $base64Attributes = $spMetadata->getBoolean('base64attributes', null);
         if ($base64Attributes === null) {
             $base64Attributes = $idpMetadata->getBoolean('base64attributes', false);
@@ -757,8 +774,8 @@ class sspmod_saml_IdP_SAML2
             $defaultEncoding = 'string';
         }
 
-        $srcEncodings = $idpMetadata->getArray('attributeencodings', array());
-        $dstEncodings = $spMetadata->getArray('attributeencodings', array());
+        $srcEncodings = $idpMetadata->getArray('attributeencodings', []);
+        $dstEncodings = $spMetadata->getArray('attributeencodings', []);
 
         /*
          * Merge the two encoding arrays. Encodings specified in the target metadata
@@ -766,9 +783,9 @@ class sspmod_saml_IdP_SAML2
          */
         $encodings = array_merge($srcEncodings, $dstEncodings);
 
-        $ret = array();
+        $ret = [];
         foreach ($attributes as $name => $values) {
-            $ret[$name] = array();
+            $ret[$name] = [];
             if (array_key_exists($name, $encodings)) {
                 $encoding = $encodings[$name];
             } else {
@@ -783,7 +800,7 @@ class sspmod_saml_IdP_SAML2
                 }
 
                 $attrval = $value;
-                if ($value instanceof DOMNodeList) {
+                if ($value instanceof \DOMNodeList) {
                     $attrval = new \SAML2\XML\saml\AttributeValue($value->item(0)->parentNode);
                 }
 
@@ -799,10 +816,10 @@ class sspmod_saml_IdP_SAML2
                             $doc = \SAML2\DOMDocumentFactory::fromString('<root>'.$value.'</root>');
                             $value = $doc->firstChild->childNodes;
                         }
-                        assert($value instanceof DOMNodeList || $value instanceof \SAML2\XML\saml\NameID);
+                        assert($value instanceof \DOMNodeList || $value instanceof \SAML2\XML\saml\NameID);
                         break;
                     default:
-                        throw new SimpleSAML_Error_Exception('Invalid encoding for attribute '.
+                        throw new \SimpleSAML\Error\Exception('Invalid encoding for attribute '.
                             var_export($name, true).': '.var_export($encoding, true));
                 }
                 $ret[$name][] = $value;
@@ -816,16 +833,15 @@ class sspmod_saml_IdP_SAML2
     /**
      * Determine which NameFormat we should use for attributes.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
      *
      * @return string  The NameFormat.
      */
     private static function getAttributeNameFormat(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata
+        Configuration $idpMetadata,
+        Configuration $spMetadata
     ) {
-
         // try SP metadata first
         $attributeNameFormat = $spMetadata->getString('attributes.NameFormat', null);
         if ($attributeNameFormat !== null) {
@@ -854,17 +870,17 @@ class sspmod_saml_IdP_SAML2
     /**
      * Build an assertion based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
      * @param array &$state The state array with information about the request.
      *
      * @return \SAML2\Assertion  The assertion.
      *
-     * @throws SimpleSAML_Error_Exception In case an error occurs when creating a holder-of-key assertion.
+     * @throws \SimpleSAML\Error\Exception In case an error occurs when creating a holder-of-key assertion.
      */
     private static function buildAssertion(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         array &$state
     ) {
         assert(isset($state['Attributes']));
@@ -877,15 +893,15 @@ class sspmod_saml_IdP_SAML2
             $signAssertion = $idpMetadata->getBoolean('saml20.sign.assertion', true);
         }
 
-        $config = SimpleSAML_Configuration::getInstance();
+        $config = Configuration::getInstance();
 
         $a = new \SAML2\Assertion();
         if ($signAssertion) {
-            sspmod_saml_Message::addSign($idpMetadata, $spMetadata, $a);
+            \SimpleSAML\Module\saml\Message::addSign($idpMetadata, $spMetadata, $a);
         }
 
         $a->setIssuer($idpMetadata->getString('entityid'));
-        $a->setValidAudiences(array($spMetadata->getString('entityid')));
+        $a->setValidAudiences([$spMetadata->getString('entityid')]);
 
         $a->setNotBefore($now - 30);
 
@@ -896,9 +912,11 @@ class sspmod_saml_IdP_SAML2
         $a->setNotOnOrAfter($now + $assertionLifetime);
 
         if (isset($state['saml:AuthnContextClassRef'])) {
-            $a->setAuthnContext($state['saml:AuthnContextClassRef']);
+            $a->setAuthnContextClassRef($state['saml:AuthnContextClassRef']);
+        } elseif (\SimpleSAML\Utils\HTTP::isHTTPS()) {
+            $a->setAuthnContextClassRef(\SAML2\Constants::AC_PASSWORD_PROTECTED_TRANSPORT);
         } else {
-            $a->setAuthnContext(\SAML2\Constants::AC_PASSWORD);
+            $a->setAuthnContextClassRef(\SAML2\Constants::AC_PASSWORD);
         }
 
         $sessionStart = $now;
@@ -910,7 +928,7 @@ class sspmod_saml_IdP_SAML2
         $sessionLifetime = $config->getInteger('session.duration', 8 * 60 * 60);
         $a->setSessionNotOnOrAfter($sessionStart + $sessionLifetime);
 
-        $a->setSessionIndex(SimpleSAML\Utils\Random::generateID());
+        $a->setSessionIndex(\SimpleSAML\Utils\Random::generateID());
 
         $sc = new \SAML2\XML\saml\SubjectConfirmation();
         $sc->SubjectConfirmationData = new \SAML2\XML\saml\SubjectConfirmationData();
@@ -938,7 +956,7 @@ class sspmod_saml_IdP_SAML2
                     if (preg_match($pattern, $clientCert, $matches)) {
                         // we have a client certificate from the browser which we add to the HoK assertion
                         $x509Certificate = new \SAML2\XML\ds\X509Certificate();
-                        $x509Certificate->certificate = str_replace(array("\r", "\n", " "), '', $matches[1]);
+                        $x509Certificate->certificate = str_replace(["\r", "\n", " "], '', $matches[1]);
 
                         $x509Data = new \SAML2\XML\ds\X509Data();
                         $x509Data->data[] = $x509Certificate;
@@ -948,18 +966,18 @@ class sspmod_saml_IdP_SAML2
 
                         $sc->SubjectConfirmationData->info[] = $keyInfo;
                     } else {
-                        throw new SimpleSAML_Error_Exception(
+                        throw new \SimpleSAML\Error\Exception(
                             'Error creating HoK assertion: No valid client certificate provided during TLS handshake '.
                             'with IdP'
                         );
                     }
                 } else {
-                    throw new SimpleSAML_Error_Exception(
+                    throw new \SimpleSAML\Error\Exception(
                         'Error creating HoK assertion: No client certificate provided during TLS handshake with IdP'
                     );
                 }
             } else {
-                throw new SimpleSAML_Error_Exception(
+                throw new \SimpleSAML\Error\Exception(
                     'Error creating HoK assertion: No HTTPS connection to IdP, but required for Holder-of-Key SSO'
                 );
             }
@@ -967,7 +985,7 @@ class sspmod_saml_IdP_SAML2
             // Bearer
             $sc->Method = \SAML2\Constants::CM_BEARER;
         }
-        $a->setSubjectConfirmation(array($sc));
+        $a->setSubjectConfirmation([$sc]);
 
         // add attributes
         if ($spMetadata->getBoolean('simplesaml.attributes', true)) {
@@ -986,9 +1004,9 @@ class sspmod_saml_IdP_SAML2
 
         if ($nameIdFormat === null || !isset($state['saml:NameID'][$nameIdFormat])) {
             // either not set in request, or not set to a format we supply. Fall back to old generation method
-            $nameIdFormat = $spMetadata->getString('NameIDFormat', null);
+            $nameIdFormat = current($spMetadata->getArrayizeString('NameIDFormat', null));
             if ($nameIdFormat === null) {
-                $nameIdFormat = $idpMetadata->getString('NameIDFormat', \SAML2\Constants::NAMEID_TRANSIENT);
+                $nameIdFormat = current($idpMetadata->getArrayizeString('NameIDFormat', \SAML2\Constants::NAMEID_TRANSIENT));
             }
         }
 
@@ -1003,15 +1021,15 @@ class sspmod_saml_IdP_SAML2
 
             if ($nameIdFormat === \SAML2\Constants::NAMEID_TRANSIENT) {
                 // generate a random id
-                $nameIdValue = SimpleSAML\Utils\Random::generateID();
+                $nameIdValue = \SimpleSAML\Utils\Random::generateID();
             } else {
                 /* this code will end up generating either a fixed assigned id (via nameid.attribute)
                    or random id if not assigned/configured */
                 $nameIdValue = self::generateNameIdValue($idpMetadata, $spMetadata, $state);
                 if ($nameIdValue === null) {
-                    SimpleSAML\Logger::warning('Falling back to transient NameID.');
+                    Logger::warning('Falling back to transient NameID.');
                     $nameIdFormat = \SAML2\Constants::NAMEID_TRANSIENT;
-                    $nameIdValue = SimpleSAML\Utils\Random::generateID();
+                    $nameIdValue = \SimpleSAML\Utils\Random::generateID();
                 }
             }
 
@@ -1030,7 +1048,7 @@ class sspmod_saml_IdP_SAML2
             $encryptNameId = $idpMetadata->getBoolean('nameid.encryption', false);
         }
         if ($encryptNameId) {
-            $a->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
+            $a->encryptNameId(\SimpleSAML\Module\saml\Message::getEncryptionKey($spMetadata));
         }
 
         return $a;
@@ -1043,20 +1061,19 @@ class sspmod_saml_IdP_SAML2
      * This function takes in a \SAML2\Assertion and encrypts it if encryption of
      * assertions are enabled in the metadata.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
      * @param \SAML2\Assertion $assertion The assertion we are encrypting.
      *
      * @return \SAML2\Assertion|\SAML2\EncryptedAssertion  The assertion.
      *
-     * @throws SimpleSAML_Error_Exception In case the encryption key type is not supported.
+     * @throws \SimpleSAML\Error\Exception In case the encryption key type is not supported.
      */
     private static function encryptAssertion(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         \SAML2\Assertion $assertion
     ) {
-
         $encryptAssertion = $spMetadata->getBoolean('assertion.encryption', null);
         if ($encryptAssertion === null) {
             $encryptAssertion = $idpMetadata->getBoolean('assertion.encryption', false);
@@ -1082,17 +1099,17 @@ class sspmod_saml_IdP_SAML2
                             "-----END CERTIFICATE-----\n";
                         break;
                     default:
-                        throw new SimpleSAML_Error_Exception('Unsupported encryption key type: '.$key['type']);
+                        throw new \SimpleSAML\Error\Exception('Unsupported encryption key type: '.$key['type']);
                 }
 
                 // extract the public key from the certificate for encryption
-                $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
+                $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, ['type' => 'public']);
                 $key->loadKey($pemKey);
             } else {
-                throw new SimpleSAML_Error_ConfigurationError(
-                    'Missing encryption key for entity `' . $spMetadata->getString('entityid') . '`',
-                    null,
-                    $spMetadata->getString('metadata-set') . '.php'
+                throw new \SimpleSAML\Error\ConfigurationError(
+                    'Missing encryption key for entity `'.$spMetadata->getString('entityid').'`',
+                    $spMetadata->getString('metadata-set').'.php',
+                    null
                 );
             }
         }
@@ -1106,21 +1123,20 @@ class sspmod_saml_IdP_SAML2
     /**
      * Build a logout request based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
      * @param array $association The SP association.
      * @param string|null $relayState An id that should be carried across the logout.
      *
-     * @return \SAML2\LogoutResponse The corresponding SAML2 logout response.
+     * @return \SAML2\LogoutRequest The corresponding SAML2 logout request.
      */
     private static function buildLogoutRequest(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         array $association,
         $relayState
     ) {
-
-        $lr = sspmod_saml_Message::buildLogoutRequest($idpMetadata, $spMetadata);
+        $lr = \SimpleSAML\Module\saml\Message::buildLogoutRequest($idpMetadata, $spMetadata);
         $lr->setRelayState($relayState);
         $lr->setSessionIndex($association['saml:SessionIndex']);
         $lr->setNameId($association['saml:NameID']);
@@ -1136,7 +1152,7 @@ class sspmod_saml_IdP_SAML2
             $encryptNameId = $idpMetadata->getBoolean('nameid.encryption', false);
         }
         if ($encryptNameId) {
-            $lr->encryptNameId(sspmod_saml_Message::getEncryptionKey($spMetadata));
+            $lr->encryptNameId(\SimpleSAML\Module\saml\Message::getEncryptionKey($spMetadata));
         }
 
         return $lr;
@@ -1146,18 +1162,17 @@ class sspmod_saml_IdP_SAML2
     /**
      * Build a authentication response based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP.
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the SP.
-     * @param string                   $consumerURL The Destination URL of the response.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the IdP.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the SP.
+     * @param string                    $consumerURL The Destination URL of the response.
      *
-     * @return \SAML2\Response The SAML2 response corresponding to the given data.
+     * @return \SAML2\Response The SAML2 Response corresponding to the given data.
      */
     private static function buildResponse(
-        SimpleSAML_Configuration $idpMetadata,
-        SimpleSAML_Configuration $spMetadata,
+        Configuration $idpMetadata,
+        Configuration $spMetadata,
         $consumerURL
     ) {
-
         $signResponse = $spMetadata->getBoolean('saml20.sign.response', null);
         if ($signResponse === null) {
             $signResponse = $idpMetadata->getBoolean('saml20.sign.response', true);
@@ -1169,7 +1184,7 @@ class sspmod_saml_IdP_SAML2
         $r->setDestination($consumerURL);
 
         if ($signResponse) {
-            sspmod_saml_Message::addSign($idpMetadata, $spMetadata, $r);
+            \SimpleSAML\Module\saml\Message::addSign($idpMetadata, $spMetadata, $r);
         }
 
         return $r;
diff --git a/modules/saml/lib/IdP/SQLNameID.php b/modules/saml/lib/IdP/SQLNameID.php
index 8111f5e231e85ac9d99760cc6a54a95a6a396691..95d5712df26a64a808b072144af9e397b905acee 100644
--- a/modules/saml/lib/IdP/SQLNameID.php
+++ b/modules/saml/lib/IdP/SQLNameID.php
@@ -1,11 +1,14 @@
 <?php
 
+namespace SimpleSAML\Module\saml\IdP;
+
 /**
  * Helper class for working with persistent NameIDs stored in SQL datastore.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_IdP_SQLNameID
+
+class SQLNameID
 {
     /**
      * Create NameID table in SQL, if it is missing.
@@ -18,7 +21,7 @@ class sspmod_saml_IdP_SQLNameID
             return;
         }
 
-        $query = 'CREATE TABLE ' . $store->prefix . '_saml_PersistentNameID (
+        $query = 'CREATE TABLE '.$store->prefix.'_saml_PersistentNameID (
             _idp VARCHAR(256) NOT NULL,
             _sp VARCHAR(256) NOT NULL,
             _user VARCHAR(256) NOT NULL,
@@ -27,7 +30,8 @@ class sspmod_saml_IdP_SQLNameID
         )';
         $store->pdo->exec($query);
 
-        $query = 'CREATE INDEX ' . $store->prefix . '_saml_PersistentNameID_idp_sp ON '  . $store->prefix . '_saml_PersistentNameID (_idp, _sp)';
+        $query = 'CREATE INDEX '.$store->prefix.'_saml_PersistentNameID_idp_sp ON ';
+        $query .= $store->prefix.'_saml_PersistentNameID (_idp, _sp)';
         $store->pdo->exec($query);
 
         $store->setTableVersion('saml_PersistentNameID', 1);
@@ -45,7 +49,9 @@ class sspmod_saml_IdP_SQLNameID
     {
         $store = \SimpleSAML\Store::getInstance();
         if (!($store instanceof \SimpleSAML\Store\SQL)) {
-            throw new SimpleSAML_Error_Exception('SQL NameID store requires SimpleSAMLphp to be configured with a SQL datastore.');
+            throw new \SimpleSAML\Error\Exception(
+                'SQL NameID store requires SimpleSAMLphp to be configured with a SQL datastore.'
+            );
         }
 
         self::createTable($store);
@@ -72,14 +78,15 @@ class sspmod_saml_IdP_SQLNameID
 
         $store = self::getStore();
 
-        $params = array(
+        $params = [
             '_idp' => $idpEntityId,
             '_sp' => $spEntityId,
             '_user' => $user,
             '_value' => $value,
-        );
+        ];
 
-        $query = 'INSERT INTO ' . $store->prefix . '_saml_PersistentNameID (_idp, _sp, _user, _value) VALUES(:_idp, :_sp, :_user, :_value)';
+        $query = 'INSERT INTO '.$store->prefix;
+        $query .= '_saml_PersistentNameID (_idp, _sp, _user, _value) VALUES(:_idp, :_sp, :_user, :_value)';
         $query = $store->pdo->prepare($query);
         $query->execute($params);
     }
@@ -101,17 +108,18 @@ class sspmod_saml_IdP_SQLNameID
 
         $store = self::getStore();
 
-        $params = array(
+        $params = [
             '_idp' => $idpEntityId,
             '_sp' => $spEntityId,
             '_user' => $user,
-        );
+        ];
 
-        $query = 'SELECT _value FROM ' . $store->prefix . '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp AND _user = :_user';
+        $query = 'SELECT _value FROM '.$store->prefix;
+        $query .= '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp AND _user = :_user';
         $query = $store->pdo->prepare($query);
         $query->execute($params);
 
-        $row = $query->fetch(PDO::FETCH_ASSOC);
+        $row = $query->fetch(\PDO::FETCH_ASSOC);
         if ($row === false) {
             // No NameID found
             return null;
@@ -136,13 +144,14 @@ class sspmod_saml_IdP_SQLNameID
 
         $store = self::getStore();
 
-        $params = array(
+        $params = [
             '_idp' => $idpEntityId,
             '_sp' => $spEntityId,
             '_user' => $user,
-        );
+        ];
 
-        $query = 'DELETE FROM ' . $store->prefix . '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp AND _user = :_user';
+        $query = 'DELETE FROM '.$store->prefix;
+        $query .= '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp AND _user = :_user';
         $query = $store->pdo->prepare($query);
         $query->execute($params);
     }
@@ -162,17 +171,18 @@ class sspmod_saml_IdP_SQLNameID
 
         $store = self::getStore();
 
-        $params = array(
+        $params = [
             '_idp' => $idpEntityId,
             '_sp' => $spEntityId,
-        );
+        ];
 
-        $query = 'SELECT _user, _value FROM ' . $store->prefix . '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp';
+        $query = 'SELECT _user, _value FROM '.$store->prefix;
+        $query .= '_saml_PersistentNameID WHERE _idp = :_idp AND _sp = :_sp';
         $query = $store->pdo->prepare($query);
         $query->execute($params);
 
-        $res = array();
-        while (($row = $query->fetch(PDO::FETCH_ASSOC)) !== false) {
+        $res = [];
+        while (($row = $query->fetch(\PDO::FETCH_ASSOC)) !== false) {
             $res[$row['_user']] = $row['_value'];
         }
 
diff --git a/modules/saml/lib/Message.php b/modules/saml/lib/Message.php
index a42d3e34df98e805602eb8e0b7f44064c5b9a5f9..bae83698334d8a9d82a7255040ff689e2fe360a7 100644
--- a/modules/saml/lib/Message.php
+++ b/modules/saml/lib/Message.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\saml;
+
 use RobRichards\XMLSecLibs\XMLSecurityKey;
 
 /**
@@ -7,47 +9,36 @@ use RobRichards\XMLSecLibs\XMLSecurityKey;
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_Message
+class Message
 {
-
     /**
      * Add signature key and sender certificate to an element (Message or Assertion).
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      * @param \SAML2\SignedElement $element The element we should add the data to.
      */
     public static function addSign(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata,
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata,
         \SAML2\SignedElement $element
     ) {
         $dstPrivateKey = $dstMetadata->getString('signature.privatekey', null);
 
         if ($dstPrivateKey !== null) {
-            $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true, 'signature.');
-            $certArray = SimpleSAML\Utils\Crypto::loadPublicKey($dstMetadata, false, 'signature.');
+            $keyArray = \SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true, 'signature.');
+            $certArray = \SimpleSAML\Utils\Crypto::loadPublicKey($dstMetadata, false, 'signature.');
         } else {
-            $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($srcMetadata, true);
-            $certArray = SimpleSAML\Utils\Crypto::loadPublicKey($srcMetadata, false);
+            $keyArray = \SimpleSAML\Utils\Crypto::loadPrivateKey($srcMetadata, true);
+            $certArray = \SimpleSAML\Utils\Crypto::loadPublicKey($srcMetadata, false);
         }
 
         $algo = $dstMetadata->getString('signature.algorithm', null);
         if ($algo === null) {
-            /*
-             * In the NIST Special Publication 800-131A, SHA-1 became deprecated for generating
-             * new digital signatures in 2011, and will be explicitly disallowed starting the 1st
-             * of January, 2014. We'll keep this as a default for the next release and mark it
-             * as deprecated, as part of the transition to SHA-256.
-             *
-             * See http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf for more info.
-             *
-             * TODO: change default to XMLSecurityKey::RSA_SHA256.
-             */
-            $algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA1);
-        }
-
-        $privateKey = new XMLSecurityKey($algo, array('type' => 'private'));
+            $algo = $srcMetadata->getString('signature.algorithm', XMLSecurityKey::RSA_SHA256);
+        }
+
+        $privateKey = new XMLSecurityKey($algo, ['type' => 'private']);
         if (array_key_exists('password', $keyArray)) {
             $privateKey->passphrase = $keyArray['password'];
         }
@@ -65,20 +56,20 @@ class sspmod_saml_Message
             return;
         }
 
-        $element->setCertificates(array($certArray['PEM']));
+        $element->setCertificates([$certArray['PEM']]);
     }
 
 
     /**
      * Add signature key and and senders certificate to message.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      * @param \SAML2\Message $message The message we should add the data to.
      */
     private static function addRedirectSign(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata,
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata,
         \SAML2\Message $message
     ) {
 
@@ -119,11 +110,11 @@ class sspmod_saml_Message
      *
      * @return string Certificate, in PEM-format.
      *
-     * @throws SimpleSAML_Error_Exception if we cannot find the certificate matching the fingerprint.
+     * @throws \SimpleSAML\Error\Exception if we cannot find the certificate matching the fingerprint.
      */
     private static function findCertificate(array $certFingerprints, array $certificates)
     {
-        $candidates = array();
+        $candidates = [];
 
         foreach ($certificates as $cert) {
             $fp = strtolower(sha1(base64_decode($cert)));
@@ -141,7 +132,7 @@ class sspmod_saml_Message
 
         $candidates = "'".implode("', '", $candidates)."'";
         $fps = "'".implode("', '", $certFingerprints)."'";
-        throw new SimpleSAML_Error_Exception('Unable to find a certificate matching the configured '.
+        throw new \SimpleSAML\Error\Exception('Unable to find a certificate matching the configured '.
             'fingerprint. Candidates: '.$candidates.'; certFingerprint: '.$fps.'.');
     }
 
@@ -149,19 +140,19 @@ class sspmod_saml_Message
     /**
      * Check the signature on a SAML2 message or assertion.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
      * @param \SAML2\SignedElement $element Either a \SAML2\Response or a \SAML2\Assertion.
      * @return boolean True if the signature is correct, false otherwise.
      *
-     * @throws \SimpleSAML_Error_Exception if there is not certificate in the metadata for the entity.
+     * @throws \SimpleSAML\Error\Exception if there is not certificate in the metadata for the entity.
      * @throws \Exception if the signature validation fails with an exception.
      */
-    public static function checkSign(SimpleSAML_Configuration $srcMetadata, \SAML2\SignedElement $element)
+    public static function checkSign(\SimpleSAML\Configuration $srcMetadata, \SAML2\SignedElement $element)
     {
         // find the public key that should verify signatures by this entity
         $keys = $srcMetadata->getPublicKeys('signing');
         if (!empty($keys)) {
-            $pemKeys = array();
+            $pemKeys = [];
             foreach ($keys as $key) {
                 switch ($key['type']) {
                     case 'X509Certificate':
@@ -170,11 +161,11 @@ class sspmod_saml_Message
                             "-----END CERTIFICATE-----\n";
                         break;
                     default:
-                        SimpleSAML\Logger::debug('Skipping unknown key type: '.$key['type']);
+                        \SimpleSAML\Logger::debug('Skipping unknown key type: '.$key['type']);
                 }
             }
         } elseif ($srcMetadata->hasValue('certFingerprint')) {
-            SimpleSAML\Logger::notice(
+            \SimpleSAML\Logger::notice(
                 "Validating certificates by fingerprint is deprecated. Please use ".
                 "certData or certificate options in your remote metadata configuration."
             );
@@ -189,38 +180,38 @@ class sspmod_saml_Message
             // we don't have the full certificate stored. Try to find it in the message or the assertion instead
             if (count($certificates) === 0) {
                 /* We need the full certificate in order to match it against the fingerprint. */
-                SimpleSAML\Logger::debug('No certificate in message when validating against fingerprint.');
+                \SimpleSAML\Logger::debug('No certificate in message when validating against fingerprint.');
                 return false;
             } else {
-                SimpleSAML\Logger::debug('Found '.count($certificates).' certificates in '.get_class($element));
+                \SimpleSAML\Logger::debug('Found '.count($certificates).' certificates in '.get_class($element));
             }
 
             $pemCert = self::findCertificate($certFingerprint, $certificates);
-            $pemKeys = array($pemCert);
+            $pemKeys = [$pemCert];
         } else {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Missing certificate in metadata for '.
                 var_export($srcMetadata->getString('entityid'), true)
             );
         }
 
-        SimpleSAML\Logger::debug('Has '.count($pemKeys).' candidate keys for validation.');
+        \SimpleSAML\Logger::debug('Has '.count($pemKeys).' candidate keys for validation.');
 
         $lastException = null;
         foreach ($pemKeys as $i => $pem) {
-            $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
+            $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'public']);
             $key->loadKey($pem);
 
             try {
                 // make sure that we have a valid signature on either the response or the assertion
                 $res = $element->validate($key);
                 if ($res) {
-                    SimpleSAML\Logger::debug('Validation with key #'.$i.' succeeded.');
+                    \SimpleSAML\Logger::debug('Validation with key #'.$i.' succeeded.');
                     return true;
                 }
-                SimpleSAML\Logger::debug('Validation with key #'.$i.' failed without exception.');
-            } catch (Exception $e) {
-                SimpleSAML\Logger::debug('Validation with key #'.$i.' failed with exception: '.$e->getMessage());
+                \SimpleSAML\Logger::debug('Validation with key #'.$i.' failed without exception.');
+            } catch (\Exception $e) {
+                \SimpleSAML\Logger::debug('Validation with key #'.$i.' failed with exception: '.$e->getMessage());
                 $lastException = $e;
             }
         }
@@ -237,15 +228,15 @@ class sspmod_saml_Message
     /**
      * Check signature on a SAML2 message if enabled.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      * @param \SAML2\Message $message The message we should check the signature on.
      *
-     * @throws \SimpleSAML_Error_Exception if message validation is enabled, but there is no signature in the message.
+     * @throws \SimpleSAML\Error\Exception if message validation is enabled, but there is no signature in the message.
      */
     public static function validateMessage(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata,
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata,
         \SAML2\Message $message
     ) {
         $enabled = null;
@@ -273,7 +264,7 @@ class sspmod_saml_Message
         }
 
         if (!self::checkSign($srcMetadata, $message)) {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Validation of received messages enabled, but no signature found on message.'
             );
         }
@@ -283,30 +274,30 @@ class sspmod_saml_Message
     /**
      * Retrieve the decryption keys from metadata.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender (IdP).
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient (SP).
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender (IdP).
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient (SP).
      *
      * @return array Array of decryption keys.
      */
     public static function getDecryptionKeys(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata
     ) {
         $sharedKey = $srcMetadata->getString('sharedkey', null);
         if ($sharedKey !== null) {
             $key = new XMLSecurityKey(XMLSecurityKey::AES128_CBC);
             $key->loadKey($sharedKey);
-            return array($key);
+            return [$key];
         }
 
-        $keys = array();
+        $keys = [];
 
         // load the new private key if it exists
-        $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, false, 'new_');
+        $keyArray = \SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, false, 'new_');
         if ($keyArray !== null) {
             assert(isset($keyArray['PEM']));
 
-            $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
+            $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, ['type' => 'private']);
             if (array_key_exists('password', $keyArray)) {
                 $key->passphrase = $keyArray['password'];
             }
@@ -315,10 +306,10 @@ class sspmod_saml_Message
         }
 
         // find the existing private key
-        $keyArray = SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true);
+        $keyArray = \SimpleSAML\Utils\Crypto::loadPrivateKey($dstMetadata, true);
         assert(isset($keyArray['PEM']));
 
-        $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private'));
+        $key = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, ['type' => 'private']);
         if (array_key_exists('password', $keyArray)) {
             $key->passphrase = $keyArray['password'];
         }
@@ -334,18 +325,18 @@ class sspmod_saml_Message
      *
      * Remote configuration overrides local configuration.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      *
      * @return array  Array of blacklisted algorithms.
      */
     public static function getBlacklistedAlgorithms(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata
     ) {
         $blacklist = $srcMetadata->getArray('encryption.blacklisted-algorithms', null);
         if ($blacklist === null) {
-            $blacklist = $dstMetadata->getArray('encryption.blacklisted-algorithms', array(XMLSecurityKey::RSA_1_5));
+            $blacklist = $dstMetadata->getArray('encryption.blacklisted-algorithms', [XMLSecurityKey::RSA_1_5]);
         }
         return $blacklist;
     }
@@ -354,19 +345,19 @@ class sspmod_saml_Message
     /**
      * Decrypt an assertion.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender (IdP).
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient (SP).
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender (IdP).
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient (SP).
      * @param \SAML2\Assertion|\SAML2\EncryptedAssertion $assertion The assertion we are decrypting.
      *
      * @return \SAML2\Assertion The assertion.
      *
-     * @throws \SimpleSAML_Error_Exception if encryption is enabled but the assertion is not encrypted, or if we cannot
+     * @throws \SimpleSAML\Error\Exception if encryption is enabled but the assertion is not encrypted, or if we cannot
      * get the decryption keys.
      * @throws \Exception if decryption fails for whatever reason.
      */
     private static function decryptAssertion(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata,
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata,
         $assertion
     ) {
         assert($assertion instanceof \SAML2\Assertion || $assertion instanceof \SAML2\EncryptedAssertion);
@@ -378,7 +369,7 @@ class sspmod_saml_Message
             }
             if ($encryptAssertion) {
                 /* The assertion was unencrypted, but we have encryption enabled. */
-                throw new Exception('Received unencrypted assertion, but encryption was enabled.');
+                throw new \Exception('Received unencrypted assertion, but encryption was enabled.');
             }
 
             return $assertion;
@@ -386,8 +377,8 @@ class sspmod_saml_Message
 
         try {
             $keys = self::getDecryptionKeys($srcMetadata, $dstMetadata);
-        } catch (Exception $e) {
-            throw new SimpleSAML_Error_Exception('Error decrypting assertion: '.$e->getMessage());
+        } catch (\Exception $e) {
+            throw new \SimpleSAML\Error\Exception('Error decrypting assertion: '.$e->getMessage());
         }
 
         $blacklist = self::getBlacklistedAlgorithms($srcMetadata, $dstMetadata);
@@ -396,10 +387,10 @@ class sspmod_saml_Message
         foreach ($keys as $i => $key) {
             try {
                 $ret = $assertion->getAssertion($key, $blacklist);
-                SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
+                \SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
                 return $ret;
-            } catch (Exception $e) {
-                SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
+            } catch (\Exception $e) {
+                \SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
                 $lastException = $e;
             }
         }
@@ -408,29 +399,74 @@ class sspmod_saml_Message
 
 
     /**
-     * Retrieve the status code of a response as a sspmod_saml_Error.
+     * Decrypt any encrypted attributes in an assertion.
+     *
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender (IdP).
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient (SP).
+     * @param \SAML2\Assertion|\SAML2\Assertion $assertion The assertion containing any possibly encrypted attributes.
+     *
+     * @return void
+     *
+     * @throws \SimpleSAML\Error\Exception if we cannot get the decryption keys or decryption fails.
+     */
+    private static function decryptAttributes(
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata,
+        \SAML2\Assertion &$assertion
+    ) {
+        if (!$assertion->hasEncryptedAttributes()) {
+            return;
+        }
+
+        try {
+            $keys = self::getDecryptionKeys($srcMetadata, $dstMetadata);
+        } catch (\Exception $e) {
+            throw new \SimpleSAML\Error\Exception('Error decrypting attributes: '.$e->getMessage());
+        }
+
+        $blacklist = self::getBlacklistedAlgorithms($srcMetadata, $dstMetadata);
+
+        $error = true;
+        foreach ($keys as $i => $key) {
+            try {
+                $assertion->decryptAttributes($key, $blacklist);
+                \SimpleSAML\Logger::debug('Attribute decryption with key #'.$i.' succeeded.');
+                $error = false;
+                break;
+            } catch (\Exception $e) {
+                \SimpleSAML\Logger::debug('Attribute decryption failed with exception: '.$e->getMessage());
+            }
+        }
+        if ($error) {
+            throw new \SimpleSAML\Error\Exception('Could not decrypt the attributes');
+        }
+    }
+
+
+    /**
+     * Retrieve the status code of a response as a \SimpleSAML\Module\saml\Error.
      *
      * @param \SAML2\StatusResponse $response The response.
      *
-     * @return sspmod_saml_Error The error.
+     * @return \SimpleSAML\Module\saml\Error The error.
      */
     public static function getResponseError(\SAML2\StatusResponse $response)
     {
         $status = $response->getStatus();
-        return new sspmod_saml_Error($status['Code'], $status['SubCode'], $status['Message']);
+        return new \SimpleSAML\Module\saml\Error($status['Code'], $status['SubCode'], $status['Message']);
     }
 
 
     /**
      * Build an authentication request based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the service provider.
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the identity provider.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the service provider.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the identity provider.
      * @return \SAML2\AuthnRequest An authentication request object.
      */
     public static function buildAuthnRequest(
-        SimpleSAML_Configuration $spMetadata,
-        SimpleSAML_Configuration $idpMetadata
+        \SimpleSAML\Configuration $spMetadata,
+        \SimpleSAML\Configuration $idpMetadata
     ) {
         $ar = new \SAML2\AuthnRequest();
 
@@ -442,6 +478,7 @@ class sspmod_saml_Message
             $nameIdPolicy = $spMetadata->getValue('NameIDPolicy');
         }
 
+<<<<<<< HEAD
         $policy = \SimpleSAML\Utils\Config\Metadata::parseNameIdPolicy($nameIdPolicy);
         if ($policy !== null) {
             // either we have a policy set, or we used the transient default
@@ -451,12 +488,12 @@ class sspmod_saml_Message
         $ar->setForceAuthn($spMetadata->getBoolean('ForceAuthn', false));
         $ar->setIsPassive($spMetadata->getBoolean('IsPassive', false));
 
-        $protbind = $spMetadata->getValueValidate('ProtocolBinding', array(
+        $protbind = $spMetadata->getValueValidate('ProtocolBinding', [
             \SAML2\Constants::BINDING_HTTP_POST,
             \SAML2\Constants::BINDING_HOK_SSO,
             \SAML2\Constants::BINDING_HTTP_ARTIFACT,
             \SAML2\Constants::BINDING_HTTP_REDIRECT,
-        ), \SAML2\Constants::BINDING_HTTP_POST);
+        ], \SAML2\Constants::BINDING_HTTP_POST);
 
         // Shoaib: setting the appropriate binding based on parameter in sp-metadata defaults to HTTP_POST
         $ar->setProtocolBinding($protbind);
@@ -466,13 +503,13 @@ class sspmod_saml_Message
 
         if ($spMetadata->hasValue('AuthnContextClassRef')) {
             $accr = $spMetadata->getArrayizeString('AuthnContextClassRef');
-            $comp = $spMetadata->getValueValidate('AuthnContextComparison', array(
+            $comp = $spMetadata->getValueValidate('AuthnContextComparison', [
                 \SAML2\Constants::COMPARISON_EXACT,
                 \SAML2\Constants::COMPARISON_MINIMUM,
                 \SAML2\Constants::COMPARISON_MAXIMUM,
                 \SAML2\Constants::COMPARISON_BETTER,
-            ), \SAML2\Constants::COMPARISON_EXACT);
-            $ar->setRequestedAuthnContext(array('AuthnContextClassRef' => $accr, 'Comparison' => $comp));
+            ], \SAML2\Constants::COMPARISON_EXACT);
+            $ar->setRequestedAuthnContext(['AuthnContextClassRef' => $accr, 'Comparison' => $comp]);
         }
 
         self::addRedirectSign($spMetadata, $idpMetadata, $ar);
@@ -484,13 +521,13 @@ class sspmod_saml_Message
     /**
      * Build a logout request based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      * @return \SAML2\LogoutRequest A logout request object.
      */
     public static function buildLogoutRequest(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata
     ) {
         $lr = new \SAML2\LogoutRequest();
         $lr->setIssuer($srcMetadata->getString('entityid'));
@@ -504,13 +541,13 @@ class sspmod_saml_Message
     /**
      * Build a logout response based on information in the metadata.
      *
-     * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender.
-     * @param SimpleSAML_Configuration $dstMetadata The metadata of the recipient.
+     * @param \SimpleSAML\Configuration $srcMetadata The metadata of the sender.
+     * @param \SimpleSAML\Configuration $dstMetadata The metadata of the recipient.
      * @return \SAML2\LogoutResponse A logout response object.
      */
     public static function buildLogoutResponse(
-        SimpleSAML_Configuration $srcMetadata,
-        SimpleSAML_Configuration $dstMetadata
+        \SimpleSAML\Configuration $srcMetadata,
+        \SimpleSAML\Configuration $dstMetadata
     ) {
         $lr = new \SAML2\LogoutResponse();
         $lr->setIssuer($srcMetadata->getString('entityid'));
@@ -524,20 +561,20 @@ class sspmod_saml_Message
     /**
      * Process a response message.
      *
-     * If the response is an error response, we will throw a sspmod_saml_Error exception with the error.
+     * If the response is an error response, we will throw a \SimpleSAML\Module\saml\Error exception with the error.
      *
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the service provider.
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the identity provider.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the service provider.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the identity provider.
      * @param \SAML2\Response $response The response.
      *
      * @return array Array with \SAML2\Assertion objects, containing valid assertions from the response.
      *
-     * @throws \SimpleSAML_Error_Exception if there are no assertions in the response.
+     * @throws \SimpleSAML\Error\Exception if there are no assertions in the response.
      * @throws \Exception if the destination of the response does not match the current URL.
      */
     public static function processResponse(
-        SimpleSAML_Configuration $spMetadata,
-        SimpleSAML_Configuration $idpMetadata,
+        \SimpleSAML\Configuration $spMetadata,
+        \SimpleSAML\Configuration $idpMetadata,
         \SAML2\Response $response
     ) {
         if (!$response->isSuccess()) {
@@ -548,7 +585,7 @@ class sspmod_saml_Message
         $currentURL = \SimpleSAML\Utils\HTTP::getSelfURLNoQuery();
         $msgDestination = $response->getDestination();
         if ($msgDestination !== null && $msgDestination !== $currentURL) {
-            throw new Exception('Destination in response doesn\'t match the current URL. Destination is "'.
+            throw new \Exception('Destination in response doesn\'t match the current URL. Destination is "'.
                 $msgDestination.'", current URL is "'.$currentURL.'".');
         }
 
@@ -560,10 +597,10 @@ class sspmod_saml_Message
          */
         $assertion = $response->getAssertions();
         if (empty($assertion)) {
-            throw new SimpleSAML_Error_Exception('No assertions found in response from IdP.');
+            throw new \SimpleSAML\Error\Exception('No assertions found in response from IdP.');
         }
 
-        $ret = array();
+        $ret = [];
         foreach ($assertion as $a) {
             $ret[] = self::processAssertion($spMetadata, $idpMetadata, $response, $a, $responseSigned);
         }
@@ -575,22 +612,22 @@ class sspmod_saml_Message
     /**
      * Process an assertion in a response.
      *
-     * @param SimpleSAML_Configuration $spMetadata The metadata of the service provider.
-     * @param SimpleSAML_Configuration $idpMetadata The metadata of the identity provider.
+     * @param \SimpleSAML\Configuration $spMetadata The metadata of the service provider.
+     * @param \SimpleSAML\Configuration $idpMetadata The metadata of the identity provider.
      * @param \SAML2\Response $response The response containing the assertion.
      * @param \SAML2\Assertion|\SAML2\EncryptedAssertion $assertion The assertion.
      * @param bool $responseSigned Whether the response is signed.
      *
      * @return \SAML2\Assertion The assertion, if it is valid.
      *
-     * @throws \SimpleSAML_Error_Exception if an error occurs while trying to validate the assertion, or if a assertion
+     * @throws \SimpleSAML\Error\Exception if an error occurs while trying to validate the assertion, or if a assertion
      * is not signed and it should be, or if we are unable to decrypt the NameID due to a local failure (missing or
      * invalid decryption key).
      * @throws \Exception if we couldn't decrypt the NameID for unexpected reasons.
      */
     private static function processAssertion(
-        SimpleSAML_Configuration $spMetadata,
-        SimpleSAML_Configuration $idpMetadata,
+        \SimpleSAML\Configuration $spMetadata,
+        \SimpleSAML\Configuration $idpMetadata,
         \SAML2\Response $response,
         $assertion,
         $responseSigned
@@ -599,10 +636,11 @@ class sspmod_saml_Message
         assert(is_bool($responseSigned));
 
         $assertion = self::decryptAssertion($idpMetadata, $spMetadata, $assertion);
+        self::decryptAttributes($idpMetadata, $spMetadata, $assertion);
 
         if (!self::checkSign($idpMetadata, $assertion)) {
             if (!$responseSigned) {
-                throw new SimpleSAML_Error_Exception('Neither the assertion nor the response was signed.');
+                throw new \SimpleSAML\Error\Exception('Neither the assertion nor the response was signed.');
             }
         } // at least one valid signature found
 
@@ -611,19 +649,19 @@ class sspmod_saml_Message
         // check various properties of the assertion
         $notBefore = $assertion->getNotBefore();
         if ($notBefore !== null && $notBefore > time() + 60) {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Received an assertion that is valid in the future. Check clock synchronization on IdP and SP.'
             );
         }
         $notOnOrAfter = $assertion->getNotOnOrAfter();
         if ($notOnOrAfter !== null && $notOnOrAfter <= time() - 60) {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Received an assertion that has expired. Check clock synchronization on IdP and SP.'
             );
         }
         $sessionNotOnOrAfter = $assertion->getSessionNotOnOrAfter();
         if ($sessionNotOnOrAfter !== null && $sessionNotOnOrAfter <= time() - 60) {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'Received an assertion with a session that has expired. Check clock synchronization on IdP and SP.'
             );
         }
@@ -632,14 +670,14 @@ class sspmod_saml_Message
             $spEntityId = $spMetadata->getString('entityid');
             if (!in_array($spEntityId, $validAudiences, true)) {
                 $candidates = '['.implode('], [', $validAudiences).']';
-                throw new SimpleSAML_Error_Exception('This SP ['.$spEntityId.
+                throw new \SimpleSAML\Error\Exception('This SP ['.$spEntityId.
                     ']  is not a valid audience for the assertion. Candidates were: '.$candidates);
             }
         }
 
         $found = false;
         $lastError = 'No SubjectConfirmation element in Subject.';
-        $validSCMethods = array(\SAML2\Constants::CM_BEARER, \SAML2\Constants::CM_HOK, \SAML2\Constants::CM_VOUCHES);
+        $validSCMethods = [\SAML2\Constants::CM_BEARER, \SAML2\Constants::CM_HOK, \SAML2\Constants::CM_VOUCHES];
         foreach ($assertion->getSubjectConfirmation() as $sc) {
             if (!in_array($sc->Method, $validSCMethods, true)) {
                 $lastError = 'Invalid Method on SubjectConfirmation: '.var_export($sc->Method, true);
@@ -681,9 +719,9 @@ class sspmod_saml_Message
                     continue;
                 }
                 // we have a valid client certificate from the browser
-                $clientCert = str_replace(array("\r", "\n", " "), '', $matches[1]);
+                $clientCert = str_replace(["\r", "\n", " "], '', $matches[1]);
 
-                $keyInfo = array();
+                $keyInfo = [];
                 foreach ($scd->info as $thing) {
                     if ($thing instanceof \SAML2\XML\ds\KeyInfo) {
                         $keyInfo[] = $thing;
@@ -695,7 +733,7 @@ class sspmod_saml_Message
                     continue;
                 }
 
-                $x509data = array();
+                $x509data = [];
                 foreach ($keyInfo[0]->info as $thing) {
                     if ($thing instanceof \SAML2\XML\ds\X509Data) {
                         $x509data[] = $thing;
@@ -707,7 +745,7 @@ class sspmod_saml_Message
                     continue;
                 }
 
-                $x509cert = array();
+                $x509cert = [];
                 foreach ($x509data[0]->data as $thing) {
                     if ($thing instanceof \SAML2\XML\ds\X509Certificate) {
                         $x509cert[] = $thing;
@@ -758,15 +796,15 @@ class sspmod_saml_Message
             break;
         }
         if (!$found) {
-            throw new SimpleSAML_Error_Exception('Error validating SubjectConfirmation in Assertion: '.$lastError);
+            throw new \SimpleSAML\Error\Exception('Error validating SubjectConfirmation in Assertion: '.$lastError);
         } // as far as we can tell, the assertion is valid
 
         // maybe we need to base64 decode the attributes in the assertion?
         if ($idpMetadata->getBoolean('base64attributes', false)) {
             $attributes = $assertion->getAttributes();
-            $newAttributes = array();
+            $newAttributes = [];
             foreach ($attributes as $name => $values) {
-                $newAttributes[$name] = array();
+                $newAttributes[$name] = [];
                 foreach ($values as $value) {
                     foreach (explode('_', $value) as $v) {
                         $newAttributes[$name][] = base64_decode($v);
@@ -780,8 +818,8 @@ class sspmod_saml_Message
         if ($assertion->isNameIdEncrypted()) {
             try {
                 $keys = self::getDecryptionKeys($idpMetadata, $spMetadata);
-            } catch (Exception $e) {
-                throw new SimpleSAML_Error_Exception('Error decrypting NameID: '.$e->getMessage());
+            } catch (\Exception $e) {
+                throw new \SimpleSAML\Error\Exception('Error decrypting NameID: '.$e->getMessage());
             }
 
             $blacklist = self::getBlacklistedAlgorithms($idpMetadata, $spMetadata);
@@ -790,11 +828,11 @@ class sspmod_saml_Message
             foreach ($keys as $i => $key) {
                 try {
                     $assertion->decryptNameId($key, $blacklist);
-                    SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
+                    \SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
                     $lastException = null;
                     break;
-                } catch (Exception $e) {
-                    SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
+                } catch (\Exception $e) {
+                    \SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
                     $lastException = $e;
                 }
             }
@@ -810,13 +848,13 @@ class sspmod_saml_Message
     /**
      * Retrieve the encryption key for the given entity.
      *
-     * @param SimpleSAML_Configuration $metadata The metadata of the entity.
+     * @param \SimpleSAML\Configuration $metadata The metadata of the entity.
      *
      * @return \RobRichards\XMLSecLibs\XMLSecurityKey  The encryption key.
      *
-     * @throws \SimpleSAML_Error_Exception if there is no supported encryption key in the metadata of this entity.
+     * @throws \SimpleSAML\Error\Exception if there is no supported encryption key in the metadata of this entity.
      */
-    public static function getEncryptionKey(SimpleSAML_Configuration $metadata)
+    public static function getEncryptionKey(\SimpleSAML\Configuration $metadata)
     {
 
         $sharedKey = $metadata->getString('sharedkey', null);
@@ -833,13 +871,13 @@ class sspmod_saml_Message
                     $pemKey = "-----BEGIN CERTIFICATE-----\n".
                         chunk_split($key['X509Certificate'], 64).
                         "-----END CERTIFICATE-----\n";
-                    $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public'));
+                    $key = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, ['type' => 'public']);
                     $key->loadKey($pemKey);
                     return $key;
             }
         }
 
-        throw new SimpleSAML_Error_Exception('No supported encryption key in '.
+        throw new \SimpleSAML\Error\Exception('No supported encryption key in '.
             var_export($metadata->getString('entityid'), true));
     }
 }
diff --git a/modules/saml/lib/SP/LogoutStore.php b/modules/saml/lib/SP/LogoutStore.php
index a92aeadf3ee190b96a2291165f0d9e541853db85..8ea35423a5c3e81bd937f1d7bcd9cff1857f547d 100644
--- a/modules/saml/lib/SP/LogoutStore.php
+++ b/modules/saml/lib/SP/LogoutStore.php
@@ -1,303 +1,333 @@
 <?php
 
+namespace SimpleSAML\Module\saml\SP;
+
 /**
  * A directory over logout information.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_saml_SP_LogoutStore
+
+class LogoutStore
 {
-	/**
-	 * Create logout table in SQL, if it is missing.
-	 *
-	 * @param \SimpleSAML\Store\SQL $store  The datastore.
-	 */
-	private static function createLogoutTable(\SimpleSAML\Store\SQL $store)
+    /**
+     * Create logout table in SQL, if it is missing.
+     *
+     * @param \SimpleSAML\Store\SQL $store  The datastore.
+     */
+    private static function createLogoutTable(\SimpleSAML\Store\SQL $store)
     {
-		$tableVer = $store->getTableVersion('saml_LogoutStore');
-		if ($tableVer === 2) {
-			return;
-		} elseif ($tableVer === 1) {
-			/* TableVersion 2 increased the column size to 255 which is the maximum length of a FQDN. */
-			$query = 'ALTER TABLE ' . $store->prefix . '_saml_LogoutStore MODIFY _authSource VARCHAR(255) NOT NULL';
-			try {
-				$store->pdo->exec($query);
-			} catch (Exception $e) {
-				SimpleSAML\Logger::warning($store->pdo->errorInfo());
-				return;
-			}
-			$store->setTableVersion('saml_LogoutStore', 2);
-			return;
-		}
-
-		$query = 'CREATE TABLE ' . $store->prefix . '_saml_LogoutStore (
-			_authSource VARCHAR(255) NOT NULL,
-			_nameId VARCHAR(40) NOT NULL,
-			_sessionIndex VARCHAR(50) NOT NULL,
-			_expire TIMESTAMP NOT NULL,
-			_sessionId VARCHAR(50) NOT NULL,
-			UNIQUE (_authSource, _nameID, _sessionIndex)
-		)';
-		$store->pdo->exec($query);
-
-		$query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_expire ON '  . $store->prefix . '_saml_LogoutStore (_expire)';
-		$store->pdo->exec($query);
-
-		$query = 'CREATE INDEX ' . $store->prefix . '_saml_LogoutStore_nameId ON '  . $store->prefix . '_saml_LogoutStore (_authSource, _nameId)';
-		$store->pdo->exec($query);
-
-		$store->setTableVersion('saml_LogoutStore', 2);
-	}
-
-
-	/**
-	 * Clean the logout table of expired entries.
-	 *
-	 * @param \SimpleSAML\Store\SQL $store  The datastore.
-	 */
-	private static function cleanLogoutStore(\SimpleSAML\Store\SQL $store)
+        $tableVer = $store->getTableVersion('saml_LogoutStore');
+        if ($tableVer === 2) {
+            return;
+        } elseif ($tableVer === 1) {
+            // TableVersion 2 increased the column size to 255 which is the maximum length of a FQDN
+            switch ($store->driver) {
+                case 'pgsql':
+                    // This does not affect the NOT NULL constraint
+                    $query = 'ALTER TABLE '.$store->prefix.
+                        '_saml_LogoutStore ALTER COLUMN _authSource TYPE VARCHAR(255)';
+                    break;
+                default:
+                    $query = 'ALTER TABLE '.$store->prefix.
+                        '_saml_LogoutStore MODIFY _authSource VARCHAR(255) NOT NULL';
+                    break;
+            }
+
+            try {
+                $store->pdo->exec($query);
+            } catch (\Exception $e) {
+                \SimpleSAML\Logger::warning($store->pdo->errorInfo());
+                return;
+            }
+            $store->setTableVersion('saml_LogoutStore', 2);
+            return;
+        }
+
+        $query = 'CREATE TABLE '.$store->prefix.'_saml_LogoutStore (
+            _authSource VARCHAR(255) NOT NULL,
+            _nameId VARCHAR(40) NOT NULL,
+            _sessionIndex VARCHAR(50) NOT NULL,
+            _expire TIMESTAMP NOT NULL,
+            _sessionId VARCHAR(50) NOT NULL,
+            UNIQUE (_authSource, _nameID, _sessionIndex)
+        )';
+        $store->pdo->exec($query);
+
+        $query = 'CREATE INDEX '.$store->prefix.'_saml_LogoutStore_expire ON ';
+        $query .= $store->prefix.'_saml_LogoutStore (_expire)';
+        $store->pdo->exec($query);
+
+        $query = 'CREATE INDEX '.$store->prefix.'_saml_LogoutStore_nameId ON ';
+        $query .= $store->prefix.'_saml_LogoutStore (_authSource, _nameId)';
+        $store->pdo->exec($query);
+
+        $store->setTableVersion('saml_LogoutStore', 2);
+    }
+
+
+    /**
+     * Clean the logout table of expired entries.
+     *
+     * @param \SimpleSAML\Store\SQL $store  The datastore.
+     */
+    private static function cleanLogoutStore(\SimpleSAML\Store\SQL $store)
     {
-		SimpleSAML\Logger::debug('saml.LogoutStore: Cleaning logout store.');
-
-		$query = 'DELETE FROM ' . $store->prefix . '_saml_LogoutStore WHERE _expire < :now';
-		$params = array('now' => gmdate('Y-m-d H:i:s'));
-
-		$query = $store->pdo->prepare($query);
-		$query->execute($params);
-	}
-
-
-	/**
-	 * Register a session in the SQL datastore.
-	 *
-	 * @param \SimpleSAML\Store\SQL $store  The datastore.
-	 * @param string $authId  The authsource ID.
-	 * @param string $nameId  The hash of the users NameID.
-	 * @param string $sessionIndex  The SessionIndex of the user.
-	 */
-	private static function addSessionSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId, $sessionIndex, $expire, $sessionId)
-    {
-		assert(is_string($authId));
-		assert(is_string($nameId));
-		assert(is_string($sessionIndex));
-		assert(is_string($sessionId));
-		assert(is_int($expire));
-
-		self::createLogoutTable($store);
-
-		if (rand(0, 1000) < 10) {
-			self::cleanLogoutStore($store);
-		}
-
-		$data = array(
-			'_authSource' => $authId,
-			'_nameId' => $nameId,
-			'_sessionIndex' => $sessionIndex,
-			'_expire' => gmdate('Y-m-d H:i:s', $expire),
-			'_sessionId' => $sessionId,
-		);
-		$store->insertOrUpdate($store->prefix . '_saml_LogoutStore', array('_authSource', '_nameId', '_sessionIndex'), $data);
-	}
-
-
-	/**
-	 * Retrieve sessions from the SQL datastore.
-	 *
-	 * @param \SimpleSAML\Store\SQL $store  The datastore.
-	 * @param string $authId  The authsource ID.
-	 * @param string $nameId  The hash of the users NameID.
-	 * @return array  Associative array of SessionIndex =>  SessionId.
-	 */
-	private static function getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId)
+        \SimpleSAML\Logger::debug('saml.LogoutStore: Cleaning logout store.');
+
+        $query = 'DELETE FROM '.$store->prefix.'_saml_LogoutStore WHERE _expire < :now';
+        $params = ['now' => gmdate('Y-m-d H:i:s')];
+
+        $query = $store->pdo->prepare($query);
+        $query->execute($params);
+    }
+
+
+    /**
+     * Register a session in the SQL datastore.
+     *
+     * @param \SimpleSAML\Store\SQL $store  The datastore.
+     * @param string $authId  The authsource ID.
+     * @param string $nameId  The hash of the users NameID.
+     * @param string $sessionIndex  The SessionIndex of the user.
+     */
+    private static function addSessionSQL(
+        \SimpleSAML\Store\SQL $store,
+        $authId,
+        $nameId,
+        $sessionIndex,
+        $expire,
+        $sessionId
+    ) {
+        assert(is_string($authId));
+        assert(is_string($nameId));
+        assert(is_string($sessionIndex));
+        assert(is_string($sessionId));
+        assert(is_int($expire));
+
+        self::createLogoutTable($store);
+
+        if (rand(0, 1000) < 10) {
+            self::cleanLogoutStore($store);
+        }
+
+        $data = [
+            '_authSource' => $authId,
+            '_nameId' => $nameId,
+            '_sessionIndex' => $sessionIndex,
+            '_expire' => gmdate('Y-m-d H:i:s', $expire),
+            '_sessionId' => $sessionId,
+        ];
+        $store->insertOrUpdate(
+            $store->prefix.'_saml_LogoutStore',
+            ['_authSource', '_nameId', '_sessionIndex'],
+            $data
+        );
+    }
+
+
+    /**
+     * Retrieve sessions from the SQL datastore.
+     *
+     * @param \SimpleSAML\Store\SQL $store  The datastore.
+     * @param string $authId  The authsource ID.
+     * @param string $nameId  The hash of the users NameID.
+     * @return array  Associative array of SessionIndex =>  SessionId.
+     */
+    private static function getSessionsSQL(\SimpleSAML\Store\SQL $store, $authId, $nameId)
     {
-		assert(is_string($authId));
-		assert(is_string($nameId));
-
-		self::createLogoutTable($store);
-
-		$params = array(
-			'_authSource' => $authId,
-			'_nameId' => $nameId,
-			'now' => gmdate('Y-m-d H:i:s'),
-		);
-
-		// We request the columns in lowercase in order to be compatible with PostgreSQL
-		$query = 'SELECT _sessionIndex AS _sessionindex, _sessionId AS _sessionid FROM ' . $store->prefix . '_saml_LogoutStore' .
-			' WHERE _authSource = :_authSource AND _nameId = :_nameId AND _expire >= :now';
-		$query = $store->pdo->prepare($query);
-		$query->execute($params);
-
-		$res = array();
-		while ( ($row = $query->fetch(PDO::FETCH_ASSOC)) !== false) {
-			$res[$row['_sessionindex']] = $row['_sessionid'];
-		}
-
-		return $res;
-	}
-
-
-	/**
-	 * Retrieve all session IDs from a key-value store.
-	 *
-	 * @param \SimpleSAML\Store $store  The datastore.
-	 * @param string $authId  The authsource ID.
-	 * @param string $nameId  The hash of the users NameID.
-	 * @param array $sessionIndexes  The session indexes.
-	 * @return array  Associative array of SessionIndex =>  SessionId.
-	 */
-	private static function getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes)
+        assert(is_string($authId));
+        assert(is_string($nameId));
+
+        self::createLogoutTable($store);
+
+        $params = [
+            '_authSource' => $authId,
+            '_nameId' => $nameId,
+            'now' => gmdate('Y-m-d H:i:s'),
+        ];
+
+        // We request the columns in lowercase in order to be compatible with PostgreSQL
+        $query = 'SELECT _sessionIndex AS _sessionindex, _sessionId AS _sessionid FROM '.$store->prefix;
+        $query .= '_saml_LogoutStore'.' WHERE _authSource = :_authSource AND _nameId = :_nameId AND _expire >= :now';
+        $query = $store->pdo->prepare($query);
+        $query->execute($params);
+
+        $res = [];
+        while (($row = $query->fetch(\PDO::FETCH_ASSOC)) !== false) {
+            $res[$row['_sessionindex']] = $row['_sessionid'];
+        }
+
+        return $res;
+    }
+
+
+    /**
+     * Retrieve all session IDs from a key-value store.
+     *
+     * @param \SimpleSAML\Store $store  The datastore.
+     * @param string $authId  The authsource ID.
+     * @param string $nameId  The hash of the users NameID.
+     * @param array $sessionIndexes  The session indexes.
+     * @return array  Associative array of SessionIndex =>  SessionId.
+     */
+    private static function getSessionsStore(\SimpleSAML\Store $store, $authId, $nameId, array $sessionIndexes)
     {
-		assert(is_string($authId));
-		assert(is_string($nameId));
-
-		$res = array();
-		foreach ($sessionIndexes as $sessionIndex) {
-			$sessionId = $store->get('saml.LogoutStore', $nameId . ':' . $sessionIndex);
-			if ($sessionId === null) {
-				continue;
-			}
-			assert(is_string($sessionId));
-			$res[$sessionIndex] = $sessionId;
-		}
-
-		return $res;
-	}
-
-
-	/**
-	 * Register a new session in the datastore.
-	 *
-	 * Please observe the change of the signature in this method. Previously, the second parameter ($nameId) was forced
-	 * to be an array. However, it has no type restriction now, and the documentation states it must be a
-	 * \SAML2\XML\saml\NameID object. Currently, this function still accepts an array passed as $nameId, and will
-	 * silently convert it to a \SAML2\XML\saml\NameID object. This is done to keep backwards-compatibility, though will
-	 * no longer be possible in the future as the $nameId parameter will be required to be an object.
-	 *
-	 * @param string $authId  The authsource ID.
-	 * @param \SAML2\XML\saml\NameID $nameId The NameID of the user.
-	 * @param string|NULL $sessionIndex  The SessionIndex of the user.
-	 */
-	public static function addSession($authId, $nameId, $sessionIndex, $expire)
+        assert(is_string($authId));
+        assert(is_string($nameId));
+
+        $res = [];
+        foreach ($sessionIndexes as $sessionIndex) {
+            $sessionId = $store->get('saml.LogoutStore', $nameId.':'.$sessionIndex);
+            if ($sessionId === null) {
+                continue;
+            }
+            assert(is_string($sessionId));
+            $res[$sessionIndex] = $sessionId;
+        }
+
+        return $res;
+    }
+
+
+    /**
+     * Register a new session in the datastore.
+     *
+     * Please observe the change of the signature in this method. Previously, the second parameter ($nameId) was forced
+     * to be an array. However, it has no type restriction now, and the documentation states it must be a
+     * \SAML2\XML\saml\NameID object. Currently, this function still accepts an array passed as $nameId, and will
+     * silently convert it to a \SAML2\XML\saml\NameID object. This is done to keep backwards-compatibility, though will
+     * no longer be possible in the future as the $nameId parameter will be required to be an object.
+     *
+     * @param string $authId  The authsource ID.
+     * @param \SAML2\XML\saml\NameID $nameId The NameID of the user.
+     * @param string|null $sessionIndex  The SessionIndex of the user.
+     */
+    public static function addSession($authId, $nameId, $sessionIndex, $expire)
     {
-		assert(is_string($authId));
-		assert(is_string($sessionIndex) || $sessionIndex === null);
-		assert(is_int($expire));
-
-		if ($sessionIndex === null) {
-			/* This IdP apparently did not include a SessionIndex, and thus probably does not
-			 * support SLO. We still want to add the session to the data store just in case
-			 * it supports SLO, but we don't want an LogoutRequest with a specific
-			 * SessionIndex to match this session. We therefore generate our own session index.
-			 */
-			$sessionIndex = SimpleSAML\Utils\Random::generateID();
-		}
-
-		$store = \SimpleSAML\Store::getInstance();
-		if ($store === false) {
-			// We don't have a datastore.
-			return;
-		}
-
-		// serialize and anonymize the NameID
+        assert(is_string($authId));
+        assert(is_string($sessionIndex) || $sessionIndex === null);
+        assert(is_int($expire));
+
+        if ($sessionIndex === null) {
+            /* This IdP apparently did not include a SessionIndex, and thus probably does not
+             * support SLO. We still want to add the session to the data store just in case
+             * it supports SLO, but we don't want an LogoutRequest with a specific
+             * SessionIndex to match this session. We therefore generate our own session index.
+             */
+            $sessionIndex = \SimpleSAML\Utils\Random::generateID();
+        }
+
+        $store = \SimpleSAML\Store::getInstance();
+        if ($store === false) {
+            // We don't have a datastore.
+            return;
+        }
+
+        // serialize and anonymize the NameID
         // TODO: remove this conditional statement
-		if (is_array($nameId)) {
-			$nameId = \SAML2\XML\saml\NameID::fromArray($nameId);
-		}
-		$strNameId = serialize($nameId);
-		$strNameId = sha1($strNameId);
-
-		/* Normalize SessionIndex. */
-		if (strlen($sessionIndex) > 50) {
-			$sessionIndex = sha1($sessionIndex);
-		}
-
-		$session = SimpleSAML_Session::getSessionFromRequest();
-		$sessionId = $session->getSessionId();
-
-		if ($store instanceof \SimpleSAML\Store\SQL) {
-			self::addSessionSQL($store, $authId, $strNameId, $sessionIndex, $expire, $sessionId);
-		} else {
-			$store->set('saml.LogoutStore', $strNameId . ':' . $sessionIndex, $sessionId, $expire);
-		}
-	}
-
-
-	/**
-	 * Log out of the given sessions.
-	 *
-	 * @param string $authId  The authsource ID.
-	 * @param \SAML2\XML\saml\NameID $nameId The NameID of the user.
-	 * @param array $sessionIndexes  The SessionIndexes we should log out of. Logs out of all if this is empty.
-	 * @returns int|FALSE  Number of sessions logged out, or FALSE if not supported.
-	 */
-	public static function logoutSessions($authId, $nameId, array $sessionIndexes)
+        if (is_array($nameId)) {
+            $nameId = \SAML2\XML\saml\NameID::fromArray($nameId);
+        }
+        $strNameId = serialize($nameId);
+        $strNameId = sha1($strNameId);
+
+        // Normalize SessionIndex
+        if (strlen($sessionIndex) > 50) {
+            $sessionIndex = sha1($sessionIndex);
+        }
+
+        $session = \SimpleSAML\Session::getSessionFromRequest();
+        $sessionId = $session->getSessionId();
+
+        if ($store instanceof \SimpleSAML\Store\SQL) {
+            self::addSessionSQL($store, $authId, $strNameId, $sessionIndex, $expire, $sessionId);
+        } else {
+            $store->set('saml.LogoutStore', $strNameId.':'.$sessionIndex, $sessionId, $expire);
+        }
+    }
+
+
+    /**
+     * Log out of the given sessions.
+     *
+     * @param string $authId  The authsource ID.
+     * @param \SAML2\XML\saml\NameID $nameId The NameID of the user.
+     * @param array $sessionIndexes  The SessionIndexes we should log out of. Logs out of all if this is empty.
+     * @returns int|false  Number of sessions logged out, or FALSE if not supported.
+     */
+    public static function logoutSessions($authId, $nameId, array $sessionIndexes)
     {
-		assert(is_string($authId));
-
-		$store = \SimpleSAML\Store::getInstance();
-		if ($store === false) {
-			/* We don't have a datastore. */
-			return false;
-		}
-
-		// serialize and anonymize the NameID
-		// TODO: remove this conditional statement
-		if (is_array($nameId)) {
-			$nameId = \SAML2\XML\saml\NameID::fromArray($nameId);
-		}
-		$strNameId = serialize($nameId);
-		$strNameId = sha1($strNameId);
-
-		/* Normalize SessionIndexes. */
-		foreach ($sessionIndexes as &$sessionIndex) {
-			assert(is_string($sessionIndex));
-			if (strlen($sessionIndex) > 50) {
-				$sessionIndex = sha1($sessionIndex);
-			}
-		}
-		unset($sessionIndex); // Remove reference
-
-		if ($store instanceof \SimpleSAML\Store\SQL) {
-			$sessions = self::getSessionsSQL($store, $authId, $strNameId);
-		} elseif (empty($sessionIndexes)) {
-			/* We cannot fetch all sessions without a SQL store. */
-			return false;
-		} else {
-			/** @var \SimpleSAML\Store $sessions At this point the store cannot be false */
-			$sessions = self::getSessionsStore($store, $authId, $strNameId, $sessionIndexes);
-
-		}
-
-		if (empty($sessionIndexes)) {
-			$sessionIndexes = array_keys($sessions);
-		}
-
-		$numLoggedOut = 0;
-		foreach ($sessionIndexes as $sessionIndex) {
-			if (!isset($sessions[$sessionIndex])) {
-				SimpleSAML\Logger::info('saml.LogoutStore: Logout requested for unknown SessionIndex.');
-				continue;
-			}
-
-			$sessionId = $sessions[$sessionIndex];
-
-			$session = SimpleSAML_Session::getSession($sessionId);
-			if ($session === null) {
-				SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of missing session.');
-				continue;
-			}
-
-			if (!$session->isValid($authId)) {
-				SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of session because it isn\'t authenticated.');
-				continue;
-			}
-
-			SimpleSAML\Logger::info('saml.LogoutStore: Logging out of session with trackId [' . $session->getTrackID() . '].');
-			$session->doLogout($authId);
-			$numLoggedOut += 1;
-		}
-
-		return $numLoggedOut;
-	}
+        assert(is_string($authId));
 
+        $store = \SimpleSAML\Store::getInstance();
+        if ($store === false) {
+            // We don't have a datastore
+            return false;
+        }
+
+        // serialize and anonymize the NameID
+        // TODO: remove this conditional statement
+        if (is_array($nameId)) {
+            $nameId = \SAML2\XML\saml\NameID::fromArray($nameId);
+        }
+        $strNameId = serialize($nameId);
+        $strNameId = sha1($strNameId);
+
+        // Normalize SessionIndexes
+        foreach ($sessionIndexes as &$sessionIndex) {
+            assert(is_string($sessionIndex));
+            if (strlen($sessionIndex) > 50) {
+                $sessionIndex = sha1($sessionIndex);
+            }
+        }
+
+        // Remove reference
+        unset($sessionIndex);
+
+        if ($store instanceof \SimpleSAML\Store\SQL) {
+            $sessions = self::getSessionsSQL($store, $authId, $strNameId);
+        } elseif (empty($sessionIndexes)) {
+            // We cannot fetch all sessions without a SQL store
+            return false;
+        } else {
+            /** @var \SimpleSAML\Store $sessions At this point the store cannot be false */
+            $sessions = self::getSessionsStore($store, $authId, $strNameId, $sessionIndexes);
+        }
+
+        if (empty($sessionIndexes)) {
+            $sessionIndexes = array_keys($sessions);
+        }
+
+        $numLoggedOut = 0;
+        foreach ($sessionIndexes as $sessionIndex) {
+            if (!isset($sessions[$sessionIndex])) {
+                \SimpleSAML\Logger::info('saml.LogoutStore: Logout requested for unknown SessionIndex.');
+                continue;
+            }
+
+            $sessionId = $sessions[$sessionIndex];
+
+            $session = \SimpleSAML\Session::getSession($sessionId);
+            if ($session === null) {
+                \SimpleSAML\Logger::info('saml.LogoutStore: Skipping logout of missing session.');
+                continue;
+            }
+
+            if (!$session->isValid($authId)) {
+                \SimpleSAML\Logger::info(
+                    'saml.LogoutStore: Skipping logout of session because it isn\'t authenticated.'
+                );
+                continue;
+            }
+
+            \SimpleSAML\Logger::info(
+                'saml.LogoutStore: Logging out of session with trackId ['.$session->getTrackID().'].'
+            );
+            $session->doLogout($authId);
+            $numLoggedOut += 1;
+        }
+
+        return $numLoggedOut;
+    }
 }
diff --git a/modules/saml/templates/proxy/invalid_session.php b/modules/saml/templates/proxy/invalid_session.php
index 1131379988f3a9954594674d5d57a72d9fb52ef6..ede358580d665a0a8c88c8b340931d97d458debd 100644
--- a/modules/saml/templates/proxy/invalid_session.php
+++ b/modules/saml/templates/proxy/invalid_session.php
@@ -2,7 +2,7 @@
 /**
  * Template to ask a user whether to logout because of a reauthentication or not.
  *
- * @var SimpleSAML_XHTML_Template $this
+ * @var \SimpleSAML\XHTML\Template $this
  *
  * @author Jaime PĂ©rez Crespo, UNINETT AS <jaime.perez@uninett.no>
  *
@@ -16,10 +16,10 @@ $this->includeAtTemplateBase('includes/header.php');
 
 $translator = $this->getTranslator();
 
-$params = array(
+$params = [
     '%IDP%' => $this->data['idp_name'],
     '%SP%' => $this->data['sp_name'],
-);
+];
 ?>
     <h2><?php echo $translator->t('{saml:proxy:invalid_idp}'); ?></h2>
     <p><?php echo $translator->t('{saml:proxy:invalid_idp_description}', $params); ?></p>
diff --git a/modules/saml/templates/proxy/invalid_session.twig b/modules/saml/templates/proxy/invalid_session.twig
new file mode 100644
index 0000000000000000000000000000000000000000..c970efabfa76c4b24389b0c8d4fdf90b987fc9f4
--- /dev/null
+++ b/modules/saml/templates/proxy/invalid_session.twig
@@ -0,0 +1,12 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ '{saml:proxy:invalid_idp}'|trans }}</h2>
+    <p>{{ '{saml:proxy:invalid_idp_description}'|trans({"%IDP%": idp_name, "%SP%": sp_name}, "app")|raw</p>
+    <form method="post" action="?">
+        <input type="hidden" name="AuthState" value="{{ AuthState|escape('html') }}" />
+        <input type="submit" name="continue" value="{{ '{general:yes_continue}'|trans }}" />
+        <input type="submit" name="cancel" value="{{ '{general:no_cancel}'|trans }}" />
+    </form>
+{% endblock %}
diff --git a/modules/saml/templates/sp/wrong_authncontextclassref.twig b/modules/saml/templates/sp/wrong_authncontextclassref.twig
new file mode 100644
index 0000000000000000000000000000000000000000..5a5012c87407efe0f5f5259756c596f795d75472
--- /dev/null
+++ b/modules/saml/templates/sp/wrong_authncontextclassref.twig
@@ -0,0 +1,7 @@
+{% set pagetitle = 'SimpleSAMLphp'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ '{saml:wrong_authncontextclassref:header}'|trans|escape('html') }}</h2>
+    <p>{{ '{saml:wrong_authncontextclassref:description}'|trans|escape('html') }}</p>
+{% endblock %}
diff --git a/modules/saml/www/disco.php b/modules/saml/www/disco.php
index 1f3bac0857692bcd0760b3bb0bf3ac89ce519fe5..b7d06c454550a1dab8eab8edb181c4a6a750e379 100644
--- a/modules/saml/www/disco.php
+++ b/modules/saml/www/disco.php
@@ -4,5 +4,5 @@
  * Built-in IdP discovery service.
  */
 
-$discoHandler = new SimpleSAML_XHTML_IdPDisco(array('saml20-idp-remote', 'shib13-idp-remote'), 'saml');
+$discoHandler = new \SimpleSAML\XHTML\IdPDisco(['saml20-idp-remote', 'shib13-idp-remote'], 'saml');
 $discoHandler->handleRequest();
diff --git a/modules/saml/www/idp/certs.php b/modules/saml/www/idp/certs.php
index a289d96a2cb473ddb5e8d6e3bd40469db50f5d19..7a2597519abfc06c5aaf63e31dd4718b98bfca5b 100644
--- a/modules/saml/www/idp/certs.php
+++ b/modules/saml/www/idp/certs.php
@@ -1,32 +1,33 @@
 <?php
 
 // Load SimpleSAMLphp, configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$config = \SimpleSAML\Configuration::getInstance();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
-if (!$config->getBoolean('enable.saml20-idp', false))
-	throw new SimpleSAML_Error_Error('NOACCESS');
+if (!$config->getBoolean('enable.saml20-idp', false)) {
+    throw new \SimpleSAML\Error\Error('NOACCESS');
+}
 
 // Check if valid local session exists..
 if ($config->getBoolean('admin.protectmetadata', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
 
 $idpentityid = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
 $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted');
 
-switch($_SERVER['PATH_INFO']) {
-	case '/new_idp.crt':
-		$certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, FALSE, 'new_');
-		break;
-	case '/idp.crt':
-		$certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, TRUE);
-		break;
-	case '/https.crt':
-		$certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, TRUE, 'https.');
-		break;
-	default:
-		throw new SimpleSAML_Error_NotFound('Unknown certificate.');
+switch ($_SERVER['PATH_INFO']) {
+    case '/new_idp.crt':
+        $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
+        break;
+    case '/idp.crt':
+        $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
+        break;
+    case '/https.crt':
+        $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true, 'https.');
+        break;
+    default:
+        throw new \SimpleSAML\Error\NotFound('Unknown certificate.');
 }
 
 header('Content-Disposition: attachment; filename='.substr($_SERVER['PATH_INFO'], 1));
diff --git a/modules/saml/www/proxy/invalid_session.php b/modules/saml/www/proxy/invalid_session.php
index f110f8beb6d60572e16fcbe8848cda5976f836f0..1afc151ae11fbc928a374f9d8e5062be007077bf 100644
--- a/modules/saml/www/proxy/invalid_session.php
+++ b/modules/saml/www/proxy/invalid_session.php
@@ -11,24 +11,24 @@
 
 // retrieve the authentication state
 if (!array_key_exists('AuthState', $_REQUEST)) {
-    throw new SimpleSAML_Error_BadRequest('Missing mandatory parameter: AuthState');
+    throw new \SimpleSAML\Error\BadRequest('Missing mandatory parameter: AuthState');
 }
 
 try {
     // try to get the state
-    $state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], 'saml:proxy:invalid_idp');
-} catch (Exception $e) {
+    $state = \SimpleSAML\Auth\State::loadState($_REQUEST['AuthState'], 'saml:proxy:invalid_idp');
+} catch (\Exception $e) {
     // the user probably hit the back button after starting the logout, try to recover the state with another stage
-    $state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthState'], 'core:Logout:afterbridge');
+    $state = \SimpleSAML\Auth\State::loadState($_REQUEST['AuthState'], 'core:Logout:afterbridge');
 
     // success! Try to continue with reauthentication, since we no longer have a valid session here
-    $idp = SimpleSAML_IdP::getById($state['core:IdP']);
-    sspmod_saml_Auth_Source_SP::reauthPostLogout($idp, $state);
+    $idp = \SimpleSAML\IdP::getById($state['core:IdP']);
+    \SimpleSAML\Module\saml\Auth\Source\SP::reauthPostLogout($idp, $state);
 }
 
 if (isset($_POST['cancel'])) {
     // the user does not want to logout, cancel login
-    SimpleSAML_Auth_State::throwException(
+    \SimpleSAML\Auth\State::throwException(
         $state,
         new \SimpleSAML\Module\saml\Error\NoAvailableIDP(
             \SAML2\Constants::STATUS_RESPONDER,
@@ -39,19 +39,19 @@ if (isset($_POST['cancel'])) {
 
 if (isset($_POST['continue'])) {
     // log the user out before being able to login again
-    $as = SimpleSAML_Auth_Source::getById($state['saml:sp:AuthId'], 'sspmod_saml_Auth_Source_SP');
-    /** @var sspmod_saml_Auth_Source_SP $as */
+    $as = \SimpleSAML\Auth\Source::getById($state['saml:sp:AuthId'], '\SimpleSAML\Module\saml\Auth\Source\SP');
+    /** @var \SimpleSAML\Module\saml\Auth\Source\SP $as */
     $as->reauthLogout($state);
 }
 
-$cfg = SimpleSAML_Configuration::getInstance();
-$template = new SimpleSAML_XHTML_Template($cfg, 'saml:proxy/invalid_session.php');
+$cfg = \SimpleSAML\Configuration::getInstance();
+$template = new \SimpleSAML\XHTML\Template($cfg, 'saml:proxy/invalid_session.php');
 $translator = $template->getTranslator();
-$template->data['AuthState'] = (string)$_REQUEST['AuthState'];
+$template->data['AuthState'] = (string) $_REQUEST['AuthState'];
 
 // get the name of the IdP
 $idpmdcfg = $state['saml:sp:IdPMetadata'];
-/** @var SimpleSAML_Configuration $idpmdcfg */
+/** @var \SimpleSAML\Configuration $idpmdcfg */
 $idpmd = $idpmdcfg->toArray();
 if (array_key_exists('name', $idpmd)) {
     $template->data['idp_name'] = $translator->getPreferredTranslation($idpmd['name']);
diff --git a/modules/saml/www/sp/discoresp.php b/modules/saml/www/sp/discoresp.php
index db9bda9d5b92fc42f40831fda84c07459b0c1f47..94ac7c1d77aad0da838d2b0e61142e4cee7063dd 100644
--- a/modules/saml/www/sp/discoresp.php
+++ b/modules/saml/www/sp/discoresp.php
@@ -5,24 +5,24 @@
  */
 
 if (!array_key_exists('AuthID', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing AuthID to discovery service response handler');
+    throw new \SimpleSAML\Error\BadRequest('Missing AuthID to discovery service response handler');
 }
 
 if (!array_key_exists('idpentityid', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing idpentityid to discovery service response handler');
+    throw new \SimpleSAML\Error\BadRequest('Missing idpentityid to discovery service response handler');
 }
-$state = SimpleSAML_Auth_State::loadState($_REQUEST['AuthID'], 'saml:sp:sso');
+$state = \SimpleSAML\Auth\State::loadState($_REQUEST['AuthID'], 'saml:sp:sso');
 
 // Find authentication source
 assert(array_key_exists('saml:sp:AuthId', $state));
 $sourceId = $state['saml:sp:AuthId'];
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new Exception('Could not find authentication source with id '.$sourceId);
 }
-if (!($source instanceof sspmod_saml_Auth_Source_SP)) {
-	throw new SimpleSAML_Error_Exception('Source type changed?');
+if (!($source instanceof \SimpleSAML\Module\saml\Auth\Source\SP)) {
+    throw new \SimpleSAML\Error\Exception('Source type changed?');
 }
 
 $source->startSSO($_REQUEST['idpentityid'], $state);
diff --git a/modules/saml/www/sp/metadata.php b/modules/saml/www/sp/metadata.php
index c2f7a3b92b4ef7e90643f2ca254790165c642035..89a580d36f207daf0f5bf2d13da3e6478fefa2a2 100644
--- a/modules/saml/www/sp/metadata.php
+++ b/modules/saml/www/sp/metadata.php
@@ -1,55 +1,57 @@
 <?php
 
 if (!array_key_exists('PATH_INFO', $_SERVER)) {
-    throw new SimpleSAML_Error_BadRequest('Missing authentication source id in metadata URL');
+    throw new \SimpleSAML\Error\BadRequest('Missing authentication source id in metadata URL');
 }
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 if ($config->getBoolean('admin.protectmetadata', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
 $sourceId = substr($_SERVER['PATH_INFO'], 1);
-$source = SimpleSAML_Auth_Source::getById($sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
 if ($source === null) {
-    throw new SimpleSAML_Error_AuthSource($sourceId, 'Could not find authentication source.');
+    throw new \SimpleSAML\Error\AuthSource($sourceId, 'Could not find authentication source.');
 }
 
-if (!($source instanceof sspmod_saml_Auth_Source_SP)) {
-    throw new SimpleSAML_Error_AuthSource($sourceId,
-        'The authentication source is not a SAML Service Provider.');
+if (!($source instanceof \SimpleSAML\Module\saml\Auth\Source\SP)) {
+    throw new \SimpleSAML\Error\AuthSource(
+        $sourceId,
+        'The authentication source is not a SAML Service Provider.'
+    );
 }
 
 $entityId = $source->getEntityId();
 $spconfig = $source->getMetadata();
 $store = \SimpleSAML\Store::getInstance();
 
-$metaArray20 = array();
+$metaArray20 = [];
 
-$slosvcdefault = array(
+$slosvcdefault = [
     \SAML2\Constants::BINDING_HTTP_REDIRECT,
     \SAML2\Constants::BINDING_SOAP,
-);
+];
 
 $slob = $spconfig->getArray('SingleLogoutServiceBinding', $slosvcdefault);
-$slol = SimpleSAML\Module::getModuleURL('saml/sp/saml2-logout.php/'.$sourceId);
+$slol = \SimpleSAML\Module::getModuleURL('saml/sp/saml2-logout.php/'.$sourceId);
 
 foreach ($slob as $binding) {
     if ($binding == \SAML2\Constants::BINDING_SOAP && !($store instanceof \SimpleSAML\Store\SQL)) {
         // we cannot properly support SOAP logout
         continue;
     }
-    $metaArray20['SingleLogoutService'][] = array(
+    $metaArray20['SingleLogoutService'][] = [
         'Binding'  => $binding,
         'Location' => $slol,
-    );
+    ];
 }
 
-$assertionsconsumerservicesdefault = array(
+$assertionsconsumerservicesdefault = [
     'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
     'urn:oasis:names:tc:SAML:1.0:profiles:browser-post',
     'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact',
     'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01',
-);
+];
 
 if ($spconfig->getString('ProtocolBinding', '') == 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser') {
     $assertionsconsumerservicesdefault[] = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
@@ -58,43 +60,42 @@ if ($spconfig->getString('ProtocolBinding', '') == 'urn:oasis:names:tc:SAML:2.0:
 $assertionsconsumerservices = $spconfig->getArray('acs.Bindings', $assertionsconsumerservicesdefault);
 
 $index = 0;
-$eps = array();
-$supported_protocols = array();
+$eps = [];
+$supported_protocols = [];
 foreach ($assertionsconsumerservices as $services) {
-
-    $acsArray = array('index' => $index);
+    $acsArray = ['index' => $index];
     switch ($services) {
         case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST':
             $acsArray['Binding'] = \SAML2\Constants::BINDING_HTTP_POST;
-            $acsArray['Location'] = SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
+            $acsArray['Location'] = \SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
             if (!in_array(\SAML2\Constants::NS_SAMLP, $supported_protocols, true)) {
                 $supported_protocols[] = \SAML2\Constants::NS_SAMLP;
             }
             break;
         case 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post':
             $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post';
-            $acsArray['Location'] = SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$sourceId);
+            $acsArray['Location'] = \SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$sourceId);
             if (!in_array('urn:oasis:names:tc:SAML:1.1:protocol', $supported_protocols, true)) {
                 $supported_protocols[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
             }
             break;
         case 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact':
             $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact';
-            $acsArray['Location'] = SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
+            $acsArray['Location'] = \SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
             if (!in_array(\SAML2\Constants::NS_SAMLP, $supported_protocols, true)) {
                 $supported_protocols[] = \SAML2\Constants::NS_SAMLP;
             }
             break;
         case 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01':
             $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:1.0:profiles:artifact-01';
-            $acsArray['Location'] = SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$sourceId.'/artifact');
+            $acsArray['Location'] = \SimpleSAML\Module::getModuleURL('saml/sp/saml1-acs.php/'.$sourceId.'/artifact');
             if (!in_array('urn:oasis:names:tc:SAML:1.1:protocol', $supported_protocols, true)) {
                 $supported_protocols[] = 'urn:oasis:names:tc:SAML:1.1:protocol';
             }
             break;
         case 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser':
             $acsArray['Binding'] = 'urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser';
-            $acsArray['Location'] = SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
+            $acsArray['Location'] = \SimpleSAML\Module::getModuleURL('saml/sp/saml2-acs.php/'.$sourceId);
             $acsArray['hoksso:ProtocolBinding'] = \SAML2\Constants::BINDING_HTTP_REDIRECT;
             if (!in_array(\SAML2\Constants::NS_SAMLP, $supported_protocols, true)) {
                 $supported_protocols[] = \SAML2\Constants::NS_SAMLP;
@@ -107,33 +108,33 @@ foreach ($assertionsconsumerservices as $services) {
 
 $metaArray20['AssertionConsumerService'] = $eps;
 
-$keys = array();
-$certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($spconfig, false, 'new_');
+$keys = [];
+$certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($spconfig, false, 'new_');
 if ($certInfo !== null && array_key_exists('certData', $certInfo)) {
     $hasNewCert = true;
 
     $certData = $certInfo['certData'];
 
-    $keys[] = array(
+    $keys[] = [
         'type'            => 'X509Certificate',
         'signing'         => true,
         'encryption'      => true,
         'X509Certificate' => $certInfo['certData'],
-    );
+    ];
 } else {
     $hasNewCert = false;
 }
 
-$certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($spconfig);
+$certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($spconfig);
 if ($certInfo !== null && array_key_exists('certData', $certInfo)) {
     $certData = $certInfo['certData'];
 
-    $keys[] = array(
+    $keys[] = [
         'type'            => 'X509Certificate',
         'signing'         => true,
         'encryption'      => ($hasNewCert ? false : true),
         'X509Certificate' => $certInfo['certData'],
-    );
+    ];
 } else {
     $certData = null;
 }
@@ -151,12 +152,12 @@ if ($format !== null) {
 }
 
 $name = $spconfig->getLocalizedString('name', null);
-$attributes = $spconfig->getArray('attributes', array());
+$attributes = $spconfig->getArray('attributes', []);
 
 if ($name !== null && !empty($attributes)) {
     $metaArray20['name'] = $name;
     $metaArray20['attributes'] = $attributes;
-    $metaArray20['attributes.required'] = $spconfig->getArray('attributes.required', array());
+    $metaArray20['attributes.required'] = $spconfig->getArray('attributes.required', []);
 
     if (empty($metaArray20['attributes.required'])) {
         unset($metaArray20['attributes.required']);
@@ -171,6 +172,14 @@ if ($name !== null && !empty($attributes)) {
     if ($nameFormat !== null) {
         $metaArray20['attributes.NameFormat'] = $nameFormat;
     }
+
+    if ($spconfig->hasValue('attributes.index')) {
+        $metaArray20['attributes.index'] = $spconfig->getInteger('attributes.index', 0);
+    }
+
+    if ($spconfig->hasValue('attributes.isDefault')) {
+        $metaArray20['attributes.isDefault'] = $spconfig->getBoolean('attributes.isDefault', false);
+    }
 }
 
 // add organization info
@@ -185,7 +194,7 @@ if ($orgName !== null) {
 
     $metaArray20['OrganizationURL'] = $spconfig->getLocalizedString('OrganizationURL', null);
     if ($metaArray20['OrganizationURL'] === null) {
-        throw new SimpleSAML_Error_Exception('If OrganizationName is set, OrganizationURL must also be set.');
+        throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
     }
 }
 
@@ -240,7 +249,7 @@ if ($spconfig->hasValue('redirect.sign')) {
 $metaArray20['metadata-set'] = 'saml20-sp-remote';
 $metaArray20['entityid'] = $entityId;
 
-$metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+$metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($entityId);
 $metaBuilder->addMetadataSP20($metaArray20, $supported_protocols);
 $metaBuilder->addOrganizationInfo($metaArray20);
 
@@ -256,15 +265,14 @@ if (isset($metaArray20['attributes']) && is_array($metaArray20['attributes'])) {
 }
 
 // sign the metadata if enabled
-$xml = SimpleSAML_Metadata_Signer::sign($xml, $spconfig->toArray(), 'SAML 2 SP');
+$xml = \SimpleSAML\Metadata\Signer::sign($xml, $spconfig->toArray(), 'SAML 2 SP');
 
 if (array_key_exists('output', $_REQUEST) && $_REQUEST['output'] == 'xhtml') {
-
-    $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin');
+    $t = new \SimpleSAML\XHTML\Template($config, 'metadata.php', 'admin');
 
     $t->data['clipboard.js'] = true;
     $t->data['header'] = 'saml20-sp'; // TODO: Replace with headerString in 2.0
-    $t->data['headerString'] = $t->noop('metadata_saml20-sp');
+    $t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_saml20-sp');
     $t->data['metadata'] = htmlspecialchars($xml);
     $t->data['metadataflat'] = '$metadata['.var_export($entityId, true).'] = '.var_export($metaArray20, true).';';
     $t->data['metaurl'] = $source->getMetadataURL();
diff --git a/modules/saml/www/sp/saml1-acs.php b/modules/saml/www/sp/saml1-acs.php
index fa1a0efb4e47803738899545578d87ec1dcba31f..db18627fd98e37ac800e7609708f392d23cb0057 100644
--- a/modules/saml/www/sp/saml1-acs.php
+++ b/modules/saml/www/sp/saml1-acs.php
@@ -3,66 +3,70 @@
 use SimpleSAML\Bindings\Shib13\Artifact;
 
 if (!array_key_exists('SAMLResponse', $_REQUEST) && !array_key_exists('SAMLart', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing SAMLResponse or SAMLart parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing SAMLResponse or SAMLart parameter.');
 }
 
 if (!array_key_exists('TARGET', $_REQUEST)) {
-	throw new SimpleSAML_Error_BadRequest('Missing TARGET parameter.');
+    throw new \SimpleSAML\Error\BadRequest('Missing TARGET parameter.');
 }
 
 if (!array_key_exists('PATH_INFO', $_SERVER)) {
-    throw new SimpleSAML_Error_BadRequest('Missing authentication source ID in assertion consumer service URL');
+    throw new \SimpleSAML\Error\BadRequest('Missing authentication source ID in assertion consumer service URL');
 }
 
 $sourceId = $_SERVER['PATH_INFO'];
 $end = strpos($sourceId, '/', 1);
-if ($end === FALSE) {
-	$end = strlen($sourceId);
+if ($end === false) {
+    $end = strlen($sourceId);
 }
 $sourceId = substr($sourceId, 1, $end - 1);
 
-$source = SimpleSAML_Auth_Source::getById($sourceId, 'sspmod_saml_Auth_Source_SP');
+$source = \SimpleSAML\Auth\Source::getById($sourceId, '\SimpleSAML\Module\saml\Auth\Source\SP');
 
 SimpleSAML\Logger::debug('Received SAML1 response');
 
-$target = (string)$_REQUEST['TARGET'];
+$target = (string) $_REQUEST['TARGET'];
 
 if (preg_match('@^https?://@i', $target)) {
-	// Unsolicited response
-	$state = array(
-		'saml:sp:isUnsolicited' => TRUE,
-		'saml:sp:AuthId' => $sourceId,
-		'saml:sp:RelayState' => \SimpleSAML\Utils\HTTP::checkURLAllowed($target),
-	);
+    // Unsolicited response
+    $state = [
+        'saml:sp:isUnsolicited' => true,
+        'saml:sp:AuthId' => $sourceId,
+        'saml:sp:RelayState' => \SimpleSAML\Utils\HTTP::checkURLAllowed($target),
+    ];
 } else {
-	$state = SimpleSAML_Auth_State::loadState($_REQUEST['TARGET'], 'saml:sp:sso');
+    $state = \SimpleSAML\Auth\State::loadState($_REQUEST['TARGET'], 'saml:sp:sso');
 
-	// Check that the authentication source is correct.
-	assert(array_key_exists('saml:sp:AuthId', $state));
-	if ($state['saml:sp:AuthId'] !== $sourceId) {
-		throw new SimpleSAML_Error_Exception('The authentication source id in the URL does not match the authentication source which sent the request.');
-	}
+    // Check that the authentication source is correct
+    assert(array_key_exists('saml:sp:AuthId', $state));
+    if ($state['saml:sp:AuthId'] !== $sourceId) {
+        throw new \SimpleSAML\Error\Exception(
+            'The authentication source id in the URL does not match the authentication source which sent the request.'
+        );
+    }
 
-	assert(isset($state['saml:idp']));
+    assert(isset($state['saml:idp']));
 }
 
 $spMetadata = $source->getMetadata();
 
 if (array_key_exists('SAMLart', $_REQUEST)) {
-	if (!isset($state['saml:idp'])) {
-		/* Unsolicited response. */
-		throw new SimpleSAML_Error_Exception('IdP initiated authentication not supported with the SAML 1.1 SAMLart protocol.');
-	}
-	$idpMetadata = $source->getIdPMetadata($state['saml:idp']);
-
-	$responseXML = Artifact::receive($spMetadata, $idpMetadata);
-	$isValidated = TRUE; /* Artifact binding validated with ssl certificate. */
+    if (!isset($state['saml:idp'])) {
+        // Unsolicited response
+        throw new \SimpleSAML\Error\Exception(
+            'IdP initiated authentication not supported with the SAML 1.1 SAMLart protocol.'
+        );
+    }
+    $idpMetadata = $source->getIdPMetadata($state['saml:idp']);
+
+    $responseXML = Artifact::receive($spMetadata, $idpMetadata);
+    $isValidated = true; /* Artifact binding validated with ssl certificate. */
 } elseif (array_key_exists('SAMLResponse', $_REQUEST)) {
-	$responseXML = $_REQUEST['SAMLResponse'];
-	$responseXML = base64_decode($responseXML);
-	$isValidated = FALSE; /* Must check signature on response. */
+    $responseXML = $_REQUEST['SAMLResponse'];
+    $responseXML = base64_decode($responseXML);
+    $isValidated = false; /* Must check signature on response. */
 } else {
-	assert(false);
+    assert(false);
 }
 
 $response = new \SimpleSAML\XML\Shib13\AuthnResponse();
@@ -75,12 +79,12 @@ $responseIssuer = $response->getIssuer();
 $attributes = $response->getAttributes();
 
 if (isset($state['saml:idp']) && $responseIssuer !== $state['saml:idp']) {
-	throw new SimpleSAML_Error_Exception('The issuer of the response wasn\'t the destination of the request.');
+    throw new \SimpleSAML\Error\Exception('The issuer of the response wasn\'t the destination of the request.');
 }
 
-$logoutState = array(
-	'saml:logout:Type' => 'saml1'
-	);
+$logoutState = [
+    'saml:logout:Type' => 'saml1'
+];
 $state['LogoutState'] = $logoutState;
 
 $state['saml:sp:NameID'] = $response->getNameID();
diff --git a/modules/saml/www/sp/saml2-acs.php b/modules/saml/www/sp/saml2-acs.php
index 7e18f0e81ace7f8750dfc730a0512db570f7e539..9dcec80c5b762c119c7014a3269da63e1a63e36f 100644
--- a/modules/saml/www/sp/saml2-acs.php
+++ b/modules/saml/www/sp/saml2-acs.php
@@ -5,22 +5,24 @@
  */
 
 if (!array_key_exists('PATH_INFO', $_SERVER)) {
-    throw new SimpleSAML_Error_BadRequest('Missing authentication source ID in assertion consumer service URL');
+    throw new \SimpleSAML\Error\BadRequest('Missing authentication source ID in assertion consumer service URL');
 }
 
 $sourceId = substr($_SERVER['PATH_INFO'], 1);
-$source = SimpleSAML_Auth_Source::getById($sourceId, 'sspmod_saml_Auth_Source_SP');
+$source = \SimpleSAML\Auth\Source::getById($sourceId, '\SimpleSAML\Module\saml\Auth\Source\SP');
 $spMetadata = $source->getMetadata();
 
 try {
     $b = \SAML2\Binding::getCurrentBinding();
-} catch (Exception $e) { // TODO: look for a specific exception
+} catch (Exception $e) {
+    // TODO: look for a specific exception
     // This is dirty. Instead of checking the message of the exception, \SAML2\Binding::getCurrentBinding() should throw
     // an specific exception when the binding is unknown, and we should capture that here
     if ($e->getMessage() === 'Unable to find the current binding.') {
-        throw new SimpleSAML_Error_Error('ACSPARAMS', $e, 400);
+        throw new \SimpleSAML\Error\Error('ACSPARAMS', $e, 400);
     } else {
-        throw $e; // do not ignore other exceptions!
+        // do not ignore other exceptions!
+        throw $e;
     }
 }
 
@@ -30,7 +32,7 @@ if ($b instanceof \SAML2\HTTPArtifact) {
 
 $response = $b->receive();
 if (!($response instanceof \SAML2\Response)) {
-    throw new SimpleSAML_Error_BadRequest('Invalid message received to AssertionConsumerService endpoint.');
+    throw new \SimpleSAML\Error\BadRequest('Invalid message received to AssertionConsumerService endpoint.');
 }
 
 $idp = $response->getIssuer();
@@ -49,7 +51,7 @@ if ($idp === null) {
     }
 }
 
-$session = SimpleSAML_Session::getSessionFromRequest();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 $prevAuth = $session->getAuthData($sourceId, 'saml:sp:prevAuth');
 if ($prevAuth !== null && $prevAuth['id'] === $response->getId() && $prevAuth['issuer'] === $idp) {
     /* OK, it looks like this message has the same issuer
@@ -67,17 +69,17 @@ if ($prevAuth !== null && $prevAuth['id'] === $response->getId() && $prevAuth['i
     }
 
     SimpleSAML\Logger::info('No RelayState or ReturnURL available, cannot redirect.');
-    throw new SimpleSAML_Error_Exception('Duplicate assertion received.');
+    throw new \SimpleSAML\Error\Exception('Duplicate assertion received.');
 }
 
-$idpMetadata = array();
+$idpMetadata = [];
 
 $state = null;
 $stateId = $response->getInResponseTo();
 if (!empty($stateId)) {
     // this should be a response to a request we sent earlier
     try {
-        $state = SimpleSAML_Auth_State::loadState($stateId, 'saml:sp:sso');
+        $state = \SimpleSAML\Auth\State::loadState($stateId, 'saml:sp:sso');
     } catch (Exception $e) {
         // something went wrong,
         SimpleSAML\Logger::warning('Could not load state specified by InResponseTo: '.$e->getMessage().
@@ -89,7 +91,7 @@ if ($state) {
     // check that the authentication source is correct
     assert(array_key_exists('saml:sp:AuthId', $state));
     if ($state['saml:sp:AuthId'] !== $sourceId) {
-        throw new SimpleSAML_Error_Exception(
+        throw new \SimpleSAML\Error\Exception(
             'The authentication source id in the URL does not match the authentication source which sent the request.'
         );
     }
@@ -98,16 +100,16 @@ if ($state) {
     assert(array_key_exists('ExpectedIssuer', $state));
     if ($state['ExpectedIssuer'] !== $idp) {
         $idpMetadata = $source->getIdPMetadata($idp);
-        $idplist = $idpMetadata->getArrayize('IDPList', array());
+        $idplist = $idpMetadata->getArrayize('IDPList', []);
         if (!in_array($state['ExpectedIssuer'], $idplist, true)) {
-            throw new SimpleSAML_Error_Exception(
+            throw new \SimpleSAML\Error\Exception(
                 'The issuer of the response does not match to the identity provider we sent the request to.'
             );
         }
     }
 } else {
     // this is an unsolicited response
-    $state = array(
+    $state = [
         'saml:sp:isUnsolicited' => true,
         'saml:sp:AuthId'        => $sourceId,
         'saml:sp:RelayState'    => \SimpleSAML\Utils\HTTP::checkURLAllowed(
@@ -116,7 +118,7 @@ if ($state) {
                 $response->getRelayState()
             )
         ),
-    );
+    ];
 }
 
 SimpleSAML\Logger::debug('Received SAML2 Response from '.var_export($idp, true).'.');
@@ -126,11 +128,11 @@ if (empty($idpMetadata)) {
 }
 
 try {
-    $assertions = sspmod_saml_Message::processResponse($spMetadata, $idpMetadata, $response);
-} catch (sspmod_saml_Error $e) {
+    $assertions = \SimpleSAML\Module\saml\Message::processResponse($spMetadata, $idpMetadata, $response);
+} catch (\SimpleSAML\Module\saml\Error $e) {
     // the status of the response wasn't "success"
     $e = $e->toException();
-    SimpleSAML_Auth_State::throwException($state, $e);
+    \SimpleSAML\Auth\State::throwException($state, $e);
 }
 
 
@@ -138,17 +140,16 @@ $authenticatingAuthority = null;
 $nameId = null;
 $sessionIndex = null;
 $expire = null;
-$attributes = array();
+$attributes = [];
 $foundAuthnStatement = false;
 foreach ($assertions as $assertion) {
-
     // check for duplicate assertion (replay attack)
     $store = \SimpleSAML\Store::getInstance();
     if ($store !== false) {
         $aID = $assertion->getId();
         if ($store->get('saml.AssertionReceived', $aID) !== null) {
-            $e = new SimpleSAML_Error_Exception('Received duplicate assertion.');
-            SimpleSAML_Auth_State::throwException($state, $e);
+            $e = new \SimpleSAML\Error\Exception('Received duplicate assertion.');
+            \SimpleSAML\Auth\State::throwException($state, $e);
         }
 
         $notOnOrAfter = $assertion->getNotOnOrAfter();
@@ -184,8 +185,8 @@ foreach ($assertions as $assertion) {
 }
 
 if (!$foundAuthnStatement) {
-    $e = new SimpleSAML_Error_Exception('No AuthnStatement found in assertion(s).');
-    SimpleSAML_Auth_State::throwException($state, $e);
+    $e = new \SimpleSAML\Error\Exception('No AuthnStatement found in assertion(s).');
+    \SimpleSAML\Auth\State::throwException($state, $e);
 }
 
 if ($expire !== null) {
@@ -197,15 +198,15 @@ if ($expire !== null) {
 
 if (!empty($nameId)) {
     // register this session in the logout store
-    sspmod_saml_SP_LogoutStore::addSession($sourceId, $nameId, $sessionIndex, $logoutExpire);
+    \SimpleSAML\Module\saml\SP\LogoutStore::addSession($sourceId, $nameId, $sessionIndex, $logoutExpire);
 
     // we need to save the NameID and SessionIndex for logout
-    $logoutState = array(
+    $logoutState = [
         'saml:logout:Type'         => 'saml2',
         'saml:logout:IdP'          => $idp,
         'saml:logout:NameID'       => $nameId,
         'saml:logout:SessionIndex' => $sessionIndex,
-    );
+    ];
 
     $state['saml:sp:NameID'] = $nameId; // no need to mark it as persistent, it already is
 } else {
@@ -222,9 +223,9 @@ if (!empty($nameId)) {
      * it to the store), marking the IdP as SAML 1.0, which does not implement logout. Then we can safely log the user
      * out from the local session, skipping Single Logout upstream to the IdP.
      */
-    $logoutState = array(
+    $logoutState = [
         'saml:logout:Type'         => 'saml1',
-    );
+    ];
 }
 
 $state['LogoutState'] = $logoutState;
@@ -243,12 +244,12 @@ if ($expire !== null) {
 }
 
 // note some information about the authentication, in case we receive the same response again
-$state['saml:sp:prevAuth'] = array(
+$state['saml:sp:prevAuth'] = [
     'id'     => $response->getId(),
     'issuer' => $idp,
-);
-if (isset($state['SimpleSAML_Auth_Source.ReturnURL'])) {
-    $state['saml:sp:prevAuth']['redirect'] = $state['SimpleSAML_Auth_Source.ReturnURL'];
+];
+if (isset($state['\SimpleSAML\Auth\Source.ReturnURL'])) {
+    $state['saml:sp:prevAuth']['redirect'] = $state['\SimpleSAML\Auth\Source.ReturnURL'];
 } elseif (isset($state['saml:sp:RelayState'])) {
     $state['saml:sp:prevAuth']['redirect'] = $state['saml:sp:RelayState'];
 }
diff --git a/modules/saml/www/sp/saml2-logout.php b/modules/saml/www/sp/saml2-logout.php
index 6fa5a0081791bc2d3588095822fc4c9a8eecfe8c..e67431f83ac204193fb2c4d69800c9f57f96dc41 100644
--- a/modules/saml/www/sp/saml2-logout.php
+++ b/modules/saml/www/sp/saml2-logout.php
@@ -7,26 +7,27 @@
  */
 
 if (!array_key_exists('PATH_INFO', $_SERVER)) {
-	throw new SimpleSAML_Error_BadRequest('Missing authentication source ID in logout URL');
+    throw new \SimpleSAML\Error\BadRequest('Missing authentication source ID in logout URL');
 }
 
 $sourceId = substr($_SERVER['PATH_INFO'], 1);
 
-$source = SimpleSAML_Auth_Source::getById($sourceId);
-if ($source === NULL) {
-	throw new Exception('Could not find authentication source with id ' . $sourceId);
+$source = \SimpleSAML\Auth\Source::getById($sourceId);
+if ($source === null) {
+    throw new \Exception('Could not find authentication source with id '.$sourceId);
 }
-if (!($source instanceof sspmod_saml_Auth_Source_SP)) {
-	throw new SimpleSAML_Error_Exception('Source type changed?');
+if (!($source instanceof \SimpleSAML\Module\saml\Auth\Source\SP)) {
+    throw new \SimpleSAML\Error\Exception('Source type changed?');
 }
 
 try {
     $binding = \SAML2\Binding::getCurrentBinding();
-} catch (Exception $e) { // TODO: look for a specific exception
+} catch (\Exception $e) {
+    // TODO: look for a specific exception
     // This is dirty. Instead of checking the message of the exception, \SAML2\Binding::getCurrentBinding() should throw
     // an specific exception when the binding is unknown, and we should capture that here
     if ($e->getMessage() === 'Unable to find the current binding.') {
-        throw new SimpleSAML_Error_Error('SLOSERVICEPARAMS', $e, 400);
+        throw new \SimpleSAML\Error\Error('SLOSERVICEPARAMS', $e, 400);
     } else {
         throw $e; // do not ignore other exceptions!
     }
@@ -34,107 +35,109 @@ try {
 $message = $binding->receive();
 
 $idpEntityId = $message->getIssuer();
-if ($idpEntityId === NULL) {
-	// Without an issuer we have no way to respond to the message.
-	throw new SimpleSAML_Error_BadRequest('Received message on logout endpoint without issuer.');
+if ($idpEntityId === null) {
+    // Without an issuer we have no way to respond to the message.
+    throw new \SimpleSAML\Error\BadRequest('Received message on logout endpoint without issuer.');
 }
 
 $spEntityId = $source->getEntityId();
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpMetadata = $source->getIdPMetadata($idpEntityId);
 $spMetadata = $source->getMetadata();
 
-sspmod_saml_Message::validateMessage($idpMetadata, $spMetadata, $message);
+\SimpleSAML\Module\saml\Message::validateMessage($idpMetadata, $spMetadata, $message);
 
 $destination = $message->getDestination();
-if ($destination !== NULL && $destination !== \SimpleSAML\Utils\HTTP::getSelfURLNoQuery()) {
-	throw new SimpleSAML_Error_Exception('Destination in logout message is wrong.');
+if ($destination !== null && $destination !== \SimpleSAML\Utils\HTTP::getSelfURLNoQuery()) {
+    throw new \SimpleSAML\Error\Exception('Destination in logout message is wrong.');
 }
 
 if ($message instanceof \SAML2\LogoutResponse) {
+    $relayState = $message->getRelayState();
+    if ($relayState === null) {
+        // Somehow, our RelayState has been lost.
+        throw new \SimpleSAML\Error\BadRequest('Missing RelayState in logout response.');
+    }
 
-	$relayState = $message->getRelayState();
-	if ($relayState === NULL) {
-		// Somehow, our RelayState has been lost.
-		throw new SimpleSAML_Error_BadRequest('Missing RelayState in logout response.');
-	}
+    if (!$message->isSuccess()) {
+        \SimpleSAML\Logger::warning(
+            'Unsuccessful logout. Status was: '.\SimpleSAML\Module\saml\Message::getResponseError($message)
+        );
+    }
 
-	if (!$message->isSuccess()) {
-		SimpleSAML\Logger::warning('Unsuccessful logout. Status was: ' . sspmod_saml_Message::getResponseError($message));
-	}
+    $state = \SimpleSAML\Auth\State::loadState($relayState, 'saml:slosent');
+    $state['saml:sp:LogoutStatus'] = $message->getStatus();
+    \SimpleSAML\Auth\Source::completeLogout($state);
+} elseif ($message instanceof \SAML2\LogoutRequest) {
+    \SimpleSAML\Logger::debug('module/saml2/sp/logout: Request from '.$idpEntityId);
+    \SimpleSAML\Logger::stats('saml20-idp-SLO idpinit '.$spEntityId.' '.$idpEntityId);
+
+    if ($message->isNameIdEncrypted()) {
+        try {
+            $keys = \SimpleSAML\Module\saml\Message::getDecryptionKeys($idpMetadata, $spMetadata);
+        } catch (\Exception $e) {
+            throw new \SimpleSAML\Error\Exception('Error decrypting NameID: '.$e->getMessage());
+        }
+
+        $blacklist = \SimpleSAML\Module\saml\Message::getBlacklistedAlgorithms($idpMetadata, $spMetadata);
+
+        $lastException = null;
+        foreach ($keys as $i => $key) {
+            try {
+                $message->decryptNameId($key, $blacklist);
+                \SimpleSAML\Logger::debug('Decryption with key #'.$i.' succeeded.');
+                $lastException = null;
+                break;
+            } catch (\Exception $e) {
+                \SimpleSAML\Logger::debug('Decryption with key #'.$i.' failed with exception: '.$e->getMessage());
+                $lastException = $e;
+            }
+        }
+        if ($lastException !== null) {
+            throw $lastException;
+        }
+    }
 
-	$state = SimpleSAML_Auth_State::loadState($relayState, 'saml:slosent');
-	$state['saml:sp:LogoutStatus'] = $message->getStatus();
-	SimpleSAML_Auth_Source::completeLogout($state);
+    $nameId = $message->getNameId();
+    $sessionIndexes = $message->getSessionIndexes();
 
-} elseif ($message instanceof \SAML2\LogoutRequest) {
+    $numLoggedOut = \SimpleSAML\Module\saml\SP\LogoutStore::logoutSessions($sourceId, $nameId, $sessionIndexes);
+    if ($numLoggedOut === false) {
+        // This type of logout was unsupported. Use the old method
+        $source->handleLogout($idpEntityId);
+        $numLoggedOut = count($sessionIndexes);
+    }
+
+    // Create and send response
+    $lr = \SimpleSAML\Module\saml\Message::buildLogoutResponse($spMetadata, $idpMetadata);
+    $lr->setRelayState($message->getRelayState());
+    $lr->setInResponseTo($message->getId());
+
+    if ($numLoggedOut < count($sessionIndexes)) {
+        \SimpleSAML\Logger::warning('Logged out of '.$numLoggedOut.' of '.count($sessionIndexes).' sessions.');
+    }
+
+    $dst = $idpMetadata->getEndpointPrioritizedByBinding(
+        'SingleLogoutService',
+        [
+            \SAML2\Constants::BINDING_HTTP_REDIRECT,
+            \SAML2\Constants::BINDING_HTTP_POST
+        ]
+    );
+
+    if (!$binding instanceof \SAML2\SOAP) {
+        $binding = \SAML2\Binding::getBinding($dst['Binding']);
+        if (isset($dst['ResponseLocation'])) {
+            $dst = $dst['ResponseLocation'];
+        } else {
+            $dst = $dst['Location'];
+        }
+        $binding->setDestination($dst);
+    }
+    $lr->setDestination($dst);
 
-	SimpleSAML\Logger::debug('module/saml2/sp/logout: Request from ' . $idpEntityId);
-	SimpleSAML\Logger::stats('saml20-idp-SLO idpinit ' . $spEntityId . ' ' . $idpEntityId);
-
-	if ($message->isNameIdEncrypted()) {
-		try {
-			$keys = sspmod_saml_Message::getDecryptionKeys($idpMetadata, $spMetadata);
-		} catch (Exception $e) {
-			throw new SimpleSAML_Error_Exception('Error decrypting NameID: ' . $e->getMessage());
-		}
-
-		$blacklist = sspmod_saml_Message::getBlacklistedAlgorithms($idpMetadata, $spMetadata);
-
-		$lastException = NULL;
-		foreach ($keys as $i => $key) {
-			try {
-				$message->decryptNameId($key, $blacklist);
-				SimpleSAML\Logger::debug('Decryption with key #' . $i . ' succeeded.');
-				$lastException = NULL;
-				break;
-			} catch (Exception $e) {
-				SimpleSAML\Logger::debug('Decryption with key #' . $i . ' failed with exception: ' . $e->getMessage());
-				$lastException = $e;
-			}
-		}
-		if ($lastException !== NULL) {
-			throw $lastException;
-		}
-	}
-
-	$nameId = $message->getNameId();
-	$sessionIndexes = $message->getSessionIndexes();
-
-	$numLoggedOut = sspmod_saml_SP_LogoutStore::logoutSessions($sourceId, $nameId, $sessionIndexes);
-	if ($numLoggedOut === FALSE) {
-		/* This type of logout was unsupported. Use the old method. */
-		$source->handleLogout($idpEntityId);
-		$numLoggedOut = count($sessionIndexes);
-	}
-
-	/* Create an send response. */
-	$lr = sspmod_saml_Message::buildLogoutResponse($spMetadata, $idpMetadata);
-	$lr->setRelayState($message->getRelayState());
-	$lr->setInResponseTo($message->getId());
-
-	if ($numLoggedOut < count($sessionIndexes)) {
-		SimpleSAML\Logger::warning('Logged out of ' . $numLoggedOut  . ' of ' . count($sessionIndexes) . ' sessions.');
-	}
-
-	$dst = $idpMetadata->getEndpointPrioritizedByBinding('SingleLogoutService', array(
-		\SAML2\Constants::BINDING_HTTP_REDIRECT,
-		\SAML2\Constants::BINDING_HTTP_POST)
-	);
-
-	if (!$binding instanceof \SAML2\SOAP) {
-		$binding = \SAML2\Binding::getBinding($dst['Binding']);
-		if (isset($dst['ResponseLocation'])) {
-			$dst = $dst['ResponseLocation'];
-		} else {
-			$dst = $dst['Location'];
-		}
-		$binding->setDestination($dst);
-	}
-	$lr->setDestination($dst);
-
-	$binding->send($lr);
+    $binding->send($lr);
 } else {
-	throw new SimpleSAML_Error_BadRequest('Unknown message received on logout endpoint: ' . get_class($message));
+    throw new \SimpleSAML\Error\BadRequest('Unknown message received on logout endpoint: '.get_class($message));
 }
diff --git a/modules/saml/www/sp/wrong_authncontextclassref.php b/modules/saml/www/sp/wrong_authncontextclassref.php
index 18e17617d5ca97c8c9b0d60884d2c74fd31043d8..9cb93bf70dbfeffbe30c113b323f9c834c9d6cce 100644
--- a/modules/saml/www/sp/wrong_authncontextclassref.php
+++ b/modules/saml/www/sp/wrong_authncontextclassref.php
@@ -1,5 +1,5 @@
 <?php
 
-$globalConfig = SimpleSAML_Configuration::getInstance();
-$t = new SimpleSAML_XHTML_Template($globalConfig, 'saml:sp/wrong_authncontextclassref.tpl.php');
+$globalConfig = \SimpleSAML\Configuration::getInstance();
+$t = new \SimpleSAML\XHTML\Template($globalConfig, 'saml:sp/wrong_authncontextclassref.tpl.php');
 $t->show();
diff --git a/modules/sanitycheck/config-templates/config-sanitycheck.php b/modules/sanitycheck/config-templates/config-sanitycheck.php
index ac40a0f48e8a5e1da222ce943bb5fd3deee5fcae..d9b45bb8af9fb724067659284eb3a0d67116d642 100644
--- a/modules/sanitycheck/config-templates/config-sanitycheck.php
+++ b/modules/sanitycheck/config-templates/config-sanitycheck.php
@@ -1,10 +1,9 @@
 <?php
-/* 
+/*
  * The configuration of SimpleSAMLphp sanitycheck package
  */
 
-$config = array (
-
+$config = [
     /*
      * Do you want to generate statistics using the cron module? If so, specify which cron tag to use.
      * Examples: daily, weekly
@@ -12,5 +11,4 @@ $config = array (
      *     'cron_tag' => null,
      */
     'cron_tag' => 'hourly',
-
-);
+];
diff --git a/modules/sanitycheck/hooks/hook_cron.php b/modules/sanitycheck/hooks/hook_cron.php
index abb2b0ce45cbc37dc690343244eb27cc7ecbcb8e..15e0736ddbdd7c6457dd586b210f7af6ae4295db 100644
--- a/modules/sanitycheck/hooks/hook_cron.php
+++ b/modules/sanitycheck/hooks/hook_cron.php
@@ -4,38 +4,38 @@
  *
  * @param array &$croninfo  Output
  */
+
 function sanitycheck_hook_cron(&$croninfo)
 {
     assert(is_array($croninfo));
     assert(array_key_exists('summary', $croninfo));
     assert(array_key_exists('tag', $croninfo));
 
-    SimpleSAML\Logger::info('cron [sanitycheck]: Running cron in cron tag [' . $croninfo['tag'] . '] ');
+    \SimpleSAML\Logger::info('cron [sanitycheck]: Running cron in cron tag ['.$croninfo['tag'].'] ');
 
     try {
-        $sconfig = SimpleSAML_Configuration::getOptionalConfig('config-sanitycheck.php');
+        $sconfig = \SimpleSAML\Configuration::getOptionalConfig('config-sanitycheck.php');
 
         $cronTag = $sconfig->getString('cron_tag', null);
         if ($cronTag === null || $cronTag !== $croninfo['tag']) {
             return;
         }
 
-        $info = array();
-        $errors = array();
-        $hookinfo = array(
+        $info = [];
+        $errors = [];
+        $hookinfo = [
             'info' => &$info,
             'errors' => &$errors,
-        );
+        ];
 
         SimpleSAML\Module::callHooks('sanitycheck', $hookinfo);
 
         if (count($errors) > 0) {
-            foreach ($errors AS $err) {
-                $croninfo['summary'][] = 'Sanitycheck error: ' . $err;
+            foreach ($errors as $err) {
+                $croninfo['summary'][] = 'Sanitycheck error: '.$err;
             }
         }
-
     } catch (Exception $e) {
-        $croninfo['summary'][] = 'Error executing sanity check: ' . $e->getMessage();
+        $croninfo['summary'][] = 'Error executing sanity check: '.$e->getMessage();
     }
 }
diff --git a/modules/sanitycheck/hooks/hook_frontpage.php b/modules/sanitycheck/hooks/hook_frontpage.php
index b713601180f28a22036c800eb7bfa0e57d5e50c8..95dddf7aa1861dab67ca05dc502e881795404421 100644
--- a/modules/sanitycheck/hooks/hook_frontpage.php
+++ b/modules/sanitycheck/hooks/hook_frontpage.php
@@ -9,9 +9,8 @@ function sanitycheck_hook_frontpage(&$links)
     assert(is_array($links));
     assert(array_key_exists('links', $links));
 
-    $links['config']['santitycheck'] = array(
+    $links['config']['sanitycheck'] = [
         'href' => SimpleSAML\Module::getModuleURL('sanitycheck/index.php'),
-        'text' => array('en' => 'Sanity check of your SimpleSAMLphp setup'),
-        'shorttext' => array('en' => 'SanityCheck'),
-    );
+        'text' => '{core:frontpage:link_sanitycheck}',
+    ];
 }
diff --git a/modules/sanitycheck/hooks/hook_moduleinfo.php b/modules/sanitycheck/hooks/hook_moduleinfo.php
index 60f7acd72daea3e38269d32c16f9da512b076f6d..87d014e2ec5a2e0c2098e1fe9aab5a60062d9d26 100644
--- a/modules/sanitycheck/hooks/hook_moduleinfo.php
+++ b/modules/sanitycheck/hooks/hook_moduleinfo.php
@@ -9,11 +9,11 @@ function sanitycheck_hook_moduleinfo(&$moduleinfo)
     assert(is_array($moduleinfo));
     assert(array_key_exists('info', $moduleinfo));
 
-    $moduleinfo['info']['sanitycheck'] = array(
-        'name' => array('en' => 'Sanity check'),
-        'description' => array('en' => 'This module adds functionality for other modules to provide santity checks.'),
+    $moduleinfo['info']['sanitycheck'] = [
+        'name' => ['en' => 'Sanity check'],
+        'description' => ['en' => 'This module adds functionality for other modules to provide sanity checks.'],
 
-        'dependencies' => array('core'),
-        'uses' => array('cron'),
-    );
+        'dependencies' => ['core'],
+        'uses' => ['cron'],
+    ];
 }
diff --git a/modules/sanitycheck/locales/en/LC_MESSAGES/messages.po b/modules/sanitycheck/locales/en/LC_MESSAGES/messages.po
new file mode 100644
index 0000000000000000000000000000000000000000..2b50d34d18dce5a79e59d9c8139ea8d5172e2da9
--- /dev/null
+++ b/modules/sanitycheck/locales/en/LC_MESSAGES/messages.po
@@ -0,0 +1,6 @@
+msgid "These checks failed:"
+msgstr "These checks failed:"
+
+msgid "These checks succeeded:"
+msgstr "These checks succeeded:"
+
diff --git a/modules/sanitycheck/locales/it/LC_MESSAGES/messages.po b/modules/sanitycheck/locales/it/LC_MESSAGES/messages.po
new file mode 100644
index 0000000000000000000000000000000000000000..558b243e066a7ab4408a5223ad3529b804efc737
--- /dev/null
+++ b/modules/sanitycheck/locales/it/LC_MESSAGES/messages.po
@@ -0,0 +1,6 @@
+msgid "These checks failed:"
+msgstr "I seguenti controlli hanno riscontrato dei problemi:"
+
+msgid "These checks succeeded:"
+msgstr "I seguenti controlli sono stati eseguiti con successo:"
+
diff --git a/modules/sanitycheck/templates/check.tpl.php b/modules/sanitycheck/templates/check.tpl.php
index cf34bff6121205914565cc434813e7973b006db3..ba9f69ada602d490a9f01bf6593e81a123f02800 100644
--- a/modules/sanitycheck/templates/check.tpl.php
+++ b/modules/sanitycheck/templates/check.tpl.php
@@ -2,44 +2,28 @@
 $this->data['header'] = 'Sanity check';
 $this->includeAtTemplateBase('includes/header.php');
 
-?>
-
-<h2><?php echo($this->data['header']); ?></h2>
-
-<?php
+echo '<h2>'.$this->data['header'].'</h2>';
 if (count($this->data['errors']) > 0) {
-?>
-<div style="border: 1px solid #800; background: #caa; margin: 1em; padding: .5em">
-<p><?php echo '<img class="float-r" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="Failed" />'; ?>	
-These checks failed:</p>
-<?php
-
-	echo '<ul>';
-	foreach ($this->data['errors'] AS $err) {
-		echo '<li>' . $err . '</li>';
-	}
-	echo '</ul>';
-
-echo '</div>';
+    echo '<div style="border: 1px solid #800; background: #caa; margin: 1em; padding: .5em">';
+    echo '<p><img class="float-r" src="/'.$this->data['baseurlpath'].
+        'resources/icons/silk/delete.png" alt="Failed" />These checks failed:</p>';
+    echo '<ul>';
+    foreach ($this->data['errors'] as $err) {
+        echo '<li>'.$err.'</li>';
+    }
 }
 ?>
-
+    </ul>
+</div>
 <?php
 if (count($this->data['info']) > 0) {
-?>
-<div style="border: 1px solid #ccc; background: #eee; margin: 1em; padding: .5em">
-<p><?php echo '<img class="float-r" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="OK" />'; ?>	
-These checks succeeded:</p>
-<?php
-	echo '<ul>';
-	foreach ($this->data['info'] AS $i) {
-		echo '<li>' . $i . '</li>';
-	}
-	echo '</ul>';
-
-
-echo '</div>';
+    echo '<div style="border: 1px solid #ccc; background: #eee; margin: 1em; padding: .5em">';
+    echo '<p><img class="float-r" src="/'.$this->data['baseurlpath'].
+        'resources/icons/silk/accept.png" alt="OK" />These checks succeeded:</p>';
+    echo '<ul>';
+    foreach ($this->data['info'] as $i) {
+        echo '<li>'.$i.'</li>';
+    }
 }
-?>
-
-<?php $this->includeAtTemplateBase('includes/footer.php'); ?>
\ No newline at end of file
+echo '</ul></div>';
+$this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/sanitycheck/templates/check.twig b/modules/sanitycheck/templates/check.twig
index ab53e5c5fd6f27a1317d9df03094b83202f9f0f0..fe51f41809cade804ccfcb83bdd5eb9b3dccfa8a 100644
--- a/modules/sanitycheck/templates/check.twig
+++ b/modules/sanitycheck/templates/check.twig
@@ -5,30 +5,41 @@
 <h2>{{ pagetitle }}</h2>
 
 {% if errors %}
-<div style="border: 1px solid #800; background: #caa; margin: 1em; padding: .5em">
-<p><img class="float-r" src="/{{ baseurlpath }}resources/icons/silk/delete.png" alt="Failed" />
-These checks failed:</p>
-
-<ul>
-{% for err in errors %}
-    <li>{{ err }}</li>
-{% endfor %}
-</ul>
 
+<div class="message-box error">
+    <div class="pure-g">
+        <div class="pure-u-1-12">
+            <span class="fa fa-times-circle fa-2x"></span>
+        </div>
+        <div class="pure-u-11-12">
+            <p>{{ 'These checks failed:'|trans }}</p>
+
+            <ul class="error-list">
+            {% for err in errors %}
+                <li>{{ err }}</li>
+            {% endfor %}
+            </ul>
+        </div>
+    </div>
 </div>
 {% endif %}
 
 {% if info %}
-<div style="border: 1px solid #ccc; background: #eee; margin: 1em; padding: .5em">
-<p><img class="float-r" src="/{{ baseurlpath }}resources/icons/silk/accept.png" alt="OK" />
-These checks succeeded:</p> 
-
-<ul>
-{% for i in info %}
-    <li>{{ i }}</li>
-{% endfor %}
-</ul>
-
+<div class="message-box success">
+    <div class="pure-g">
+        <div class="pure-u-1-12">
+            <span class="fa fa-check fa-2x"> </span>
+        </div>
+        <div class="pure-u-11-12">
+            <p>{{ 'These checks succeeded:'|trans }}</p>
+
+            <ul>
+            {% for i in info %}
+                <li>{{ i }}</li>
+            {% endfor %}
+            </ul>
+        </div>
+    </div>
 </div>
 {% endif %}
 
diff --git a/modules/sanitycheck/www/index.php b/modules/sanitycheck/www/index.php
index e365db28d57a98282e3abe0528d0c0d8604fa42c..8946bad073f5ca56a7107056c5343ec8acefda21 100644
--- a/modules/sanitycheck/www/index.php
+++ b/modules/sanitycheck/www/index.php
@@ -1,17 +1,16 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
-$info = array();
-$errors = array();
-$hookinfo = array(
+$info = [];
+$errors = [];
+$hookinfo = [
     'info' => &$info,
     'errors' => &$errors,
-);
-SimpleSAML\Module::callHooks('sanitycheck', $hookinfo);
+];
+\SimpleSAML\Module::callHooks('sanitycheck', $hookinfo);
 
 if (isset($_REQUEST['output']) && $_REQUEST['output'] == 'text') {
-
     if (count($errors) === 0) {
         echo 'OK';
     } else {
@@ -20,7 +19,7 @@ if (isset($_REQUEST['output']) && $_REQUEST['output'] == 'text') {
     exit;
 }
 
-$t = new SimpleSAML_XHTML_Template($config, 'sanitycheck:check.tpl.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'sanitycheck:check.tpl.php');
 $t->data['pageid'] = 'sanitycheck';
 $t->data['errors'] = $errors;
 $t->data['info'] = $info;
diff --git a/modules/smartattributes/docs/smartattributes.md b/modules/smartattributes/docs/smartattributes.md
index 0c2c8c1369d950130a79d2784702405b47b02d19..06fd24141088bb8db5c8c86246989c42c5b8728e 100644
--- a/modules/smartattributes/docs/smartattributes.md
+++ b/modules/smartattributes/docs/smartattributes.md
@@ -17,11 +17,12 @@ The filter has the following configuration options:
 * `candidates`. An array of attributes names to consider as the identifier attribute. Defaults to:
 	* eduPersonTargetedID
 	* eduPersonPrincipalName
+	* pairwise-id
+	* subject-id
 	* openid
 	* facebook_targetedID
 	* twitter_targetedID
 	* windowslive_targetedID
-	* myspace_targetedID
 	* linkedin_targetedID
 * `id_attribute`. A string to use as the name of the newly added attribute. Defaults to `smart_id`.
 * `add_authority`. A boolean to indicate whether or not to append the SAML AuthenticatingAuthority to the resulting identifier. This can be useful to indicate what SAML IdP was used, in case the original identifier is not scoped. Defaults to `TRUE`.
diff --git a/modules/smartattributes/lib/Auth/Process/SmartID.php b/modules/smartattributes/lib/Auth/Process/SmartID.php
index 67dba450b972ea3b4ee86f97342a5571a4057085..00ca468eae4ff9ce4f4afe09e1de9949577f1ce7 100644
--- a/modules/smartattributes/lib/Auth/Process/SmartID.php
+++ b/modules/smartattributes/lib/Auth/Process/SmartID.php
@@ -1,117 +1,125 @@
 <?php
 
-class sspmod_smartattributes_Auth_Process_SmartID extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Which attributes to use as identifiers?
-	 *
-	 * IMPORTANT: If you use the (default) attributemaps (twitter2name, facebook2name,
-	 * etc., be sure to comment out the entries that map xxx_targetedID to
-	 * eduPersonTargetedID, or there will be no way to see its origin any more.
-	 */
-	private $_candidates = array(
-		'eduPersonTargetedID',
-		'eduPersonPrincipalName',
-		'openid',
-		'facebook_targetedID',
-		'twitter_targetedID',
-		'windowslive_targetedID',
-		'myspace_targetedID',
-		'linkedin_targetedID',
-	);
-
-	/**
-	 * The name of the generated ID attribute.
-	 */
-	private $_id_attribute = 'smart_id';
-
-	/**
-	 * Whether to append the AuthenticatingAuthority, separated by '!'
-	 * This only works when SSP is used as a gateway.
-	 */
-	private $_add_authority = true;
-
-	/**
-	 * Whether to prepend the CandidateID, separated by ':'
-	 */
-	private $_add_candidate = true;
-
-	/**
-	 * Attributes which should be added/appended.
-	 *
-	 * Associative array of arrays.
-	 */
-	private $attributes = array();
-
-
-	public function __construct($config, $reserved) {
-		parent::__construct($config, $reserved);
-
-		assert(is_array($config));
-
-		if (array_key_exists('candidates', $config)) {
-			$this->_candidates = $config['candidates'];
-			if (!is_array($this->_candidates)) {
-				throw new Exception('SmartID authproc configuration error: \'candidates\' should be an array.');
-			}
-		}
-
-		if (array_key_exists('id_attribute', $config)) {
-			$this->_id_attribute = $config['id_attribute'];
-			if (!is_string($this->_id_attribute)) {
-				throw new Exception('SmartID authproc configuration error: \'id_attribute\' should be a string.');
-			}
-		}
-
-		if (array_key_exists('add_authority', $config)) {
-			$this->_add_authority = $config['add_authority'];
-			if (!is_bool($this->_add_authority)) {
-				throw new Exception('SmartID authproc configuration error: \'add_authority\' should be a boolean.');
-			}
-		}
-
-		if (array_key_exists('add_candidate', $config)) {
-			$this->_add_candidate = $config['add_candidate'];
-			if (!is_bool($this->_add_candidate)) {
-				throw new Exception('SmartID authproc configuration error: \'add_candidate\' should be a boolean.');
-			}
-		}
-
-	}
-
-	private function addID($attributes, $request) {
-		foreach ($this->_candidates as $idCandidate) {
-			if (isset($attributes[$idCandidate][0])) {
-				if(($this->_add_authority) && (isset($request['saml:AuthenticatingAuthority'][0]))) {
-					return ($this->_add_candidate ? $idCandidate.':' : '').$attributes[$idCandidate][0] . '!' . $request['saml:AuthenticatingAuthority'][0];
-				} else {
-					return ($this->_add_candidate ? $idCandidate.':' : '').$attributes[$idCandidate][0];
-				}
-			}
-		}
-		/*
-		* At this stage no usable id_candidate has been detected.
-		*/
-		throw new SimpleSAML_Error_Exception('This service needs at least one of the following
-		attributes to identity users: '.implode(', ', $this->_candidates).'. Unfortunately not
-		one of them was detected. Please ask your institution administrator to release one of
-		them, or try using another identity provider.');
-	}
-
-
-	/**
-	 * Apply filter to add or replace attributes.
-	 *
-	 * Add or replace existing attributes with the configured values.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		$ID = $this->addID($request['Attributes'], $request);
-
-		if(isset($ID)) $request['Attributes'][$this->_id_attribute] = array($ID);
-	}
+namespace SimpleSAML\Module\smartattributes\Auth\Process;
+
+class SmartID extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Which attributes to use as identifiers?
+     *
+     * IMPORTANT: If you use the (default) attributemaps (twitter2name, facebook2name,
+     * etc., be sure to comment out the entries that map xxx_targetedID to
+     * eduPersonTargetedID, or there will be no way to see its origin any more.
+     */
+    private $candidates = [
+        'eduPersonTargetedID',
+        'eduPersonPrincipalName',
+        'pairwise-id',
+        'subject-id',
+        'openid',
+        'facebook_targetedID',
+        'twitter_targetedID',
+        'windowslive_targetedID',
+        'linkedin_targetedID',
+    ];
+
+    /**
+     * The name of the generated ID attribute.
+     */
+    private $id_attribute = 'smart_id';
+
+    /**
+     * Whether to append the AuthenticatingAuthority, separated by '!'
+     * This only works when SSP is used as a gateway.
+     */
+    private $add_authority = true;
+
+    /**
+     * Whether to prepend the CandidateID, separated by ':'
+     */
+    private $add_candidate = true;
+
+    /**
+     * Attributes which should be added/appended.
+     *
+     * Associative array of arrays.
+     */
+    private $attributes = [];
+
+
+    public function __construct($config, $reserved)
+    {
+        parent::__construct($config, $reserved);
+
+        assert(is_array($config));
+
+        if (array_key_exists('candidates', $config)) {
+            $this->candidates = $config['candidates'];
+            if (!is_array($this->candidates)) {
+                throw new \Exception('SmartID authproc configuration error: \'candidates\' should be an array.');
+            }
+        }
+
+        if (array_key_exists('id_attribute', $config)) {
+            $this->id_attribute = $config['id_attribute'];
+            if (!is_string($this->id_attribute)) {
+                throw new \Exception('SmartID authproc configuration error: \'id_attribute\' should be a string.');
+            }
+        }
+
+        if (array_key_exists('add_authority', $config)) {
+            $this->add_authority = $config['add_authority'];
+            if (!is_bool($this->add_authority)) {
+                throw new \Exception('SmartID authproc configuration error: \'add_authority\' should be a boolean.');
+            }
+        }
+
+        if (array_key_exists('add_candidate', $config)) {
+            $this->add_candidate = $config['add_candidate'];
+            if (!is_bool($this->add_candidate)) {
+                throw new \Exception('SmartID authproc configuration error: \'add_candidate\' should be a boolean.');
+            }
+        }
+    }
+
+    private function addID($attributes, $request)
+    {
+        $state = $request['saml:sp:State'];
+        foreach ($this->candidates as $idCandidate) {
+            if (isset($attributes[$idCandidate][0])) {
+                if (($this->add_authority) && (isset($state['saml:AuthenticatingAuthority'][0]))) {
+                    return ($this->add_candidate ? $idCandidate.':' : '').$attributes[$idCandidate][0].'!'.
+                        $state['saml:AuthenticatingAuthority'][0];
+                } else {
+                    return ($this->add_candidate ? $idCandidate.':' : '').$attributes[$idCandidate][0];
+                }
+            }
+        }
+        /*
+         * At this stage no usable id_candidate has been detected.
+         */
+        throw new \SimpleSAML\Error\Exception('This service needs at least one of the following
+            attributes to identity users: '.implode(', ', $this->candidates).'. Unfortunately not
+            one of them was detected. Please ask your institution administrator to release one of
+            them, or try using another identity provider.');
+    }
+
+    /**
+     * Apply filter to add or replace attributes.
+     *
+     * Add or replace existing attributes with the configured values.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        $id = $this->addID($request['Attributes'], $request);
+
+        if (isset($id)) {
+            $request['Attributes'][$this->id_attribute] = [$id];
+        }
+    }
 }
diff --git a/modules/smartattributes/lib/Auth/Process/SmartName.php b/modules/smartattributes/lib/Auth/Process/SmartName.php
index 44323f9196a22ab4ae2597eb76a117e95c493162..19a69baa6f31d66fc8a15e3bdc1c7d72d3c67bb5 100644
--- a/modules/smartattributes/lib/Auth/Process/SmartName.php
+++ b/modules/smartattributes/lib/Auth/Process/SmartName.php
@@ -1,76 +1,92 @@
 <?php
 
+namespace SimpleSAML\Module\smartattributes\Auth\Process;
+
 /**
  * Filter to set name in a smart way, based on available name attributes.
  *
  * @author Andreas Ă…kre Solberg, UNINETT AS.
  * @package SimpleSAMLphp
  */
-class sspmod_smartattributes_Auth_Process_SmartName extends SimpleSAML_Auth_ProcessingFilter {
-
-	/**
-	 * Attributes which should be added/appended.
-	 *
-	 * Assiciative array of arrays.
-	 */
-	private $attributes = array();
-
-
-	private function getFullName($attributes) {
-		if (isset($attributes['displayName']))
-			return $attributes['displayName'][0];
-		
-		if (isset($attributes['cn'])) {
-			if (count(explode(' ', $attributes['cn'][0])) > 1)
-				return $attributes['cn'][0];
-		}
-		
-		if (isset($attributes['sn']) && isset($attributes['givenName']))
-			return $attributes['givenName'][0] . ' ' . $attributes['sn'][0];
-
-		if (isset($attributes['cn']))
-			return $attributes['cn'][0];
-
-		if (isset($attributes['sn']))
-			return $attributes['sn'][0];
-
-		if (isset($attributes['givenName']))
-			return $attributes['givenName'][0];
-		
-		if (isset($attributes['eduPersonPrincipalName'])) {
-			$localname = $this->getLocalUser($attributes['eduPersonPrincipalName'][0]);
-			if (isset($localname)) return $localname;
-		}		
-		
-		return NULL;
-	}
-	
-	private function getLocalUser($userid) {
-		if (strpos($userid, '@') === FALSE) return NULL;
-		$decomposed = explode('@', $userid);
-		if(count($decomposed) === 2) {
-			return $decomposed[0];
-		}
-		return NULL;
-	}
-
-	/**
-	 * Apply filter to add or replace attributes.
-	 *
-	 * Add or replace existing attributes with the configured values.
-	 *
-	 * @param array &$request  The current request
-	 */
-	public function process(&$request) {
-		assert(is_array($request));
-		assert(array_key_exists('Attributes', $request));
-
-		$attributes =& $request['Attributes'];
-		
-		$fullname = $this->getFullName($attributes);
-		
-		if(isset($fullname)) $request['Attributes']['smartname-fullname'] = array($fullname);
-		
-	}
 
+class SmartName extends \SimpleSAML\Auth\ProcessingFilter
+{
+    /**
+     * Attributes which should be added/appended.
+     *
+     * Assiciative array of arrays.
+     */
+    private $attributes = [];
+
+
+    private function getFullName($attributes)
+    {
+        if (isset($attributes['displayName'])) {
+            return $attributes['displayName'][0];
+        }
+
+        if (isset($attributes['cn'])) {
+            if (count(explode(' ', $attributes['cn'][0])) > 1) {
+                return $attributes['cn'][0];
+            }
+        }
+
+        if (isset($attributes['sn']) && isset($attributes['givenName'])) {
+            return $attributes['givenName'][0].' '.$attributes['sn'][0];
+        }
+
+        if (isset($attributes['cn'])) {
+            return $attributes['cn'][0];
+        }
+
+        if (isset($attributes['sn'])) {
+            return $attributes['sn'][0];
+        }
+
+        if (isset($attributes['givenName'])) {
+            return $attributes['givenName'][0];
+        }
+
+        if (isset($attributes['eduPersonPrincipalName'])) {
+            $localname = $this->getLocalUser($attributes['eduPersonPrincipalName'][0]);
+            if (isset($localname)) {
+                return $localname;
+            }
+        }
+
+        return null;
+    }
+
+    private function getLocalUser($userid)
+    {
+        if (strpos($userid, '@') === false) {
+            return null;
+        }
+        $decomposed = explode('@', $userid);
+        if (count($decomposed) === 2) {
+            return $decomposed[0];
+        }
+        return null;
+    }
+
+    /**
+     * Apply filter to add or replace attributes.
+     *
+     * Add or replace existing attributes with the configured values.
+     *
+     * @param array &$request  The current request
+     */
+    public function process(&$request)
+    {
+        assert(is_array($request));
+        assert(array_key_exists('Attributes', $request));
+
+        $attributes = &$request['Attributes'];
+
+        $fullname = $this->getFullName($attributes);
+
+        if (isset($fullname)) {
+            $request['Attributes']['smartname-fullname'] = [$fullname];
+        }
+    }
 }
diff --git a/modules/sqlauth/lib/Auth/Source/SQL.php b/modules/sqlauth/lib/Auth/Source/SQL.php
index 67995ab63bdcc5ebe1adf0a8ed6c2440753e7355..b820a6a3e44dc818969bd46d300b059cc777c21e 100644
--- a/modules/sqlauth/lib/Auth/Source/SQL.php
+++ b/modules/sqlauth/lib/Auth/Source/SQL.php
@@ -1,5 +1,7 @@
 <?php
 
+namespace SimpleSAML\Module\sqlauth\Auth\Source;
+
 /**
  * Simple SQL authentication source
  *
@@ -9,7 +11,7 @@
  * @package SimpleSAMLphp
  */
 
-class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
+class SQL extends \SimpleSAML\Module\core\Auth\UserPassBase
 {
     /**
      * The DSN we should connect to.
@@ -53,16 +55,16 @@ class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
         parent::__construct($info, $config);
 
         // Make sure that all required parameters are present.
-        foreach (array('dsn', 'username', 'password', 'query') as $param) {
+        foreach (['dsn', 'username', 'password', 'query'] as $param) {
             if (!array_key_exists($param, $config)) {
-                throw new Exception('Missing required attribute \'' . $param .
-                    '\' for authentication source ' . $this->authId);
+                throw new \Exception('Missing required attribute \''.$param.
+                    '\' for authentication source '.$this->authId);
             }
 
             if (!is_string($config[$param])) {
-                throw new Exception('Expected parameter \'' . $param .
-                    '\' for authentication source ' . $this->authId .
-                    ' to be a string. Instead it was: ' .
+                throw new \Exception('Expected parameter \''.$param.
+                    '\' for authentication source '.$this->authId.
+                    ' to be a string. Instead it was: '.
                     var_export($config[$param], true));
             }
         }
@@ -80,32 +82,32 @@ class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
     /**
      * Create a database connection.
      *
-     * @return PDO  The database connection.
+     * @return \PDO  The database connection.
      */
     private function connect()
     {
         try {
-            $db = new PDO($this->dsn, $this->username, $this->password, $this->options);
-        } catch (PDOException $e) {
-            throw new Exception('sqlauth:' . $this->authId . ': - Failed to connect to \'' .
-                $this->dsn . '\': '. $e->getMessage());
+            $db = new \PDO($this->dsn, $this->username, $this->password, $this->options);
+        } catch (\PDOException $e) {
+            throw new \Exception('sqlauth:'.$this->authId.': - Failed to connect to \''.
+                $this->dsn.'\': '.$e->getMessage());
         }
 
-        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+        $db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
 
         $driver = explode(':', $this->dsn, 2);
         $driver = strtolower($driver[0]);
 
-        /* Driver specific initialization. */
+        // Driver specific initialization
         switch ($driver) {
-        case 'mysql':
-            /* Use UTF-8. */
-            $db->exec("SET NAMES 'utf8mb4'");
-            break;
-        case 'pgsql':
-            /* Use UTF-8. */
-            $db->exec("SET NAMES 'UTF8'");
-            break;
+            case 'mysql':
+                // Use UTF-8
+                $db->exec("SET NAMES 'utf8mb4'");
+                break;
+            case 'pgsql':
+                // Use UTF-8
+                $db->exec("SET NAMES 'UTF8'");
+                break;
         }
 
         return $db;
@@ -117,7 +119,7 @@ class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
      *
      * On a successful login, this function should return the users attributes. On failure,
      * it should throw an exception. If the error was caused by the user entering the wrong
-     * username or password, a SimpleSAML_Error_Error('WRONGUSERPASS') should be thrown.
+     * username or password, a \SimpleSAML\Error\Error('WRONGUSERPASS') should be thrown.
      *
      * Note that both the username and the password are UTF-8 encoded.
      *
@@ -134,55 +136,54 @@ class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
 
         try {
             $sth = $db->prepare($this->query);
-        } catch (PDOException $e) {
-            throw new Exception('sqlauth:' . $this->authId .
-                ': - Failed to prepare query: ' . $e->getMessage());
+        } catch (\PDOException $e) {
+            throw new \Exception('sqlauth:'.$this->authId.
+                ': - Failed to prepare query: '.$e->getMessage());
         }
 
         try {
-            $sth->execute(array('username' => $username, 'password' => $password));
-        } catch (PDOException $e) {
-            throw new Exception('sqlauth:' . $this->authId .
-                ': - Failed to execute query: ' . $e->getMessage());
+            $sth->execute(['username' => $username, 'password' => $password]);
+        } catch (\PDOException $e) {
+            throw new \Exception('sqlauth:'.$this->authId.
+                ': - Failed to execute query: '.$e->getMessage());
         }
 
         try {
-            $data = $sth->fetchAll(PDO::FETCH_ASSOC);
-        } catch (PDOException $e) {
-            throw new Exception('sqlauth:' . $this->authId .
-                ': - Failed to fetch result set: ' . $e->getMessage());
+            $data = $sth->fetchAll(\PDO::FETCH_ASSOC);
+        } catch (\PDOException $e) {
+            throw new \Exception('sqlauth:'.$this->authId.
+                ': - Failed to fetch result set: '.$e->getMessage());
         }
 
-        SimpleSAML\Logger::info('sqlauth:' . $this->authId . ': Got ' . count($data) .
+        \SimpleSAML\Logger::info('sqlauth:'.$this->authId.': Got '.count($data).
             ' rows from database');
 
         if (count($data) === 0) {
-            /* No rows returned - invalid username/password. */
-            SimpleSAML\Logger::error('sqlauth:' . $this->authId .
+            // No rows returned - invalid username/password
+            \SimpleSAML\Logger::error('sqlauth:'.$this->authId.
                 ': No rows in result set. Probably wrong username/password.');
-            throw new SimpleSAML_Error_Error('WRONGUSERPASS');
+            throw new \SimpleSAML\Error\Error('WRONGUSERPASS');
         }
 
         /* Extract attributes. We allow the resultset to consist of multiple rows. Attributes
          * which are present in more than one row will become multivalued. null values and
          * duplicate values will be skipped. All values will be converted to strings.
          */
-        $attributes = array();
+        $attributes = [];
         foreach ($data as $row) {
             foreach ($row as $name => $value) {
-
                 if ($value === null) {
                     continue;
                 }
 
-                $value = (string)$value;
+                $value = (string) $value;
 
                 if (!array_key_exists($name, $attributes)) {
-                    $attributes[$name] = array();
+                    $attributes[$name] = [];
                 }
 
                 if (in_array($value, $attributes[$name], true)) {
-                    /* Value already exists in attribute. */
+                    // Value already exists in attribute
                     continue;
                 }
 
@@ -190,7 +191,7 @@ class sspmod_sqlauth_Auth_Source_SQL extends sspmod_core_Auth_UserPassBase
             }
         }
 
-        SimpleSAML\Logger::info('sqlauth:' . $this->authId . ': Attributes: ' .
+        \SimpleSAML\Logger::info('sqlauth:'.$this->authId.': Attributes: '.
             implode(',', array_keys($attributes)));
 
         return $attributes;
diff --git a/modules/statistics/bin/loganalyzer.php b/modules/statistics/bin/loganalyzer.php
index bf9a1641893d805a55aaacc93cc0e892ccecddd4..85ae093f3e31ab1dfdde61a1ce1ca304c4f17154 100755
--- a/modules/statistics/bin/loganalyzer.php
+++ b/modules/statistics/bin/loganalyzer.php
@@ -5,18 +5,18 @@
 $baseDir = dirname(dirname(dirname(dirname(__FILE__))));
 
 // Add library autoloader.
-require_once($baseDir . '/lib/_autoload.php');
+require_once($baseDir.'/lib/_autoload.php');
 
 // Initialize the configuration.
-$configdir = SimpleSAML\Utils\Config::getConfigDir();
-SimpleSAML_Configuration::setConfigDir($configdir);
-SimpleSAML\Utils\Time::initTimezone();
+$configdir = \SimpleSAML\Utils\Config::getConfigDir();
+\SimpleSAML\Configuration::setConfigDir($configdir);
+\SimpleSAML\Utils\Time::initTimezone();
 
 $progName = array_shift($argv);
 $debug = false;
 $dryrun = false;
 
-foreach($argv as $a) {
+foreach ($argv as $a) {
     if (strlen($a) === 0) {
         continue;
     }
@@ -29,7 +29,7 @@ foreach($argv as $a) {
     }
 
     // Map short options to long options.
-    $shortOptMap = array('-d' => '--debug');
+    $shortOptMap = ['-d' => '--debug'];
     if (array_key_exists($a, $shortOptMap)) {
         $a = $shortOptMap[$a];
     }
@@ -44,13 +44,13 @@ foreach($argv as $a) {
             $dryrun = true;
             break;
         default:
-            echo('Unknown option: ' . $a . "\n");
-            echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
+            echo 'Unknown option: '.$a."\n";
+            echo 'Please run `'.$progName.' --help` for usage information.'."\n";
             exit(1);
     }
 }
 
-$aggregator = new sspmod_statistics_Aggregator(true);
+$aggregator = new \SimpleSAML\Module\statistics\Aggregator(true);
 $aggregator->dumpConfig();
 $aggregator->debugInfo();
 $results = $aggregator->aggregate($debug);
@@ -60,9 +60,9 @@ if (!$dryrun) {
     $aggregator->store($results);
 }
 
-foreach ($results AS $slot => $val) {
-    foreach ($val AS $sp => $no) {
-        echo $sp . " " . count($no) . " - ";
+foreach ($results as $slot => $val) {
+    foreach ($val as $sp => $no) {
+        echo $sp." ".count($no)." - ";
     }
     echo "\n";
 }
@@ -72,7 +72,8 @@ foreach ($results AS $slot => $val) {
  * This function prints the help output.
  */
 
-function printHelp() {
+function printHelp()
+{
     global $progName;
 
     echo <<<END
@@ -84,6 +85,4 @@ Options:
  -d, --debug			Used when configuring the log file syntax. See doc.
  --dry-run			Aggregate but do not store the results.
 END;
-
 }
-
diff --git a/modules/statistics/bin/logcleaner.php b/modules/statistics/bin/logcleaner.php
index b845a139602c756e9b28cde423fcba30057639f5..b160cdab2780d2806831aa044a0e2655e1812bed 100755
--- a/modules/statistics/bin/logcleaner.php
+++ b/modules/statistics/bin/logcleaner.php
@@ -5,11 +5,11 @@
 $baseDir = dirname(dirname(dirname(dirname(__FILE__))));
 
 // Add library autoloader.
-require_once($baseDir . '/lib/_autoload.php');
+require_once($baseDir.'/lib/_autoload.php');
 
 // Initialize the configuration.
-$configdir = SimpleSAML\Utils\Config::getConfigDir();
-SimpleSAML_Configuration::setConfigDir($configdir);
+$configdir = \SimpleSAML\Utils\Config::getConfigDir();
+\SimpleSAML\Configuration::setConfigDir($configdir);
 
 $progName = array_shift($argv);
 $debug = false;
@@ -30,7 +30,7 @@ foreach ($argv as $a) {
     }
 
     // Map short options to long options.
-    $shortOptMap = array('-d' => '--debug');
+    $shortOptMap = ['-d' => '--debug'];
     if (array_key_exists($a, $shortOptMap)) {
         $a = $shortOptMap[$a];
     }
@@ -52,17 +52,17 @@ foreach ($argv as $a) {
             $output = $v;
             break;
         default:
-            echo('Unknown option: ' . $a . "\n");
-            echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
+            echo 'Unknown option: '.$a."\n";
+            echo 'Please run `'.$progName.' --help` for usage information.'."\n";
             exit(1);
     }
 }
 
-$cleaner = new sspmod_statistics_LogCleaner($infile);
+$cleaner = new \SimpleSAML\Module\statistics\LogCleaner($infile);
 $cleaner->dumpConfig();
 $todelete = $cleaner->clean($debug);
 
-echo "Cleaning these trackIDs: " . join(', ', $todelete) . "\n";
+echo "Cleaning these trackIDs: ".join(', ', $todelete)."\n";
 
 if (!$dryrun) {
     $cleaner->store($todelete, $output);
@@ -72,7 +72,8 @@ if (!$dryrun) {
  * This function prints the help output.
  */
 
-function printHelp() {
+function printHelp()
+{
     global $progName;
 
     echo <<<END
@@ -89,4 +90,3 @@ Options:
 
 END;
 }
-
diff --git a/modules/statistics/config-templates/module_statistics.php b/modules/statistics/config-templates/module_statistics.php
index 89c97c4250ceb7baab34ba5711a4fd336b4a9a78..9e186dc2908f65297a74825e8c03e830fee1fe84 100644
--- a/modules/statistics/config-templates/module_statistics.php
+++ b/modules/statistics/config-templates/module_statistics.php
@@ -1,10 +1,9 @@
 <?php
-/* 
+/*
  * The configuration of SimpleSAMLphp statistics package
  */
 
-$config = array (
-
+$config = [
     // Authentication & authorization for statistics
 
     // Whether the statistics require authentication before use.
@@ -24,165 +23,168 @@ $config = array (
 
     'statdir' => '/tmp/stats/',
     'inputfile' => '/var/log/simplesamlphp.stat',
-    'offset' => 60*60*2 + 60*60*24*3, // Two hours offset to match epoch and norwegian winter time.
-	
+    'offset' => 60 * 60 * 2 + 60 * 60 * 24 * 3, // Two hours offset to match epoch and norwegian winter time.
+
     'datestart' => 1,
     'datelength' => 15,
     'offsetspan' => 21,
-	
+
     // Dimensions on graph from Google Charts in pixels...
     'dimension.x' => 800,
     'dimension.y' => 350,
-	
+
     /*
      * Do you want to generate statistics using the cron module? If so, specify which cron tag to use.
      * Examples: daily, weekly
-     * To not run statistics in cron, set value to 
+     * To not run statistics in cron, set value to
      *     'cron_tag' => null,
      */
     'cron_tag' => 'daily',
 
     /*
-     * Set max running time for this script. This is also controlle by max_execution_time in php.ini
-     * and is defalut set to 30 sec. Your web server can have other timeout configurations that may
+     * Set max running time for this script. This is also controlled by max_execution_time in php.ini
+     * and is set to 30 sec by default. Your web server can have other timeout configurations that may
      * also interrupt PHP execution. Apache has a Timeout directive and IIS has a
      * CGI timeout function. Both default to 300 seconds.
      */
     'time_limit' => 300,
-	
-    'timeres' => array(
-        'day' => array(
+
+    'timeres' => [
+        'day' => [
             'name' => 'Day',
-            'slot'              => 60*15,            // Slots of 15 minutes
-            'fileslot'	        => 60*60*24,         // One day (24 hours) file slots
-            'axislabelint'      => 6*4,              // Number of slots per label. 4 per hour *6 = 6 hours 
-            'dateformat-period'	=> 'j. M',           //  4. Mars
-            'dateformat-intra'	=> 'j. M H:i',       //  4. Mars 12:30	
-        ),
-        'week' => array(
+            'slot'              => 60 * 15, // Slots of 15 minutes
+            'fileslot'          => 60 * 60 * 24, // One day (24 hours) file slots
+            'axislabelint'      => 6 * 4, // Number of slots per label. 4 per hour *6 = 6 hours
+            'dateformat-period' => 'j. M', //  4. Mars
+            'dateformat-intra'  => 'j. M H:i', //  4. Mars 12:30
+        ],
+        'week' => [
             'name' => 'Week',
-            'slot'		=> 60*60,            // Slots of one hour
-            'fileslot'	        => 60*60*24*7,       // 7 days of data in each file
-            'axislabelint'      => 24,               // Number of slots per label. 24 is one each day
-            'dateformat-period'	=> 'j. M',           //  4. Mars
-            'dateformat-intra'	=> 'j. M H:i',       //  4. Mars 12:30
-        ),
-        'month' => array(
+            'slot'              => 60 * 60, // Slots of one hour
+            'fileslot'          => 60 * 60 * 24 * 7, // 7 days of data in each file
+            'axislabelint'      => 24, // Number of slots per label. 24 is one each day
+            'dateformat-period' => 'j. M', //  4. Mars
+            'dateformat-intra'  => 'j. M H:i', //  4. Mars 12:30
+        ],
+        'month' => [
             'name' => 'Month',
-            'slot'              => 60*60*24,         // Slots of one day
-            'fileslot'          => 60*60*24*30,      // 30 days of data in each file
-            'axislabelint'      => 7,                // Number of slots per label. 7 days => 1 week
-            'dateformat-period'	=> 'j. M Y H:i',     //  4. Mars 12:30
-            'dateformat-intra'	=> 'j. M',           //  4. Mars
-        ),
-        'monthaligned' => array(
+            'slot'              => 60 * 60 * 24, // Slots of one day
+            'fileslot'          => 60 * 60 * 24 * 30, // 30 days of data in each file
+            'axislabelint'      => 7, // Number of slots per label. 7 days => 1 week
+            'dateformat-period' => 'j. M Y H:i', //  4. Mars 12:30
+            'dateformat-intra'  => 'j. M', //  4. Mars
+        ],
+        'monthaligned' => [
             'name'              => 'AlignedMonth',
-            'slot'              => 60*60*24,         // Slots of one day
-            'fileslot'          => null,             // 30 days of data in each file
+            'slot'              => 60 * 60 * 24, // Slots of one day
+            'fileslot'          => null, // 30 days of data in each file
             'customDateHandler' => 'month',
-            'axislabelint'      => 7,                // Number of slots per label. 7 days => 1 week
-            'dateformat-period'	=> 'j. M Y H:i',     //  4. Mars 12:30
-            'dateformat-intra'	=> 'j. M',           //  4. Mars
-        ),
-        'days180' => array(
+            'axislabelint'      => 7, // Number of slots per label. 7 days => 1 week
+            'dateformat-period' => 'j. M Y H:i', //  4. Mars 12:30
+            'dateformat-intra'  => 'j. M', //  4. Mars
+        ],
+        'days180' => [
             'name'              => '180 days',
-            'slot'              => 60*60*24,         // Slots of 1 day (24 hours)
-            'fileslot'          => 60*60*24*180,     // 80 days of data in each file
-            'axislabelint'      => 30,               // Number of slots per label. 7 days => 1 week
-            'dateformat-period' => 'j. M',           //  4. Mars
-            'dateformat-intra'  => 'j. M',           //  4. Mars
-        ),
-    ),
+            'slot'              => 60 * 60 * 24, // Slots of 1 day (24 hours)
+            'fileslot'          => 60 * 60 * 24 * 180, // 80 days of data in each file
+            'axislabelint'      => 30, // Number of slots per label. 7 days => 1 week
+            'dateformat-period' => 'j. M', //  4. Mars
+            'dateformat-intra'  => 'j. M', //  4. Mars
+        ],
+    ],
 
-    'statrules' => array(
-        'sloratio' => array(
+    'statrules' => [
+        'sloratio' => [
             'name'         => 'SLO to SSO ratio',
-            'descr'        => 'Comparison of the number of Single Log-Out compared to Single Sign-On. Graph shows how many logouts where initiated for each Single Sign-On.',
+            'descr'        => 'Comparison of the number of Single Log-Out compared to Single Sign-On.'.
+                ' Graph shows how many logouts where initiated for each Single Sign-On.',
             'type'         => 'calculated',
             'presenter'    => 'statistics:Ratio',
-            'ref'          => array('slo', 'sso'),
-            'fieldPresentation' => array(
+            'ref'          => ['slo', 'sso'],
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'ssomulti' => array(
+            ],
+        ],
+        'ssomulti' => [
             'name'         => 'Requests per session',
-            'descr'        => 'Number of SSO request pairs exchanged between IdP and SP within the same IdP session. A high number indicates that the session at the SP is timing out faster than at the IdP.',
+            'descr'        => 'Number of SSO request pairs exchanged between IdP and SP within the same IdP session.'.
+                ' A high number indicates that the session at the SP is timing out faster than at the IdP.',
             'type'         => 'calculated',
             'presenter'    => 'statistics:Ratio',
-            'ref'          => array('sso', 'ssofirst'),
-            'fieldPresentation' => array(
+            'ref'          => ['sso', 'ssofirst'],
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'sso' => array(
+            ],
+        ],
+        'sso' => [
             'name'         => 'SSO to service',
             'descr'        => 'The number of logins at a Service Provider.',
             'action'       => 'saml20-idp-SSO',
-            'col'          => 6,                     // Service Provider EntityID
-            'fieldPresentation' => array(
+            'col'          => 6, // Service Provider EntityID
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'ssofirst' => array(
+            ],
+        ],
+        'ssofirst' => [
             'name'         => 'SSO-first to service',
             'descr'        => 'The number of logins at a Service Provider.',
             'action'       => 'saml20-idp-SSO-first',
-            'col'          => 6,                     // Service Provider EntityID
-            'fieldPresentation' => array(
+            'col'          => 6, // Service Provider EntityID
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'slo' => array(
+            ],
+        ],
+        'slo' => [
             'name'         => 'SLO initiated from service',
             'descr'        => 'The number of initated Sinlge Logout from each of the service providers.',
             'action'       => 'saml20-idp-SLO',
-            'col'          => 7,                     // Service Provider EntityID that initiated the logout.
-            'fieldPresentation' => array(
+            'col'          => 7, // Service Provider EntityID that initiated the logout.
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'consent' => array(
+            ],
+        ],
+        'consent' => [
             'name'         => 'Consent',
-            'descr'        => 'Consent statistics. Everytime a user logs in to a service an entry is logged for one of three states: consent was found, consent was not found or consent storage was not available.',
+            'descr'        => 'Consent statistics. Everytime a user logs in to a service an entry is logged for'.
+                ' one of three states: consent was found, consent was not found or consent storage was not available.',
             'action'       => 'consent',
             'col'          => 6,
-            'fieldPresentation' => array(
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'consentresponse' => array(
+            ],
+        ],
+        'consentresponse' => [
             'name'         => 'Consent response',
-            'descr'        => 'Consent response statistics. Everytime a user accepts consent, it is logged whether the user selected to remember the consent to next time.',
+            'descr'        => 'Consent response statistics. Everytime a user accepts consent,'.
+                ' it is logged whether the user selected to remember the consent to next time.',
             'action'       => 'consentResponse',
             'col'          => 6,
-            'fieldPresentation' => array(
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-        'slopages' => array(
+            ],
+        ],
+        'slopages' => [
             'name'         => 'SLO iframe pages',
             'descr'        => 'The varioust IFrame SLO pages a user visits',
             'action'       => 'slo-iframe',
-            'col'          => 6,                     // Page the user visits.
-        ),
-        'slofail' => array(
+            'col'          => 6, // Page the user visits.
+        ],
+        'slofail' => [
             'name'         => 'Failed iframe IdP-init SLOs',
             'descr'        => 'The number of logout failures from various SPs',
             'action'       => 'slo-iframe-fail',
-            'col'          => 6,                     // Service Provider EntityID that wasn't logged out.
-            'fieldPresentation' => array(
+            'col'          => 6, // Service Provider EntityID that wasn't logged out.
+            'fieldPresentation' => [
                 'class'    => 'statistics:Entity',
                 'config'   => 'saml20-sp-remote',
-            ),
-        ),
-    ),
-
-);
+            ],
+        ],
+    ],
+];
diff --git a/modules/statistics/hooks/hook_cron.php b/modules/statistics/hooks/hook_cron.php
index ccd95e4603b9f11e55bbafca1d11f7cbdbd8c290..a3ee4952cc347d567d4d044f4bbd83b05b7a7b5d 100644
--- a/modules/statistics/hooks/hook_cron.php
+++ b/modules/statistics/hooks/hook_cron.php
@@ -1,40 +1,42 @@
 <?php
+
 /**
  * Hook to run a cron job.
  *
  * @param array &$croninfo  Output
  */
+
 function statistics_hook_cron(&$croninfo)
 {
     assert(is_array($croninfo));
     assert(array_key_exists('summary', $croninfo));
     assert(array_key_exists('tag', $croninfo));
 
-    $statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
-	
+    $statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
+
     if (is_null($statconfig->getValue('cron_tag', null))) {
         return;
     }
     if ($statconfig->getValue('cron_tag', null) !== $croninfo['tag']) {
         return;
     }
-	
+
     $maxtime = $statconfig->getInteger('time_limit', null);
     if ($maxtime) {
         set_time_limit($maxtime);
     }
-	
+
     try {
-        $aggregator = new sspmod_statistics_Aggregator();
+        $aggregator = new \SimpleSAML\Module\statistics\Aggregator();
         $results = $aggregator->aggregate();
         if (empty($results)) {
-            SimpleSAML\Logger::notice('Output from statistics aggregator was empty.');
+            \SimpleSAML\Logger::notice('Output from statistics aggregator was empty.');
         } else {
             $aggregator->store($results);
         }
-    } catch (Exception $e) {
-        $message = 'Loganalyzer threw exception: ' . $e->getMessage();
-        SimpleSAML\Logger::warning($message);
+    } catch (\Exception $e) {
+        $message = 'Loganalyzer threw exception: '.$e->getMessage();
+        \SimpleSAML\Logger::warning($message);
         $croninfo['summary'][] = $message;
     }
 }
diff --git a/modules/statistics/hooks/hook_frontpage.php b/modules/statistics/hooks/hook_frontpage.php
index 03a97aa52bdb5013f3fb2f2faa785940c355d010..462a300bfb265e8c0a97036c4df9084743a8e4cf 100644
--- a/modules/statistics/hooks/hook_frontpage.php
+++ b/modules/statistics/hooks/hook_frontpage.php
@@ -9,14 +9,13 @@ function statistics_hook_frontpage(&$links)
     assert(is_array($links));
     assert(array_key_exists('links', $links));
 
-    $links['config']['statistics'] = array(
+    $links['config']['statistics'] = [
         'href' => SimpleSAML\Module::getModuleURL('statistics/showstats.php'),
-        'text' => array('en' => 'Show statistics', 'no' => 'Vis statistikk'),
-        'shorttext' => array('en' => 'Statistics', 'no' => 'Statistikk'),
-    );
-    $links['config']['statisticsmeta'] = array(
+        'text' => '{core:frontpage:link_statistics}',
+    ];
+    $links['config']['statisticsmeta'] = [
         'href' => SimpleSAML\Module::getModuleURL('statistics/statmeta.php'),
-        'text' => array('en' => 'Show statistics metadata', 'no' => 'Vis statistikk metadata'),
-        'shorttext' => array('en' => 'Statistics metadata', 'no' => 'Statistikk metadata'),
-    );
+        'text' => '{core:frontpage:link_statistics_metadata}',
+        'shorttext' => ['en' => 'Statistics metadata', 'no' => 'Statistikk metadata'],
+    ];
 }
diff --git a/modules/statistics/hooks/hook_sanitycheck.php b/modules/statistics/hooks/hook_sanitycheck.php
index 9936379c54a3bb88349a3b3e19ba34cde431150c..879ee3ee784c292f68cd979d66420799b6251085 100644
--- a/modules/statistics/hooks/hook_sanitycheck.php
+++ b/modules/statistics/hooks/hook_sanitycheck.php
@@ -1,6 +1,6 @@
 <?php
 /**
- * Hook to do santity checks
+ * Hook to do sanity checks
  *
  * @param array &$hookinfo  hookinfo
  */
@@ -11,28 +11,29 @@ function statistics_hook_sanitycheck(&$hookinfo)
     assert(array_key_exists('info', $hookinfo));
 
     try {
-        $statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
-    } catch(Exception $e) {
-        $hookinfo['errors'][] = '[statistics] Could not get configuration: ' . $e->getMessage(); return;
+        $statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
+    } catch (Exception $e) {
+        $hookinfo['errors'][] = '[statistics] Could not get configuration: '.$e->getMessage();
+        return;
     }
 
     $statdir = $statconfig->getValue('statdir');
     $inputfile = $statconfig->getValue('inputfile');
 
     if (file_exists($statdir)) {
-        $hookinfo['info'][] = '[statistics] Statistics dir [' . $statdir . '] exists';
+        $hookinfo['info'][] = '[statistics] Statistics dir ['.$statdir.'] exists';
         if (is_writable($statdir)) {
-            $hookinfo['info'][] = '[statistics] Statistics dir [' . $statdir . '] is writable';
+            $hookinfo['info'][] = '[statistics] Statistics dir ['.$statdir.'] is writable';
         } else {
-            $hookinfo['errors'][] = '[statistics] Statistics dir [' . $statdir . '] is not writable';
+            $hookinfo['errors'][] = '[statistics] Statistics dir ['.$statdir.'] is not writable';
         }
     } else {
-        $hookinfo['errors'][] = '[statistics] Statistics dir [' . $statdir . '] does not exists';
+        $hookinfo['errors'][] = '[statistics] Statistics dir ['.$statdir.'] does not exists';
     }
 
     if (file_exists($inputfile)) {
-        $hookinfo['info'][] = '[statistics] Input file [' . $inputfile . '] exists';
+        $hookinfo['info'][] = '[statistics] Input file ['.$inputfile.'] exists';
     } else {
-        $hookinfo['errors'][] = '[statistics] Input file [' . $inputfile . '] does not exists';
+        $hookinfo['errors'][] = '[statistics] Input file ['.$inputfile.'] does not exists';
     }
 }
diff --git a/modules/statistics/lib/AccessCheck.php b/modules/statistics/lib/AccessCheck.php
index f742b51d1f47d799091744deba096d26af79a8f1..750a5d0526e0aa3aa494e6f0ffdba9dc70dbef6c 100644
--- a/modules/statistics/lib/AccessCheck.php
+++ b/modules/statistics/lib/AccessCheck.php
@@ -1,18 +1,21 @@
 <?php
 
+namespace SimpleSAML\Module\statistics;
+
 /**
  * Class implementing the access checker function for the statistics module.
  *
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_AccessCheck
+
+class AccessCheck
 {
     /**
      * Check that the user has access to the statistics.
      *
      * If the user doesn't have access, send the user to the login page.
      */
-    public static function checkAccess(SimpleSAML_Configuration $statconfig)
+    public static function checkAccess(\SimpleSAML\Configuration $statconfig)
     {
         $protected = $statconfig->getBoolean('protected', false);
         $authsource = $statconfig->getString('auth', null);
@@ -21,22 +24,22 @@ class sspmod_statistics_AccessCheck
 
         $acl = $statconfig->getValue('acl', null);
         if ($acl !== null && !is_string($acl) && !is_array($acl)) {
-            throw new SimpleSAML_Error_Exception('Invalid value for \'acl\'-option. Should be an array or a string.');
+            throw new \SimpleSAML\Error\Exception('Invalid value for \'acl\'-option. Should be an array or a string.');
         }
 
         if (!$protected) {
             return;
         }
 
-        if (SimpleSAML\Utils\Auth::isAdmin()) {
+        if (\SimpleSAML\Utils\Auth::isAdmin()) {
             // User logged in as admin. OK.
-            SimpleSAML\Logger::debug('Statistics auth - logged in as admin, access granted');
+            \SimpleSAML\Logger::debug('Statistics auth - logged in as admin, access granted');
             return;
         }
 
         if (!isset($authsource)) {
             // If authsource is not defined, init admin login.
-            SimpleSAML\Utils\Auth::requireAdmin();
+            \SimpleSAML\Utils\Auth::requireAdmin();
         }
 
         // We are using an authsource for login.
@@ -45,7 +48,7 @@ class sspmod_statistics_AccessCheck
         $as->requireAuth();
 
         // User logged in with auth source.
-        SimpleSAML\Logger::debug('Statistics auth - valid login with auth source [' . $authsource . ']');
+        \SimpleSAML\Logger::debug('Statistics auth - valid login with auth source ['.$authsource.']');
 
         // Retrieving attributes
         $attributes = $as->getAttributes();
@@ -53,29 +56,33 @@ class sspmod_statistics_AccessCheck
         if (!empty($allowedusers)) {
             // Check if userid exists
             if (!isset($attributes[$useridattr][0])) {
-                throw new Exception('User ID is missing');
+                throw new \Exception('User ID is missing');
             }
 
             // Check if userid is allowed access..
             if (in_array($attributes[$useridattr][0], $allowedusers, true)) {
-                SimpleSAML\Logger::debug('Statistics auth - User granted access by user ID [' . $attributes[$useridattr][0] . ']');
+                \SimpleSAML\Logger::debug(
+                    'Statistics auth - User granted access by user ID ['.$attributes[$useridattr][0].']'
+                );
                 return;
             }
-            SimpleSAML\Logger::debug('Statistics auth - User denied access by user ID [' . $attributes[$useridattr][0] . ']');
+            \SimpleSAML\Logger::debug(
+                'Statistics auth - User denied access by user ID ['.$attributes[$useridattr][0].']'
+            );
         } else {
-            SimpleSAML\Logger::debug('Statistics auth - no allowedUsers list.');
+            \SimpleSAML\Logger::debug('Statistics auth - no allowedUsers list.');
         }
 
         if (!is_null($acl)) {
-            $acl = new sspmod_core_ACL($acl);
+            $acl = new \SimpleSAML\Module\core\ACL($acl);
             if ($acl->allows($attributes)) {
-                SimpleSAML\Logger::debug('Statistics auth - allowed access by ACL.');
+                \SimpleSAML\Logger::debug('Statistics auth - allowed access by ACL.');
                 return;
             }
-            SimpleSAML\Logger::debug('Statistics auth - denied access by ACL.');
+            \SimpleSAML\Logger::debug('Statistics auth - denied access by ACL.');
         } else {
-            SimpleSAML\Logger::debug('Statistics auth - no ACL configured.');
+            \SimpleSAML\Logger::debug('Statistics auth - no ACL configured.');
         }
-        throw new SimpleSAML_Error_Exception('Access denied to the current user.');
+        throw new \SimpleSAML\Error\Exception('Access denied to the current user.');
     }
 }
diff --git a/modules/statistics/lib/Aggregator.php b/modules/statistics/lib/Aggregator.php
index d943c7fd278e6b76cc9fcd71cde60d8e0f9c9233..966012d6399329c6b5f250a3d68e53b9f22197e8 100644
--- a/modules/statistics/lib/Aggregator.php
+++ b/modules/statistics/lib/Aggregator.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_Aggregator
+
+class Aggregator
 {
     private $statconfig;
     private $statdir;
@@ -21,7 +25,7 @@ class sspmod_statistics_Aggregator
     public function __construct($fromcmdline = false)
     {
         $this->fromcmdline = $fromcmdline;
-        $this->statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
+        $this->statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
 
         $this->statdir = $this->statconfig->getValue('statdir');
         $this->inputfile = $this->statconfig->getValue('inputfile');
@@ -35,19 +39,19 @@ class sspmod_statistics_Aggregator
 
     public function dumpConfig()
     {
-        echo 'Statistics directory   : ' . $this->statdir . "\n";
-        echo 'Input file             : ' . $this->inputfile . "\n";
-        echo 'Offset                 : ' . $this->offset . "\n";
+        echo 'Statistics directory   : '.$this->statdir."\n";
+        echo 'Input file             : '.$this->inputfile."\n";
+        echo 'Offset                 : '.$this->offset."\n";
     }
 
     public function debugInfo()
     {
-        echo 'Memory usage           : ' . number_format(memory_get_usage() / (1024*1024), 2) . " MB\n";
+        echo 'Memory usage           : '.number_format(memory_get_usage() / 1048576, 2)." MB\n"; // 1024*1024=1048576
     }
 
     public function loadMetadata()
     {
-        $filename = $this->statdir . '/.stat.metadata';
+        $filename = $this->statdir.'/.stat.metadata';
         $metadata = null;
         if (file_exists($filename)) {
             $metadata = unserialize(file_get_contents($filename));
@@ -66,34 +70,37 @@ class sspmod_statistics_Aggregator
         $this->metadata['memory'] = memory_get_usage();
         $this->metadata['lastrun'] = time();
 
-        $filename = $this->statdir . '/.stat.metadata';
+        $filename = $this->statdir.'/.stat.metadata';
         file_put_contents($filename, serialize($this->metadata), LOCK_EX);
     }
 
-    public function aggregate($debug = false) {
+    public function aggregate($debug = false)
+    {
         $this->loadMetadata();
 
         if (!is_dir($this->statdir)) {
-            throw new Exception('Statistics module: output dir do not exists [' . $this->statdir . ']');
+            throw new \Exception('Statistics module: output dir do not exists ['.$this->statdir.']');
         }
 
         if (!file_exists($this->inputfile)) {
-            throw new Exception('Statistics module: input file do not exists [' . $this->inputfile . ']');
+            throw new \Exception('Statistics module: input file do not exists ['.$this->inputfile.']');
         }
 
         $file = fopen($this->inputfile, 'r');
 
         if ($file === false) {
-            throw new Exception('Statistics module: unable to open file [' . $this->inputfile . ']');
+            throw new \Exception('Statistics module: unable to open file ['.$this->inputfile.']');
         }
 
-        $logparser = new sspmod_statistics_LogParser(
-            $this->statconfig->getValue('datestart', 0), $this->statconfig->getValue('datelength', 15), $this->statconfig->getValue('offsetspan', 44)
-        );
-        $datehandler = array(
-            'default' => new sspmod_statistics_DateHandler($this->offset),
-            'month' => new  sspmod_statistics_DateHandlerMonth($this->offset),
+        $logparser = new LogParser(
+            $this->statconfig->getValue('datestart', 0),
+            $this->statconfig->getValue('datelength', 15),
+            $this->statconfig->getValue('offsetspan', 44)
         );
+        $datehandler = [
+            'default' => new DateHandler($this->offset),
+            'month' => new  DateHandlerMonth($this->offset),
+        ];
 
         $notBefore = 0;
         $lastRead = 0;
@@ -104,9 +111,9 @@ class sspmod_statistics_Aggregator
             $lastlinehash = $this->metadata['lastlinehash'];
         }
 
-        $lastlogline = 'sdfsdf'; 
+        $lastlogline = 'sdfsdf';
         $lastlineflip = false;
-        $results = array();
+        $results = [];
 
         $i = 0;
         // Parse through log file, line by line
@@ -127,13 +134,14 @@ class sspmod_statistics_Aggregator
             $action = trim($content[5]);
 
             if ($this->fromcmdline && ($i % 10000) == 0) {
-                echo("Read line " . $i . "\n");
+                echo "Read line ".$i."\n";
             }
 
             if ($debug) {
-                echo("----------------------------------------\n");
-                echo('Log line: ' . $logline . "\n");
-                echo('Date parse [' . substr($logline, 0, $this->statconfig->getValue('datelength', 15)) . '] to [' . date(DATE_RFC822, $epoch) . ']' . "\n");
+                echo "----------------------------------------\n";
+                echo 'Log line: '.$logline."\n";
+                echo 'Date parse ['.substr($logline, 0, $this->statconfig->getValue('datelength', 15)).
+                    '] to ['.date(DATE_RFC822, $epoch).']'."\n";
                 echo htmlentities(print_r($content, true));
                 if ($i >= 13) {
                     exit;
@@ -146,7 +154,7 @@ class sspmod_statistics_Aggregator
 
             if ($epoch === $notBefore) {
                 if (!$lastlineflip) {
-                    if (sha1($logline) === $lastlinehash) { 
+                    if (sha1($logline) === $lastlinehash) {
                         $lastlineflip = true;
                     }
                     continue;
@@ -169,7 +177,7 @@ class sspmod_statistics_Aggregator
                     continue;
                 }
 
-                foreach ($this->timeres as $tres => $tresconfig ) {
+                foreach ($this->timeres as $tres => $tresconfig) {
                     $dh = 'default';
                     if (isset($tresconfig['customDateHandler'])) {
                         $dh = $tresconfig['customDateHandler'];
@@ -207,7 +215,7 @@ class sspmod_statistics_Aggregator
         if (is_int($colrule)) {
             return trim($content[$colrule]);
         } elseif (is_array($colrule)) {
-            $difcols = array();
+            $difcols = [];
             foreach ($colrule as $cr) {
                 $difcols[] = trim($content[$cr]);
             }
@@ -219,11 +227,11 @@ class sspmod_statistics_Aggregator
 
     private function cummulateData($previous, $newdata)
     {
-        $dataset = array();
+        $dataset = [];
         foreach (func_get_args() as $item) {
             foreach ($item as $slot => $dataarray) {
                 if (!array_key_exists($slot, $dataset)) {
-                    $dataset[$slot] = array();
+                    $dataset[$slot] = [];
                 }
                 foreach ($dataarray as $key => $data) {
                     if (!array_key_exists($key, $dataset[$slot])) {
@@ -238,10 +246,10 @@ class sspmod_statistics_Aggregator
 
     public function store($results)
     {
-        $datehandler = array(
-            'default' => new sspmod_statistics_DateHandler($this->offset),
-            'month' => new  sspmod_statistics_DateHandlerMonth($this->offset),
-        );
+        $datehandler = [
+            'default' => new DateHandler($this->offset),
+            'month' => new DateHandlerMonth($this->offset),
+        ];
 
         // Iterate the first level of results, which is per rule, as defined in the config.
         foreach ($results as $rulename => $timeresdata) {
@@ -264,33 +272,33 @@ class sspmod_statistics_Aggregator
                     $maxslot = $slotlist[count($slotlist) - 1];
 
                     // Get start and end slot number within the file, based on the fileslot.
-                    $start = (int)$datehandler['default']->toSlot(
-                        $datehandler[$dh]->fromSlot($fileno, $this->timeres[$tres]['fileslot']), 
+                    $start = (int) $datehandler['default']->toSlot(
+                        $datehandler[$dh]->fromSlot($fileno, $this->timeres[$tres]['fileslot']),
                         $this->timeres[$tres]['slot']
                     );
-                    $end = (int)$datehandler['default']->toSlot(
-                        $datehandler[$dh]->fromSlot($fileno+1, $this->timeres[$tres]['fileslot']), 
+                    $end = (int) $datehandler['default']->toSlot(
+                        $datehandler[$dh]->fromSlot($fileno + 1, $this->timeres[$tres]['fileslot']),
                         $this->timeres[$tres]['slot']
                     );
 
                     // Fill in missing entries and sort file results
-                    $filledresult = array();
+                    $filledresult = [];
                     for ($slot = $start; $slot < $end; $slot++) {
-                        if (array_key_exists($slot,  $fileres)) {
+                        if (array_key_exists($slot, $fileres)) {
                             $filledresult[$slot] = $fileres[$slot];
                         } else {
                             if ($lastfile == $fileno && $slot > $maxslot) {
-                                $filledresult[$slot] = array('_' => null);
+                                $filledresult[$slot] = ['_' => null];
                             } else {
-                                $filledresult[$slot] = array('_' => 0);
+                                $filledresult[$slot] = ['_' => 0];
                             }
                         }
                     }
 
-                    $filename = $this->statdir . '/' . $rulename . '-' . $tres . '-' . $fileno . '.stat';
+                    $filename = $this->statdir.'/'.$rulename.'-'.$tres.'-'.$fileno.'.stat';
                     if (file_exists($filename)) {
                         $previousData = unserialize(file_get_contents($filename));
-                        $filledresult = $this->cummulateData($previousData, $filledresult);	
+                        $filledresult = $this->cummulateData($previousData, $filledresult);
                     }
 
                     // store file
diff --git a/modules/statistics/lib/DateHandler.php b/modules/statistics/lib/DateHandler.php
index 13ed07c7f5dd5b8d25d40d1fca87ad4da784100a..ae9807df9ea6907992b4e25c7aad2921df49fcd2 100644
--- a/modules/statistics/lib/DateHandler.php
+++ b/modules/statistics/lib/DateHandler.php
@@ -1,16 +1,20 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_DateHandler
+
+class DateHandler
 {
     protected $offset;
 
     /**
      * Constructor
      *
-     * @param array $offset 	Date offset
+     * @param array $offset Date offset
      */
     public function __construct($offset)
     {
@@ -28,14 +32,14 @@ class sspmod_statistics_DateHandler
     public function toSlot($epoch, $slotsize)
     {
         $dst = $this->getDST($epoch);
-        return floor( ($epoch + $this->offset + $dst) / $slotsize);
+        return floor(($epoch + $this->offset + $dst) / $slotsize);
     }
 
     public function fromSlot($slot, $slotsize)
     {
-        $temp = $slot*$slotsize - $this->offset;
+        $temp = $slot * $slotsize - $this->offset;
         $dst = $this->getDST($temp);
-        return $slot*$slotsize - $this->offset - $dst;
+        return $slot * $slotsize - $this->offset - $dst;
     }
 
     public function prettyDateEpoch($epoch, $dateformat)
diff --git a/modules/statistics/lib/DateHandlerMonth.php b/modules/statistics/lib/DateHandlerMonth.php
index cdbe93c35b6cb37a3e2b84d134e23ee7afda1d0f..061af6e62c8029a3eeea32de3a221c4b811f496b 100644
--- a/modules/statistics/lib/DateHandlerMonth.php
+++ b/modules/statistics/lib/DateHandlerMonth.php
@@ -1,14 +1,18 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_DateHandlerMonth extends sspmod_statistics_DateHandler
+
+class DateHandlerMonth extends DateHandler
 {
     /**
      * Constructor
      *
-     * @param integer $offset 	Date offset
+     * @param integer $offset Date offset
      */
     public function __construct($offset)
     {
@@ -34,6 +38,6 @@ class sspmod_statistics_DateHandlerMonth extends sspmod_statistics_DateHandler
     {
         $month = ($from % 12) + 1;
         $year = 2000 + floor($from / 12);
-        return $year . '-' . $month;
+        return $year.'-'.$month;
     }
 }
diff --git a/modules/statistics/lib/Graph/GoogleCharts.php b/modules/statistics/lib/Graph/GoogleCharts.php
index 613dddfc5aecf97bc5e60b8218beb00d5407628e..129639de50d103e4002b0504e7e3c3a117242141 100644
--- a/modules/statistics/lib/Graph/GoogleCharts.php
+++ b/modules/statistics/lib/Graph/GoogleCharts.php
@@ -1,12 +1,16 @@
 <?php
+
+namespace SimpleSAML\Module\statistics\Graph;
+
 /*
- * sspmod_statistics_Graph_GoogleCharts will help you to create a Google Chart
- * using the Google Charts API. 
+ * \SimpleSAML\Module\statistics\Graph\GoogleCharts will help you to create a Google Chart
+ * using the Google Charts API.
  *
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_Graph_GoogleCharts
+
+class GoogleCharts
 {
     /**
      * @var integer
@@ -40,11 +44,11 @@ class sspmod_statistics_Graph_GoogleCharts
     // t:10.0,58.0,95.0
     private function encodedata($datasets)
     {
-        $setstr = array();
+        $setstr = [];
         foreach ($datasets as $dataset) {
             $setstr[] = self::extEncode($dataset);
         }
-        return 'e:' . join(',', $setstr);
+        return 'e:'.join(',', $setstr);
     }
 
     public static function extEncode($values) // $max = 4095, $min = 0
@@ -59,68 +63,68 @@ class sspmod_statistics_Graph_GoogleCharts
                 $first = substr($extended_table, intval(($delta * $v / 100) / $size), 1);
                 $second = substr($extended_table, intval(($delta * $v / 100) % $size), 1);
                 $chardata .= "$first$second";
-            } else { 
-                $chardata .= '__'; // Value out of max range; 
-            } 
+            } else {
+                $chardata .= '__'; // Value out of max range;
+            }
         }
-        return($chardata); 
+        return $chardata;
     }
 
     /**
      * Generate a Google Charts URL which points to a generated image.
-     * More documentation on Google Charts here: 
+     * More documentation on Google Charts here:
      *   http://code.google.com/apis/chart/
      *
-     * @param $axis        Axis
-     * @param $axpis       Axis positions
-     * @param $datasets    Datasets values
-     * @param $max         Max value. Will be the topmost value on the Y-axis.
+     * @param string $axis        Axis
+     * @param string $axpis       Axis positions
+     * @param array $datasets    Datasets values
+     * @param integer $max         Max value. Will be the topmost value on the Y-axis.
      */
     public function show($axis, $axispos, $datasets, $maxes)
     {
-        $labeld = '&chxt=x,y' . '&chxr=0,0,1|1,0,' . $maxes[0];
+        $labeld = '&chxt=x,y'.'&chxr=0,0,1|1,0,'.$maxes[0];
         if (count($datasets) > 1) {
             if (count($datasets) !== count($maxes)) {
-                throw new Exception('Incorrect number of max calculations for graph plotting.');
+                throw new \Exception('Incorrect number of max calculations for graph plotting.');
             }
-            $labeld = '&chxt=x,y,r' . '&chxr=0,0,1|1,0,' . $maxes[0] . '|2,0,' . $maxes[1];
+            $labeld = '&chxt=x,y,r'.'&chxr=0,0,1|1,0,'.$maxes[0].'|2,0,'.$maxes[1];
         }
 
-        $url = 'https://chart.apis.google.com/chart?' .
+        $url = 'https://chart.apis.google.com/chart?'.
             // Dimension of graph. Default is 800x350
-            'chs=' . $this->x . 'x' . $this->y . 
+            'chs='.$this->x.'x'.$this->y.
 
             // Dateset values
-            '&chd=' . $this->encodedata($datasets) .
+            '&chd='.$this->encodedata($datasets).
 
             // Fill area...
-            '&chco=ff5c00,cca600' . 
-            '&chls=1,1,0|1,6,3' .
+            '&chco=ff5c00,cca600'.
+            '&chls=1,1,0|1,6,3'.
 
             // chart type is linechart
-            '&cht=lc' .
-            $labeld .
-            '&chxl=0:|' . $this->encodeaxis($axis) . # . $'|1:||top' .
-            '&chxp=0,' . join(',', $axispos) .
-            '&chg=' . (2400/(count($datasets[0])-1)) . ',-1,3,3';   // lines
+            '&cht=lc'.
+            $labeld.
+            '&chxl=0:|'.$this->encodeaxis($axis).#.$'|1:||top'.
+            '&chxp=0,'.join(',', $axispos).
+            '&chg='.(2400 / (count($datasets[0]) - 1)).',-1,3,3'; // lines
 
         return $url;
     }
 
     public function showPie($axis, $datasets)
     {
-        $url = 'https://chart.apis.google.com/chart?' .
+        $url = 'https://chart.apis.google.com/chart?'.
 
         // Dimension of graph. Default is 800x350
-        'chs=' . $this->x . 'x' . $this->y . 
+        'chs='.$this->x.'x'.$this->y.
 
         // Dateset values.
-        '&chd=' . $this->encodedata(array($datasets)) .
+        '&chd='.$this->encodedata([$datasets]).
 
         // chart type is linechart
-        '&cht=p' .
+        '&cht=p'.
 
-        '&chl=' . $this->encodeaxis($axis);
+        '&chl='.$this->encodeaxis($axis);
 
         return $url;
     }
@@ -133,13 +137,15 @@ class sspmod_statistics_Graph_GoogleCharts
      *
      * Here is some test code:
      * <code>
-     * 	    $foo = array(0, 2, 2.3, 2.6, 6, 10, 15, 98, 198, 256, 487, 563, 763, 801, 899, 999, 987, 198234.485, 283746);
-     *	    foreach ($foo AS $f) {
-     *	        echo '<p>' . $f . ' => ' . sspmod_statistics_Graph_GoogleCharts::roof($f);
-     *	    }
+     *      $foo = array(
+     *          0, 2, 2.3, 2.6, 6, 10, 15, 98, 198, 256, 487, 563, 763, 801, 899, 999, 987, 198234.485, 283746
+     *      );
+     *      foreach ($foo as $f) {
+     *          echo '<p>'.$f.' => '.\SimpleSAML\Module\statistics\Graph\GoogleCharts::roof($f);
+     *      }
      * </code>
-     * 
-     * @param $max    Input value.
+     *
+     * @param integer $max    Input value.
      */
     public static function roof($max)
     {
@@ -156,7 +162,7 @@ class sspmod_statistics_Graph_GoogleCharts
         }
 
         $maxGridLines = 10;
-        $candidates = array(1, 2, 5, 10, 20, 25, 50, 100);
+        $candidates = [1, 2, 5, 10, 20, 25, 50, 100];
 
         foreach ($candidates as $c) {
             if ($t / $c < $maxGridLines) {
@@ -165,5 +171,6 @@ class sspmod_statistics_Graph_GoogleCharts
                 return $target_top;
             }
         }
+        return 1;
     }
 }
diff --git a/modules/statistics/lib/LogCleaner.php b/modules/statistics/lib/LogCleaner.php
index b80a39e53e2816ee04a971d567d04dd51a111849..eafb501904e36d7cac8883a3edb1b70da4bca12f 100644
--- a/modules/statistics/lib/LogCleaner.php
+++ b/modules/statistics/lib/LogCleaner.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_LogCleaner
+
+class LogCleaner
 {
     private $statconfig;
     private $statdir;
@@ -16,7 +20,7 @@ class sspmod_statistics_LogCleaner
      */
     public function __construct($inputfile = null)
     {
-        $this->statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
+        $this->statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
 
         $this->statdir = $this->statconfig->getValue('statdir');
         $this->inputfile = $this->statconfig->getValue('inputfile');
@@ -33,9 +37,9 @@ class sspmod_statistics_LogCleaner
      */
     public function dumpConfig()
     {
-        echo 'Statistics directory   : ' . $this->statdir . "\n";
-        echo 'Input file             : ' . $this->inputfile . "\n";
-        echo 'Offset                 : ' . $this->offset . "\n";
+        echo 'Statistics directory   : '.$this->statdir."\n";
+        echo 'Input file             : '.$this->inputfile."\n";
+        echo 'Offset                 : '.$this->offset."\n";
     }
 
 
@@ -46,20 +50,22 @@ class sspmod_statistics_LogCleaner
     public function clean($debug = false)
     {
         if (!is_dir($this->statdir)) {
-            throw new Exception('Statistics module: output dir do not exists [' . $this->statdir . ']');
+            throw new \Exception('Statistics module: output dir do not exists ['.$this->statdir.']');
         }
 
         if (!file_exists($this->inputfile)) {
-            throw new Exception('Statistics module: input file do not exists [' . $this->inputfile . ']');
+            throw new \Exception('Statistics module: input file do not exists ['.$this->inputfile.']');
         }
 
         $file = fopen($this->inputfile, 'r');
 
-        $logparser = new sspmod_statistics_LogParser(
-            $this->statconfig->getValue('datestart', 0), $this->statconfig->getValue('datelength', 15), $this->statconfig->getValue('offsetspan', 44)
+        $logparser = new LogParser(
+            $this->statconfig->getValue('datestart', 0),
+            $this->statconfig->getValue('datelength', 15),
+            $this->statconfig->getValue('offsetspan', 44)
         );
 
-        $sessioncounter = array();
+        $sessioncounter = [];
 
         $i = 0;
         // Parse through log file, line by line
@@ -77,7 +83,7 @@ class sspmod_statistics_LogCleaner
             $content = $logparser->parseContent($logline);
 
             if (($i % 10000) == 0) {
-                echo("Read line " . $i . "\n");
+                echo "Read line ".$i."\n";
             }
 
             $trackid = $content[4];
@@ -88,9 +94,10 @@ class sspmod_statistics_LogCleaner
             $sessioncounter[$trackid]++;
 
             if ($debug) {
-                echo("----------------------------------------\n");
-                echo('Log line: ' . $logline . "\n");
-                echo('Date parse [' . substr($logline, 0, $this->statconfig->getValue('datelength', 15)) . '] to [' . date(DATE_RFC822, $epoch) . ']' . "\n");
+                echo "----------------------------------------\n";
+                echo 'Log line: '.$logline."\n";
+                echo 'Date parse ['.substr($logline, 0, $this->statconfig->getValue('datelength', 15)).
+                    '] to ['.date(DATE_RFC822, $epoch).']'."\n";
                 echo htmlentities(print_r($content, true));
                 if ($i >= 13) {
                     exit;
@@ -98,7 +105,7 @@ class sspmod_statistics_LogCleaner
             }
         }
 
-        $histogram = array();
+        $histogram = [];
         foreach ($sessioncounter as $trackid => $sc) {
             if (!isset($histogram[$sc])) {
                 $histogram[$sc] = 0;
@@ -107,7 +114,7 @@ class sspmod_statistics_LogCleaner
         }
         ksort($histogram);
 
-        $todelete = array();
+        $todelete = [];
         foreach ($sessioncounter as $trackid => $sc) {
             if ($sc > 200) {
                 $todelete[] = $trackid;
@@ -125,14 +132,14 @@ class sspmod_statistics_LogCleaner
      */
     public function store($todelete, $outputfile)
     {
-        echo "Preparing to delete [" .count($todelete) . "] trackids\n";
+        echo "Preparing to delete [".count($todelete)."] trackids\n";
 
         if (!is_dir($this->statdir)) {
-            throw new Exception('Statistics module: output dir do not exists [' . $this->statdir . ']');
+            throw new \Exception('Statistics module: output dir do not exists ['.$this->statdir.']');
         }
 
         if (!file_exists($this->inputfile)) {
-            throw new Exception('Statistics module: input file do not exists [' . $this->inputfile . ']');
+            throw new \Exception('Statistics module: input file do not exists ['.$this->inputfile.']');
         }
 
         $file = fopen($this->inputfile, 'r');
@@ -142,10 +149,12 @@ class sspmod_statistics_LogCleaner
             // Delete existing output file.
             unlink($outputfile);
         }
-        $outfile = fopen($outputfile, 'x'); /* Create the output file. */
+        $outfile = fopen($outputfile, 'x'); // Create the output file
 
-        $logparser = new sspmod_statistics_LogParser(
-            $this->statconfig->getValue('datestart', 0), $this->statconfig->getValue('datelength', 15), $this->statconfig->getValue('offsetspan', 44)
+        $logparser = new LogParser(
+            $this->statconfig->getValue('datestart', 0),
+            $this->statconfig->getValue('datelength', 15),
+            $this->statconfig->getValue('offsetspan', 44)
         );
 
         $i = 0;
@@ -162,7 +171,7 @@ class sspmod_statistics_LogCleaner
             $content = $logparser->parseContent($logline);
 
             if (($i % 10000) == 0) {
-                echo("Read line " . $i . "\n");
+                echo "Read line ".$i."\n";
             }
 
             $trackid = $content[4];
diff --git a/modules/statistics/lib/LogParser.php b/modules/statistics/lib/LogParser.php
index 516c56c93bba6b04f112702e99e93f0c39c7ea14..1fa73aa5e689c094c383a1f3bc1ad70722debe38 100644
--- a/modules/statistics/lib/LogParser.php
+++ b/modules/statistics/lib/LogParser.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_LogParser
+
+class LogParser
 {
     /**
      * @var integer
@@ -43,7 +47,8 @@ class sspmod_statistics_LogParser
     public function parseEpoch($line)
     {
         $epoch = strtotime(substr($line, 0, $this->datelength));
-        if ($epoch > time() + 2678400) {  // 60 * 60 *24 * 31 = 2678400
+        if ($epoch > time() + 2678400) {
+            // 60 * 60 * 24 * 31 = 2678400
             /*
              * More than a month in the future - probably caused by
              * the log files missing the year.
diff --git a/modules/statistics/lib/RatioDataset.php b/modules/statistics/lib/RatioDataset.php
index a88573c65697df752766edc1fa8bf1c42e8dd570..5449a3fd1797c03c08b9d04d8e530f58d8202be4 100644
--- a/modules/statistics/lib/RatioDataset.php
+++ b/modules/statistics/lib/RatioDataset.php
@@ -1,19 +1,23 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_RatioDataset extends sspmod_statistics_StatDataset
+
+class RatioDataset extends StatDataset
 {
     public function aggregateSummary()
     {
         /**
          * Aggregate summary table from dataset. To be used in the table view.
          */
-        $this->summary = array(); 
-        $noofvalues = array();
+        $this->summary = [];
+        $noofvalues = [];
         foreach ($this->results as $slot => $res) {
-            foreach ($res AS $key => $value) {
+            foreach ($res as $key => $value) {
                 if (array_key_exists($key, $this->summary)) {
                     $this->summary[$key] += $value;
                     if ($value > 0) {
@@ -56,12 +60,12 @@ class sspmod_statistics_RatioDataset extends sspmod_statistics_StatDataset
 
     public function combine($result1, $result2)
     {
-        $combined = array();
+        $combined = [];
 
         foreach ($result2 as $tick => $val) {
-            $combined[$tick] = array();
+            $combined[$tick] = [];
             foreach ($val as $index => $num) {
-                $combined[$tick][$index] = $this->divide( 
+                $combined[$tick][$index] = $this->divide(
                     $this->ag($index, $result1[$tick]),
                     $this->ag($index, $result2[$tick])
                 );
@@ -75,4 +79,3 @@ class sspmod_statistics_RatioDataset extends sspmod_statistics_StatDataset
         return null;
     }
 }
-
diff --git a/modules/statistics/lib/Ruleset.php b/modules/statistics/lib/Ruleset.php
index 0c65b1399dc0fae51ae574b67ea68126350fb8f6..9d8c67d058ec3eb28a3717eaf8f5878c3e23e177 100644
--- a/modules/statistics/lib/Ruleset.php
+++ b/modules/statistics/lib/Ruleset.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_Ruleset
+
+class Ruleset
 {
     private $statconfig;
     private $availrulenames;
@@ -29,29 +33,30 @@ class sspmod_statistics_Ruleset
          * Walk through file lists, and get available [rule][fileslot]...
          */
         if (!is_dir($statdir)) {
-            throw new Exception('Statisics output directory [' . $statdir . '] does not exists.');
+            throw new \Exception('Statisics output directory ['.$statdir.'] does not exists.');
         }
         $filelist = scandir($statdir);
-        $this->available = array();
+        $this->available = [];
         foreach ($filelist as $file) {
-        if (preg_match('/([a-z0-9_]+)-([a-z0-9_]+)-([0-9]+)\.stat/', $file, $matches)) {
-            if (array_key_exists($matches[1], $statrules)) {
-                if (array_key_exists($matches[2], $timeres)) 
-                    $this->available[$matches[1]][$matches[2]][] = $matches[3];
+            if (preg_match('/([a-z0-9_]+)-([a-z0-9_]+)-([0-9]+)\.stat/', $file, $matches)) {
+                if (array_key_exists($matches[1], $statrules)) {
+                    if (array_key_exists($matches[2], $timeres)) {
+                        $this->available[$matches[1]][$matches[2]][] = $matches[3];
+                    }
                 }
             }
         }
         if (empty($this->available)) {
-            throw new Exception('No aggregated statistics files found in [' . $statdir . ']');
+            throw new \Exception('No aggregated statistics files found in ['.$statdir.']');
         }
 
         /*
          * Create array with information about available rules..
          */
         $this->availrules = array_keys($statrules);
-        $available_rules = array();
+        $available_rules = [];
         foreach ($this->availrules as $key) {
-            $available_rules[$key] = array('name' => $statrules[$key]['name'], 'descr' => $statrules[$key]['descr']);
+            $available_rules[$key] = ['name' => $statrules[$key]['name'], 'descr' => $statrules[$key]['descr']];
         }
         $this->availrulenames = $available_rules;
     }
@@ -86,9 +91,11 @@ class sspmod_statistics_Ruleset
         $statrulesConfig = $this->statconfig->getConfigItem('statrules');
         $statruleConfig = $statrulesConfig->getConfigItem($rule);
 
-        $presenterClass = SimpleSAML\Module::resolveClass($statruleConfig->getValue('presenter', 'statistics:BaseRule'), 'Statistics_Rulesets');
+        $presenterClass = \SimpleSAML\Module::resolveClass(
+            $statruleConfig->getValue('presenter', 'statistics:BaseRule'),
+            'Statistics_Rulesets'
+        );
         $statrule = new $presenterClass($this->statconfig, $statruleConfig, $rule, $this->available);
         return $statrule;
     }
 }
-
diff --git a/modules/statistics/lib/StatDataset.php b/modules/statistics/lib/StatDataset.php
index b30b59bb52d3046c45a1f3f537274e11d2ecccea..70898bfbce7e04d49cda0b6646e37b4e77752b89 100644
--- a/modules/statistics/lib/StatDataset.php
+++ b/modules/statistics/lib/StatDataset.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Module\statistics;
 
 /**
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_StatDataset
+
+class StatDataset
 {
     protected $statconfig;
     protected $ruleconfig;
@@ -29,8 +31,8 @@ class sspmod_statistics_StatDataset
      */
     public function __construct($statconfig, $ruleconfig, $ruleid, $timeres, $fileslot)
     {
-        assert($statconfig instanceof SimpleSAML_Configuration);
-        assert($ruleconfig instanceof SimpleSAML_Configuration);
+        assert($statconfig instanceof \SimpleSAML\Configuration);
+        assert($ruleconfig instanceof \SimpleSAML\Configuration);
         $this->statconfig = $statconfig;
         $this->ruleconfig = $ruleconfig;
 
@@ -44,9 +46,9 @@ class sspmod_statistics_StatDataset
         $this->delimiter = '_';
         $this->max = 0;
 
-        $this->datehandlerTick = new sspmod_statistics_DateHandler($this->statconfig->getValue('offset', 0));
+        $this->datehandlerTick = new DateHandler($this->statconfig->getValue('offset', 0));
         if ($this->timeresconfig->getValue('customDateHandler', 'default') === 'month') {
-            $this->datehandlerFile = new sspmod_statistics_DateHandlerMonth(0);
+            $this->datehandlerFile = new DateHandlerMonth(0);
         } else {
             $this->datehandlerFile = $this->datehandlerTick;
         }
@@ -89,21 +91,21 @@ class sspmod_statistics_StatDataset
             }
             $maxvalue = max($res[$this->delimiter], $maxvalue);
         }
-        $this->max = sspmod_statistics_Graph_GoogleCharts::roof($maxvalue);
+        $this->max = Graph\GoogleCharts::roof($maxvalue);
     }
 
     public function getDebugData()
     {
-        $debugdata = array();
+        $debugdata = [];
 
         $slotsize = $this->timeresconfig->getValue('slot');
         $dateformat_intra = $this->timeresconfig->getValue('dateformat-intra');
 
         foreach ($this->results as $slot => &$res) {
-            $debugdata[$slot] = array(
+            $debugdata[$slot] = [
                 $this->datehandlerTick->prettyDateSlot($slot, $slotsize, $dateformat_intra),
                 $res[$this->delimiter]
-            );
+            ];
         }
         return $debugdata;
     }
@@ -111,7 +113,7 @@ class sspmod_statistics_StatDataset
     public function aggregateSummary()
     {
         // aggregate summary table from dataset. To be used in the table view
-        $this->summary = array();
+        $this->summary = [];
         foreach ($this->results as $slot => $res) {
             foreach ($res as $key => $value) {
                 if (array_key_exists($key, $this->summary)) {
@@ -128,7 +130,7 @@ class sspmod_statistics_StatDataset
     public function getTopDelimiters()
     {
         // create a list of delimiter keys that has the highest total summary in this period
-        $topdelimiters = array();
+        $topdelimiters = [];
         $maxdelimiters = 4;
         $i = 0;
         foreach ($this->summary as $key => $value) {
@@ -144,7 +146,7 @@ class sspmod_statistics_StatDataset
 
     public function availDelimiters()
     {
-        $availDelimiters = array();
+        $availDelimiters = [];
         foreach ($this->summary as $key => $value) {
             $availDelimiters[$key] = 1;
         }
@@ -153,7 +155,7 @@ class sspmod_statistics_StatDataset
 
     public function getPieData()
     {
-        $piedata = array();
+        $piedata = [];
         $sum = 0;
         $topdelimiters = $this->getTopDelimiters();
 
@@ -186,8 +188,8 @@ class sspmod_statistics_StatDataset
         $dateformat_intra = $this->timeresconfig->getValue('dateformat-intra');
         $axislabelint = $this->timeresconfig->getValue('axislabelint');
 
-        $axis = array();
-        $axispos = array();
+        $axis = [];
+        $axispos = [];
         $xentries = count($this->results);
         $lastslot = 0;
         $i = 0;
@@ -204,7 +206,7 @@ class sspmod_statistics_StatDataset
 
         $axis[] = $this->datehandlerTick->prettyDateSlot($lastslot + 1, $slotsize, $dateformat_intra);
 
-        return array('axis' => $axis, 'axispos' => $axispos);
+        return ['axis' => $axis, 'axispos' => $axispos];
     }
 
     /*
@@ -213,7 +215,7 @@ class sspmod_statistics_StatDataset
     public function getPercentValues()
     {
         $i = 0;
-        $dataset = array();
+        $dataset = [];
         foreach ($this->results as $slot => $res) {
             if (array_key_exists($this->delimiter, $res)) {
                 if ($res[$this->delimiter] === null) {
@@ -232,27 +234,27 @@ class sspmod_statistics_StatDataset
 
     public function getDelimiterPresentation()
     {
-        $config = SimpleSAML_Configuration::getInstance();
-        $t = new SimpleSAML_XHTML_Template($config, 'statistics:statistics.tpl.php');
+        $config = \SimpleSAML\Configuration::getInstance();
+        $t = new \SimpleSAML\XHTML\Template($config, 'statistics:statistics.tpl.php');
 
         $availdelimiters = $this->availDelimiters();
 
         // create a delimiter presentation filter for this rule...
         if ($this->ruleconfig->hasValue('fieldPresentation')) {
             $fieldpresConfig = $this->ruleconfig->getConfigItem('fieldPresentation');
-            $classname = SimpleSAML\Module::resolveClass(
+            $classname = \SimpleSAML\Module::resolveClass(
                 $fieldpresConfig->getValue('class'),
                 'Statistics_FieldPresentation'
             );
             if (!class_exists($classname)) {
-                throw new Exception('Could not find field presentation plugin ['.$classname.']: No class found');
+                throw new \Exception('Could not find field presentation plugin ['.$classname.']: No class found');
             }
             $presentationHandler = new $classname($availdelimiters, $fieldpresConfig->getValue('config'), $t);
 
             return $presentationHandler->getPresentation();
         }
 
-        return array();
+        return [];
     }
 
     public function getDelimiterPresentationPie()
@@ -260,7 +262,7 @@ class sspmod_statistics_StatDataset
         $topdelimiters = $this->getTopDelimiters();
         $delimiterPresentation = $this->getDelimiterPresentation();
 
-        $pieaxis = array();
+        $pieaxis = [];
         foreach ($topdelimiters as $key) {
             $keyName = $key;
             if (array_key_exists($key, $delimiterPresentation)) {
@@ -275,21 +277,21 @@ class sspmod_statistics_StatDataset
     public function loadData()
     {
         $statdir = $this->statconfig->getValue('statdir');
-        $resarray = array();
-        $rules = SimpleSAML\Utils\Arrays::arrayize($this->ruleid);
+        $resarray = [];
+        $rules = \SimpleSAML\Utils\Arrays::arrayize($this->ruleid);
         foreach ($rules as $rule) {
             // Get file and extract results.
             $resultFileName = $statdir.'/'.$rule.'-'.$this->timeres.'-'.$this->fileslot.'.stat';
             if (!file_exists($resultFileName)) {
-                throw new Exception('Aggregated statitics file ['.$resultFileName.'] not found.');
+                throw new \Exception('Aggregated statitics file ['.$resultFileName.'] not found.');
             }
             if (!is_readable($resultFileName)) {
-                throw new Exception('Could not read statitics file ['.$resultFileName.']. Bad file permissions?');
+                throw new \Exception('Could not read statitics file ['.$resultFileName.']. Bad file permissions?');
             }
             $resultfile = file_get_contents($resultFileName);
             $newres = unserialize($resultfile);
             if (empty($newres)) {
-                throw new Exception('Aggregated statistics in file ['.$resultFileName.'] was empty.');
+                throw new \Exception('Aggregated statistics in file ['.$resultFileName.'] was empty.');
             }
             $resarray[] = $newres;
         }
@@ -303,6 +305,4 @@ class sspmod_statistics_StatDataset
         }
         $this->results = $combined;
     }
-
 }
-
diff --git a/modules/statistics/lib/Statistics/FieldPresentation/Base.php b/modules/statistics/lib/Statistics/FieldPresentation/Base.php
index 1402ee31561991b7116b69378520fd5ac77a984f..bb2568f1d6c8814acf4da00021d22ab7fb0ed8cb 100644
--- a/modules/statistics/lib/Statistics/FieldPresentation/Base.php
+++ b/modules/statistics/lib/Statistics/FieldPresentation/Base.php
@@ -1,6 +1,8 @@
 <?php
 
-class sspmod_statistics_Statistics_FieldPresentation_Base
+namespace SimpleSAML\Module\statistics\Statistics\FieldPresentation;
+
+class Base
 {
     protected $fields;
     protected $template;
@@ -15,6 +17,6 @@ class sspmod_statistics_Statistics_FieldPresentation_Base
 
     public function getPresentation()
     {
-        return array('_' => 'Total');
+        return ['_' => 'Total'];
     }
 }
diff --git a/modules/statistics/lib/Statistics/FieldPresentation/Entity.php b/modules/statistics/lib/Statistics/FieldPresentation/Entity.php
index 5556d08f819e68ac0d05354adda58c26b506924c..624d215b7936cf16c4ce7fa5327742e08c71557a 100644
--- a/modules/statistics/lib/Statistics/FieldPresentation/Entity.php
+++ b/modules/statistics/lib/Statistics/FieldPresentation/Entity.php
@@ -1,17 +1,19 @@
 <?php
 
-class sspmod_statistics_Statistics_FieldPresentation_Entity extends sspmod_statistics_Statistics_FieldPresentation_Base
+namespace SimpleSAML\Module\statistics\Statistics\FieldPresentation;
+
+class Entity extends Base
 {
     public function getPresentation()
     {
-        $mh = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+        $mh = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
         $metadata = $mh->getList($this->config);
 
-        $translation = array('_' => 'All services');
+        $translation = ['_' => 'All services'];
         foreach ($this->fields as $field) {
             if (array_key_exists($field, $metadata)) {
                 if (array_key_exists('name', $metadata[$field])) {
-                    $translation[$field] = $this->template->t($metadata[$field]['name'], array(), false);
+                    $translation[$field] = $this->template->t($metadata[$field]['name']);
                 }
             }
         }
diff --git a/modules/statistics/lib/Statistics/Rulesets/BaseRule.php b/modules/statistics/lib/Statistics/Rulesets/BaseRule.php
index 99b2254fdaca026704a513d2fef0c9af7c248d7b..875557bc8dab7c8a0896fe196208d9d57abf1e5b 100644
--- a/modules/statistics/lib/Statistics/Rulesets/BaseRule.php
+++ b/modules/statistics/lib/Statistics/Rulesets/BaseRule.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics\Statistics\Rulesets;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_Statistics_Rulesets_BaseRule
+
+class BaseRule
 {
     protected $statconfig;
     protected $ruleconfig;
@@ -15,15 +19,15 @@ class sspmod_statistics_Statistics_Rulesets_BaseRule
      */
     public function __construct($statconfig, $ruleconfig, $ruleid, $available)
     {
-        assert($statconfig instanceof SimpleSAML_Configuration);
-        assert($ruleconfig instanceof SimpleSAML_Configuration);
+        assert($statconfig instanceof \SimpleSAML\Configuration);
+        assert($ruleconfig instanceof \SimpleSAML\Configuration);
         $this->statconfig = $statconfig;
         $this->ruleconfig = $ruleconfig;
         $this->ruleid = $ruleid;
 
         $this->available = null;
         if (array_key_exists($ruleid, $available)) {
-            $this->available = $available[$ruleid];	
+            $this->available = $available[$ruleid];
         }
     }
 
@@ -32,9 +36,10 @@ class sspmod_statistics_Statistics_Rulesets_BaseRule
         return $this->ruleid;
     }
 
-    public function availableTimeRes() {
+    public function availableTimeRes()
+    {
         $timeresConfigs = $this->statconfig->getValue('timeres');
-        $available_times = array(); 
+        $available_times = [];
         foreach ($timeresConfigs as $tres => $tresconfig) {
             if (array_key_exists($tres, $this->available)) {
                 $available_times[$tres] = $tresconfig['name'];
@@ -49,17 +54,22 @@ class sspmod_statistics_Statistics_Rulesets_BaseRule
         $timeresConfig = $timeresConfigs[$timeres];
 
         if (isset($timeresConfig['customDateHandler']) && $timeresConfig['customDateHandler'] == 'month') {
-            $datehandler = new sspmod_statistics_DateHandlerMonth(0);
+            $datehandler = new \SimpleSAML\Module\statistics\DateHandlerMonth(0);
         } else {
-            $datehandler = new sspmod_statistics_DateHandler($this->statconfig->getValue('offset', 0));
+            $datehandler = new \SimpleSAML\Module\statistics\DateHandler($this->statconfig->getValue('offset', 0));
         }
 
         /*
          * Get list of avaiable times in current file (rule)
          */
-        $available_times = array(); 
+        $available_times = [];
         foreach ($this->available[$timeres] as $slot) {
-            $available_times[$slot] = $datehandler->prettyHeader($slot, $slot + 1, $timeresConfig['fileslot'], $timeresConfig['dateformat-period']);
+            $available_times[$slot] = $datehandler->prettyHeader(
+                $slot,
+                $slot + 1,
+                $timeresConfig['fileslot'],
+                $timeresConfig['dateformat-period']
+            );
         }
         return $available_times;
     }
@@ -105,15 +115,20 @@ class sspmod_statistics_Statistics_Rulesets_BaseRule
         if ($timeslotindex[$fileslot] < (count($timeslotindex) - 1)) {
             $available_times_next = $timeslots[$timeslotindex[$fileslot] + 1];
         }
-        return array('prev' => $available_times_prev, 'next' => $available_times_next);
+        return ['prev' => $available_times_prev, 'next' => $available_times_next];
     }
 
     public function getDataSet($preferTimeRes, $preferTime)
     {
         $timeres = $this->resolveTimeRes($preferTimeRes);
         $fileslot = $this->resolveFileSlot($timeres, $preferTime);
-        $dataset = new sspmod_statistics_StatDataset($this->statconfig, $this->ruleconfig, $this->ruleid, $timeres, $fileslot);
+        $dataset = new \SimpleSAML\Module\statistics\StatDataset(
+            $this->statconfig,
+            $this->ruleconfig,
+            $this->ruleid,
+            $timeres,
+            $fileslot
+        );
         return $dataset;
     }
 }
-
diff --git a/modules/statistics/lib/Statistics/Rulesets/Ratio.php b/modules/statistics/lib/Statistics/Rulesets/Ratio.php
index ceb0ff3d42ed773c205608ecac7d7a65cdcd9c56..1f76f6b4709791447db69970aafcf7d666e02175 100644
--- a/modules/statistics/lib/Statistics/Rulesets/Ratio.php
+++ b/modules/statistics/lib/Statistics/Rulesets/Ratio.php
@@ -1,9 +1,13 @@
 <?php
+
+namespace SimpleSAML\Module\statistics\Statistics\Rulesets;
+
 /*
  * @author Andreas Ă…kre Solberg <andreas.solberg@uninett.no>
  * @package SimpleSAMLphp
  */
-class sspmod_statistics_Statistics_Rulesets_Ratio extends sspmod_statistics_Statistics_Rulesets_BaseRule
+
+class Ratio extends BaseRule
 {
     protected $refrule1;
     protected $refrule2;
@@ -13,8 +17,8 @@ class sspmod_statistics_Statistics_Rulesets_Ratio extends sspmod_statistics_Stat
      */
     public function __construct($statconfig, $ruleconfig, $ruleid, $available)
     {
-        assert($statconfig instanceof SimpleSAML_Configuration);
-        assert($ruleconfig instanceof SimpleSAML_Configuration);
+        assert($statconfig instanceof \SimpleSAML\Configuration);
+        assert($ruleconfig instanceof \SimpleSAML\Configuration);
 
         parent::__construct($statconfig, $ruleconfig, $ruleid, $available);
 
@@ -25,8 +29,8 @@ class sspmod_statistics_Statistics_Rulesets_Ratio extends sspmod_statistics_Stat
         $statruleConfig1 = $statrulesConfig->getConfigItem($refNames[0]);
         $statruleConfig2 = $statrulesConfig->getConfigItem($refNames[1]);
 
-        $this->refrule1 = new sspmod_statistics_Statistics_Rulesets_BaseRule($this->statconfig, $statruleConfig1, $refNames[0], $available);
-        $this->refrule2 = new sspmod_statistics_Statistics_Rulesets_BaseRule($this->statconfig, $statruleConfig2, $refNames[1], $available);
+        $this->refrule1 = new BaseRule($this->statconfig, $statruleConfig1, $refNames[0], $available);
+        $this->refrule2 = new BaseRule($this->statconfig, $statruleConfig2, $refNames[1], $available);
     }
 
     public function availableTimeRes()
@@ -61,8 +65,13 @@ class sspmod_statistics_Statistics_Rulesets_Ratio extends sspmod_statistics_Stat
 
         $refNames = $this->ruleconfig->getArray('ref');
 
-        $dataset = new sspmod_statistics_RatioDataset($this->statconfig, $this->ruleconfig, $refNames, $timeres, $fileslot);
+        $dataset = new \SimpleSAML\Module\statistics\RatioDataset(
+            $this->statconfig,
+            $this->ruleconfig,
+            $refNames,
+            $timeres,
+            $fileslot
+        );
         return $dataset;
     }
 }
-
diff --git a/modules/statistics/templates/statistics.tpl.php b/modules/statistics/templates/statistics.tpl.php
index fa7e1f4e93a8c31c8d0fabbf8f76047a4d9455a9..2e111451f1347d1887aa2cda3f8e28f2e3f4e544 100644
--- a/modules/statistics/templates/statistics.tpl.php
+++ b/modules/statistics/templates/statistics.tpl.php
@@ -1,56 +1,72 @@
 <?php
 $this->data['header'] = 'SimpleSAMLphp Statistics';
 
-$this->data['jquery'] = array('core' => true, 'ui' => true, 'css' => true);
+$this->data['jquery'] = ['core' => true, 'ui' => true, 'css' => true];
 
-$this->data['head'] = '<link rel="stylesheet" type="text/css" href="' . SimpleSAML\Module::getModuleURL("statistics/style.css") . '" />' . "\n";
-$this->data['head'] .= '<script type="text/javascript" src="' . SimpleSAML\Module::getModuleURL("statistics/javascript.js") . '"></script>' . "\n";
+$this->data['head'] = '<link rel="stylesheet" type="text/css" href="'.
+    SimpleSAML\Module::getModuleURL("statistics/assets/css/statistics.css").'" />'."\n";
+$this->data['head'] .= '<script type="text/javascript" src="'.
+    SimpleSAML\Module::getModuleURL("statistics/assets/js/statistics.js").'"></script>'."\n";
 
 $this->includeAtTemplateBase('includes/header.php');
 
-echo '<h1>'. $this->data['available.rules'][$this->data['selected.rule']]['name'] . '</h1>';
-echo '<p>' . $this->data['available.rules'][$this->data['selected.rule']]['descr'] . '</p>';
+echo '<h1>'.$this->data['available.rules'][$this->data['selected.rule']]['name'].'</h1>';
+echo '<p>'.$this->data['available.rules'][$this->data['selected.rule']]['descr'].'</p>';
 
 // Report settings
 echo '<table class="selecttime">';
-echo '<tr><td class="selecttime_icon"><img src="' . SimpleSAML\Utils\HTTP::getBaseUrl() . 'resources/icons/crystal_project/kchart.32x32.png" alt="Report settings" /></td>';
+echo '<tr><td class="selecttime_icon"><img src="'.SimpleSAML\Utils\HTTP::getBaseURL().
+    'resources/icons/crystal_project/kchart.32x32.png" alt="Report settings" /></td>';
 
 // Select report
 echo '<td>';
 echo '<form action="#">';
-echo $this->data['post_rule'];
-echo '<select onchange="submit();" name="rule">';
-foreach ($this->data['available.rules'] as $key => $rule) {
-    if ($key === $this->data['selected.rule']) {
-        echo '<option selected="selected" value="' . $key . '">' . $rule['name'] . '</option>';
-    } else {
-        echo '<option value="' . $key . '">' . $rule['name'] . '</option>';
+
+foreach ($this->data['post_rule'] as $k => $v) {
+    echo '<input type="hidden" name="'.$k.'" value="'.htmlspecialchars($v).'" />'."\n";
+}
+
+if (!empty($this->data['available_rules'])) {
+    echo '<select onchange="submit();" name="rule">';
+    foreach ($this->data['available_rules'] as $key => $rule) {
+        if ($key === $this->data['selected_rule']) {
+            echo '<option selected="selected" value="'.$key.'">'.$rule['name'].'</option>';
+        } else {
+            echo '<option value="'.$key.'">'.$rule['name'].'</option>';
+        }
     }
+    echo '</select>';
 }
-echo '</select></form>';
-echo '</td>';
+echo '</form></td>';
 
 // Select delimiter
 echo '<td class="td_right">';
 echo '<form action="#">';
-echo $this->data['post_d'];
-echo '<select onchange="submit();" name="d">';
-foreach ($this->data['availdelimiters'] as $key => $delim) {
-    $delimName = $delim;
-    if (array_key_exists($delim, $this->data['delimiterPresentation'])) {
-        $delimName = $this->data['delimiterPresentation'][$delim];
-    }
 
-    if ($key == '_') {
-        echo '<option value="_">Total</option>';
-    } elseif (isset($_REQUEST['d']) && $delim == $_REQUEST['d']) {
-        echo '<option selected="selected" value="' . htmlspecialchars($delim) . '">' . htmlspecialchars($delimName) . '</option>';
-    } else {
-        echo '<option  value="' . htmlspecialchars($delim) . '">' . htmlspecialchars($delimName) . '</option>';
+foreach ($this->data['post_d'] as $k => $v) {
+    echo '<input type="hidden" name="'.$k.'" value="'.htmlspecialchars($v).'" />'."\n";
+}
+
+if (!empty($this->data['availdelimiters'])) {
+    echo '<select onchange="submit();" name="d">';
+    foreach ($this->data['availdelimiters'] as $key => $delim) {
+        $delimName = $delim;
+        if (array_key_exists($delim, $this->data['delimiterPresentation'])) {
+            $delimName = $this->data['delimiterPresentation'][$delim];
+        }
+
+        if ($key == '_') {
+            echo '<option value="_">Total</option>';
+        } elseif (isset($_REQUEST['d']) && $delim == $_REQUEST['d']) {
+            echo '<option selected="selected" value="'.htmlspecialchars($delim).'">'.
+                htmlspecialchars($delimName).'</option>';
+        } else {
+            echo '<option  value="'.htmlspecialchars($delim).'">'.htmlspecialchars($delimName).'</option>';
+        }
     }
+    echo '</select>';
 }
-echo '</select></form>';
-echo '</td></tr>';
+echo '</form></td></tr>';
 
 echo '</table>';
 
@@ -59,137 +75,159 @@ echo '</table>';
 
 // Select time and date
 echo '<table class="selecttime">';
-echo '<tr><td class="selecttime_icon"><img src="' . SimpleSAML\Utils\HTTP::getBaseUrl() . 'resources/icons/crystal_project/date.32x32.png" alt="Select date and time" /></td>';
+echo '<tr><td class="selecttime_icon"><img src="'.SimpleSAML\Utils\HTTP::getBaseURL().
+    'resources/icons/crystal_project/date.32x32.png" alt="Select date and time" /></td>';
 
 if (isset($this->data['available.times.prev'])) {
-    echo '<td><a href="' . $this->data['get_times_prev'] . '">« Previous</a></td>';
+    echo '<td><a href="'.$this->data['get_times_prev'].'">« Previous</a></td>';
 } else {
     echo '<td class="selecttime_link_grey">« Previous</td>';
 }
 
 echo '<td class="td_right">';
 echo '<form action="#">';
-echo $this->data['post_res'];
-echo '<select onchange="submit();" name="res">';
-foreach ($this->data['available.timeres'] as $key => $timeresname) {
-    if ($key == $this->data['selected.timeres']) {
-        echo '<option selected="selected" value="' . $key . '">' . $timeresname . '</option>';
-    } else {
-        echo '<option  value="' . $key . '">' . $timeresname . '</option>';
+
+foreach ($this->data['post_res'] as $k => $v) {
+    echo '<input type="hidden" name="'.$k.'" value="'.htmlspecialchars($v).'" />'."\n";
+}
+
+if (!empty($this->data['available.timeres'])) {
+    echo '<select onchange="submit();" name="res">';
+    foreach ($this->data['available.timeres'] as $key => $timeresname) {
+        if ($key == $this->data['selected.timeres']) {
+            echo '<option selected="selected" value="'.$key.'">'.$timeresname.'</option>';
+        } else {
+            echo '<option  value="'.$key.'">'.$timeresname.'</option>';
+        }
     }
+    echo '</select>';
 }
-echo '</select></form>';
-echo '</td>';
+echo '</form></td>';
 
 echo '<td class="td_left">';
 echo '<form action="#">';
-echo $this->data['post_time'];
-echo '<select onchange="submit();" name="time">';
-foreach ($this->data['available.times'] as $key => $timedescr) {
-    if ($key == $this->data['selected.time']) {
-        echo '<option selected="selected" value="' . $key . '">' . $timedescr . '</option>';
-    } else {
-        echo '<option  value="' . $key . '">' . $timedescr . '</option>';
+
+foreach ($this->data['post_time'] as $k => $v) {
+    echo '<input type="hidden" name="'.$k.'" value="'.htmlspecialchars($v).'" />'."\n";
+}
+
+if (!empty($this->data['available.times'])) {
+    echo '<select onchange="submit();" name="time">';
+    foreach ($this->data['available.times'] as $key => $timedescr) {
+        if ($key == $this->data['selected.time']) {
+            echo '<option selected="selected" value="'.$key.'">'.$timedescr.'</option>';
+        } else {
+            echo '<option  value="'.$key.'">'.$timedescr.'</option>';
+        }
     }
+    echo '</select>';
 }
-echo '</select></form>';
-echo '</td>';
+echo '</form></td>';
 
 if (isset($this->data['available.times.next'])) {
-    echo '<td class="td_right td_next_right"><a href="' . $this->data['get_times_next'] . '">Next »</a></td>';
+    echo '<td class="td_right td_next_right"><a href="'.$this->data['get_times_next'].'">Next »</a></td>';
 } else {
     echo '<td class="td_right selecttime_link_grey td_next_right">Next »</td>';
 }
 
 echo '</tr></table>';
+echo '<div id="tabdiv">';
+if (!empty($this->data['results'])) {
+    echo '<ul class="tabset_tabs">
+       <li><a href="#graph">Graph</a></li>
+       <li><a href="#table">Summary table</a></li>
+       <li><a href="#debug">Time serie</a></li>
+    </ul>';
+    echo '
 
+    <div id="graph" class="tabset_content">';
 
-echo '<div id="tabdiv"><ul class="tabset_tabs">
-   <li><a href="#graph">Graph</a></li>
-   <li><a href="#table">Summary table</a></li>
-   <li><a href="#debug">Time serie</a></li>
-</ul>';
-echo '
+    echo '<img src="'.htmlspecialchars($this->data['imgurl']).'" alt="Graph" />';
 
-<div id="graph" class="tabset_content">';
+    echo '<form action="#">';
+    echo '<p class="p_right">Compare with total from this dataset ';
 
-echo '<img src="' . htmlspecialchars($this->data['imgurl']) . '" alt="Graph" />';
-
-echo '<form action="#">';
-echo '<p class="p_right">Compare with total from this dataset ';
-echo $this->data['post_rule2'];
-echo '<select onchange="submit();" name="rule2">';
-echo '	<option value="_">None</option>';
-foreach ($this->data['available.rules'] as $key => $rule) {
-    if ($key === $this->data['selected.rule2']) {
-        echo '<option selected="selected" value="' . $key . '">' . $rule['name'] . '</option>';
-    } else {
-        echo '<option value="' . $key . '">' . $rule['name'] . '</option>';
+    foreach ($this->data['post_rule2'] as $k => $v) {
+        echo '<input type="hidden" name="'.$k.'" value="'.htmlspecialchars($v).'" />'."\n";
     }
-}
-echo '</select></p></form>';
-
-echo '</div>'; // end graph content.
 
-
-/**
- * Handle table view - - - - - - 
- */
-$classint = array('odd', 'even'); $i = 0;
-echo '<div id="table" class="tabset_content">';
-
-if (isset($this->data['pieimgurl'])) {
-    echo '<img src="' . $this->data['pieimgurl'] . '" alt="Pie chart" />';
-}
-echo '<table class="tableview"><tr><th class="value">Value</th><th class="category">Data range</th></tr>';
-
-foreach ($this->data['summaryDataset'] as $key => $value) {
-    $clint = $classint[$i++ % 2];
-
-    $keyName = $key;
-    if (array_key_exists($key, $this->data['delimiterPresentation'])) {
-        $keyName = $this->data['delimiterPresentation'][$key];
+    echo '<select onchange="submit();" name="rule2">';
+    echo '	<option value="_">None</option>';
+    foreach ($this->data['available_rules'] as $key => $rule) {
+        if ($key === $this->data['selected.rule2']) {
+            echo '<option selected="selected" value="'.$key.'">'.$rule['name'].'</option>';
+        } else {
+            echo '<option value="'.$key.'">'.$rule['name'].'</option>';
+        }
     }
+    echo '</select></p></form>';
 
-    if ($key === '_') {
-        echo '<tr class="total '  . $clint . '"><td  class="value">' . $value . '</td><td class="category">' . $keyName . '</td></tr>';
-    } else {
-        echo '<tr class="' . $clint . '"><td  class="value">' . $value . '</td><td class="category">' . $keyName . '</td></tr>';
-    }
-}
+    echo '</div>'; // end graph content.
 
-echo '</table></div>';
-//  - - - - - - - End table view - - - - - - - 
+    /**
+     * Handle table view - - - - - -
+     */
+    $classint = ['odd', 'even'];
+    $i = 0;
+    echo '<div id="table" class="tabset_content">';
 
-echo '<div id="debug" >';
-echo '<table class="timeseries">';
-echo '<tr><th>Time</th><th>Total</th>';
-foreach ($this->data['topdelimiters'] as $key) {
-    $keyName = $key;
-    if (array_key_exists($key, $this->data['delimiterPresentation'])) {
-        $keyName = $this->data['delimiterPresentation'][$key];
+    if (isset($this->data['pieimgurl'])) {
+        echo '<img src="'.$this->data['pieimgurl'].'" alt="Pie chart" />';
+    }
+    echo '<table class="tableview"><tr><th class="value">Value</th><th class="category">Data range</th></tr>';
+
+    foreach ($this->data['summaryDataset'] as $key => $value) {
+        $clint = $classint[$i++ % 2];
+
+        $keyName = $key;
+        if (array_key_exists($key, $this->data['delimiterPresentation'])) {
+            $keyName = $this->data['delimiterPresentation'][$key];
+        }
+
+        if ($key === '_') {
+            echo '<tr class="total '.$clint.'"><td  class="value">'.
+                $value.'</td><td class="category">'.$keyName.'</td></tr>';
+        } else {
+            echo '<tr class="'.$clint.'"><td  class="value">'.$value.
+                '</td><td class="category">'.$keyName.'</td></tr>';
+        }
     }
-    echo'<th>' . $keyName . '</th>';
-}
-echo '</tr>';
-
 
-$i = 0;
-foreach ($this->data['debugdata'] as $slot => $dd) {
-    echo '<tr class="' . ((++$i % 2) == 0 ? 'odd' : 'even') . '">';
-    echo '<td>' . $dd[0] . '</td>';
-    echo '<td class="datacontent">' . $dd[1] . '</td>';
+    echo '</table></div>';
+    //  - - - - - - - End table view - - - - - - -
 
+    echo '<div id="debug" >';
+    echo '<table class="timeseries">';
+    echo '<tr><th>Time</th><th>Total</th>';
     foreach ($this->data['topdelimiters'] as $key) {
-        echo '<td class="datacontent">' . (array_key_exists($key, $this->data['results'][$slot]) ?
-            $this->data['results'][$slot][$key] : '&nbsp;') . '</td>';
+        $keyName = $key;
+        if (array_key_exists($key, $this->data['delimiterPresentation'])) {
+            $keyName = $this->data['delimiterPresentation'][$key];
+        }
+        echo'<th>'.$keyName.'</th>';
     }
     echo '</tr>';
-}
-echo '</table>';
+
+    $i = 0;
+    foreach ($this->data['debugdata'] as $slot => $dd) {
+        echo '<tr class="'.((++$i % 2) == 0 ? 'odd' : 'even').'">';
+        echo '<td>'.$dd[0].'</td>';
+        echo '<td class="datacontent">'.$dd[1].'</td>';
+
+        foreach ($this->data['topdelimiters'] as $key) {
+            echo '<td class="datacontent">'.(array_key_exists($key, $this->data['results'][$slot]) ?
+                $this->data['results'][$slot][$key] : '&nbsp;').'</td>';
+        }
+        echo '</tr>';
+    }
+    echo '</table>';
 
 
-echo '</div>'; // End debug tab content
+    echo '</div>'; // End debug tab content
+} else {
+    echo '<h4 align="center">'.$this->data['error'].'</h4>';
+    echo '<p align="center"><a href="showstats.php">Clear selection</a></p>';
+}
 echo '</div>'; // End tab div
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/modules/statistics/templates/statistics.twig b/modules/statistics/templates/statistics.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e9f8946f936271139fa4f7c11609439ff53c0c51
--- /dev/null
+++ b/modules/statistics/templates/statistics.twig
@@ -0,0 +1,223 @@
+{% set pagetitle = 'SimpleSAMLphp Statistics'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}assets/css/statistics.css" rel="stylesheet" />
+{% endblock %}
+
+{% block postload %}
+<script type="text/javascript" src="{{ baseurlpath }}assets/js/statistics.js"></script>
+{% endblock %}
+
+{% block content %}
+    <h1>{{ current_rule.name }}</h1>
+    <p>{{ current_rule.descr }}</p>
+
+    <table class="selecttime">
+        <tr>
+            <td class="selecttime_icon">
+                <i class="fa fa-pie-chart"></i>
+            </td>
+            <td>
+                <form action="#">
+                    {% for key, value in post_rule %}
+                    <input type="hidden" name="{{ key|escape('html') }}" value="{{ value|escape('html') }}">
+                    {% endfor %}
+                    <select onchange="submit();" name="rule">
+                    {% for key, rule in available_rules %}
+                        {% if key == selected_rule %}
+                        <option selected="selected" value="{{ key }}">{{ rule.name }}</option>
+                        {% else %}
+                        <option value="{{ key }}">{{ rule.name }}</option>
+                        {% endif %}
+                    {% endfor %}
+                    </select>
+                </form>
+            </td>
+            <td class="td_right">
+                <form action="#">
+                    {% for key, value in post_d %}
+                    <input type="hidden" name="{{ key|escape('html') }}" value="{{ value|escape('html') }}">
+                    {% endfor %}
+                    {% if availdelimiters %}
+                    <select onchange="submit();" name="d">
+                    {% for key, delim in availdelimiters %}
+                        {% set delimName = delim %}
+
+                        {% if delimiterPresentation[delim] is defined %}
+                        {% set delimName = delimiterPresentation[delim] %}
+                        {% endif %}
+
+                        {% if key == "_" %}
+                        <option value="_">Total</option>
+                        {% elseif request_d is defined and delim == request_d %}
+                        <option selected="selected" value="{{ delim|escape('html') }}">{{ delimName|escape('html') }}</option>
+                        {% else %}
+                        <option value="{{ delim|escape('html') }}">{{ delimName|escape('html') }}</option>
+                        {% endif %}
+                    {% endfor %}
+                    </select>
+                    {% endif %}
+                </form>
+            </td>
+        </tr>
+    </table>
+
+    <table class="selecttime">
+        <tr>
+            <td class="selecttime_icon">
+                <i class="fa fa-calendar"></i>
+            </td>
+            {% if available_times_prev %}
+            <td><a href="{{ get_times_prev }}">&laquo; Previous</a></td>
+            {% else %}
+            <td class="selecttime_link_grey">&laquo; Previous</td>
+            {% endif %}
+            <td class="td_right">
+                <form action="#">
+                    {% for key, value in post_res %}
+                    <input type="hidden" name="{{ key|escape('html') }}" value="{{ value|escape('html') }}">
+                    {% endfor %}
+                    {% if available_timeres %}
+                    <select onchange="submit();" name="res">
+                    {% for key, timeresname in available_timeres %}
+                        {% if key == selected_timeres %}
+                        <option selected="selected" value="{{ key }}">{{ timeresname }}</option>
+                        {% else %}
+                        <option value="{{ key }}">{{ timeresname }}</option>
+                        {% endif %}
+                    {% endfor %}
+                    </select>
+                    {% endif %}
+                </form>
+            </td>
+            <td class="td_left">
+                <form action="#">
+                    {% for key, value in post_time %}
+                    <input type="hidden" name="{{ key|escape('html') }}" value="{{ value|escape('html') }}">
+                    {% endfor %}
+                    {% if available_times %}
+                    <select onchange="submit();" name=time>
+                    {% for key, timedescr in available_times %}
+                        {% if key == selected_time %}
+                        <option selected="selected" value="{{ key }}">{{ timedescr }}</option>
+                        {% else %}
+                        <option value="{{ key }}">{{ timedescr }}</option>
+                        {% endif%}
+                    {% endfor %}
+                    </select>
+                    {% endif %}
+                </form>
+            </td>
+            {% if available_times_next %}
+                <td class="td_right td_next_right"><a href="{{ get_times_next }}">Next &raquo;</a></td>
+            {% else %}
+                <td class="td_right selecttime_link_grey">Next &raquo;</td>
+            {% endif %}
+        </tr>
+    </table>
+
+    <div id="tabdiv">
+    {% if results %}
+        <ul class="tabset_tabs">
+            <li class="tab-link current" data-tab="graph"><a href="#graph">Graph</a></li>
+            <li class="tab-link" data-tab="table"><a href="#table">Summary table</a></li>
+            <li class="tab-link" data-tab="debug"><a href="#debug">Time serie</a></li>
+        </ul>
+
+        <div id="graph" class="tabset_content current">
+            <img src="{{ imgurl }}" alt="Graph" />
+            <form action="#">
+                <p class="p_right">Compare with total from this dataset
+                <select onchange="submit();" name="rule2">
+                    <option value="_">None</option>
+                    {% for key, rule in available_rules %}
+                    {% if key == selected_rule2 %}
+                    <option selected="selected" value="{{ key }}">{{ rule.name }}</option>
+                    {% else %}
+                    <option value="{{ key }}">{{ rule.name }}</option>
+                    {% endif %}
+                    {% endfor %}
+                </select>
+                </p>
+            </form>
+        </div>
+
+        <div id="table" class="tabset_content">
+            {% if pieimgurl is defined %}
+            <img src="{{ pieimgurl }}" alt="Pie chart" />
+            {% endif %}
+
+            <table class="tableview">
+                <tr>
+                    <th class="value">Value</th>
+                    <th class="category">Data range</th>
+                </tr>
+                {% for key, value in summaryDataset %}
+                {% if loop.index0 is even %}
+                    {% set class = 'even' %}
+                {% else %}
+                    {% set class = 'odd' %}
+                {% endif %}
+
+                {% set keyName = key %}
+                {% if delimiterPresentation[key] is defined %}
+                {% set keyName = delimiterPresentation[key] %}
+                {% endif %}
+
+                {% if key == "_" %}
+                <tr class="total {{ class }}">
+                    <td class="value">{{ value }}</td>
+                    <td class="category">{{ keyName }}</td>
+                </tr>
+                {% else %}
+                <tr class="{{ class }}">
+                    <td class="value">{{ value }}</td>
+                    <td class="category">{{ keyName }}</td>
+                </tr>
+                {% endif %}
+                {% endfor %}
+            </table>
+        </div>
+
+        <div id="debug" class="tabset_content">
+            <table class="timeseries">
+                <tr>
+                    <th>Time</th>
+                    <th>Total</th>
+                    {% for key, value in topdelimiters %}
+                    {% set keyName = value %}
+                    {% if delimiterPresentation[value] is defined %}
+                        {% set keyName = delimiterPresentation[value] %}
+                    {% endif %}
+                    <th>{{ keyName }}</th>
+                    {% endfor %}
+                </tr>
+                {% for slot, dd in debugdata %}
+
+                {% if loop.index0 is even %}
+                    {% set class = 'even' %}
+                {% else %}
+                    {% set class = 'odd' %}
+                {% endif %}
+
+                <tr class="{{ class }}">
+                    <td>{{ dd[0] }}</td>
+                    <td class="datacontent">{{ dd[1] }}</td>
+                    {% for key, value in topdelimiters %}
+                    {% if results[slot] is defined %}
+                    <td class="datacontent">{{ results[slot][value] }}</td>
+                    {% else %}
+                    <td class="datacontent">&nbsp;</td>
+                    {% endif %}
+                    {% endfor %}
+                </tr>
+                {% endfor %}
+            </table>
+        </div>
+    {% else %}
+        <h4 align="center">{{ error }}</h4>
+        <p align="center"><a href="showstats.php">Clear selection</a></p>
+    {% endif %}
+    </div>
+{% endblock %}
diff --git a/modules/statistics/templates/statmeta.tpl.php b/modules/statistics/templates/statmeta.tpl.php
index 9af5a032ef3ce5b9caf74256de5bbb8c9ca6b885..324b4e0c5c2ad26a0abf5e3b3c2ee82d98ec3a0b 100644
--- a/modules/statistics/templates/statmeta.tpl.php
+++ b/modules/statistics/templates/statmeta.tpl.php
@@ -1,6 +1,7 @@
 <?php
 $this->data['header'] = 'SimpleSAMLphp Statistics Metadata';
-$this->data['head'] = '<link rel="stylesheet" type="text/css" href="' . SimpleSAML\Module::getModuleURL("statistics/style.css") . '" />';
+$this->data['head'] = '<link rel="stylesheet" type="text/css" href="'.
+    SimpleSAML\Module::getModuleURL("statistics/assets/css/statistics.css").'" />';
 $this->includeAtTemplateBase('includes/header.php');
 
 echo '<table id="statmeta">' ;
@@ -9,34 +10,33 @@ if (isset($this->data['metadata'])) {
     $metadata = $this->data['metadata'];
 
     if (isset($metadata['lastrun'])) {
-        echo '<tr><td>Aggregator last run at</td><td>' . $metadata['lastrun'] . '</td></tr>';
+        echo '<tr><td>Aggregator last run at</td><td>'.$metadata['lastrun'].'</td></tr>';
     }
 
     if (isset($metadata['notBefore'])) {
-        echo '<tr><td>Aggregated data until</td><td>' . $metadata['notBefore'] . '</td></tr>';
+        echo '<tr><td>Aggregated data until</td><td>'.$metadata['notBefore'].'</td></tr>';
     }
 
     if (isset($metadata['memory'])) {
-        echo '<tr><td>Memory usage</td><td>' . $metadata['memory'] . ' MB' . '</td></tr>';
+        echo '<tr><td>Memory usage</td><td>'.$metadata['memory'].' MB'.'</td></tr>';
     }
 
     if (isset($metadata['time'])) {
-        echo '<tr><td>Execution time</td><td>' . $metadata['time'] . ' seconds' . '</td></tr>';
+        echo '<tr><td>Execution time</td><td>'.$metadata['time'].' seconds'.'</td></tr>';
     }
 
-    if (isset($metadata['lastlinehash'] )) {
-        echo '<tr><td>SHA1 of last processed logline</td><td>' . $metadata['lastlinehash'] . '</td></tr>';
+    if (isset($metadata['lastlinehash'])) {
+        echo '<tr><td>SHA1 of last processed logline</td><td>'.$metadata['lastlinehash'].'</td></tr>';
     }
 
-    if (isset($metadata['lastline'] )) {
-        echo '<tr><td>Last processed logline</td><td>' . $metadata['lastline'] . '</td></tr>';
+    if (isset($metadata['lastline'])) {
+        echo '<tr><td>Last processed logline</td><td>'.$metadata['lastline'].'</td></tr>';
     }
 } else {
     echo '<tr><td>No metadata found</td></tr>';
 }
 
 echo '</table>';
-echo '<p>[ <a href="' . SimpleSAML\Module::getModuleURL("statistics/showstats.php") . '">Show statistics</a> ] </p>';
+echo '<p>[ <a href="'.SimpleSAML\Module::getModuleURL("statistics/showstats.php").'">Show statistics</a> ] </p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
-
diff --git a/modules/statistics/templates/statmeta.twig b/modules/statistics/templates/statmeta.twig
new file mode 100644
index 0000000000000000000000000000000000000000..09808e837a0d97818e143582d9915199cfe24d43
--- /dev/null
+++ b/modules/statistics/templates/statmeta.twig
@@ -0,0 +1,39 @@
+{% set pagetitle = 'SimpleSAMLphp Statistics Metadata'|trans %}
+{% extends "base.twig" %}
+
+{% block preload %}
+    <link href="{{ baseurlpath }}assets/css/statistics.css" rel="stylesheet" />
+{% endblock %}
+
+{% block content %}
+    <table id="statmeta">
+    {% if metadata is defined %}
+        {% if metadata.lastrun is defined %}
+            <tr><td>Aggregator last run at</td><td>{{ metadata.lastrun }}</td></tr>
+        {% endif %}
+
+        {% if metadata.notBefore is defined %}
+            <tr><td>Aggregated data until</td><td>{{ metadata.notBefore }}</td></tr>
+        {% endif %}
+
+        {% if metadata.memory is defined %}
+            <tr><td>Memory usage</td><td>{{ metadata.memory }} MB</td></tr>
+        {% endif %}
+
+        {% if metadata.memory is defined %}
+            <tr><td>Execution time</td><td>{{ metadata.time }} seconds</td></tr>
+        {% endif %}
+
+        {% if metadata.memory is defined %}
+            <tr><td>SHA1 of last processed logline</td><td>{{ metadata.lastlinehash }}</td></tr>
+        {% endif %}
+
+        {% if metadata.memory is defined %}
+            <tr><td>Last processed logline</td><td>{{ metadata.lastline }}</td></tr>
+        {% endif %}
+    {% else %}
+        <tr><td>No metadata found</td></tr>
+    {% endif %}
+    </table>
+    <p>[ <a href="{{ baseurlpath }}showstats.php">Show statistics</a> ]</p>
+{% endblock %}
diff --git a/modules/statistics/www/style.css b/modules/statistics/www/assets/css/statistics.css
similarity index 70%
rename from modules/statistics/www/style.css
rename to modules/statistics/www/assets/css/statistics.css
index 1485d07910f3e7bb23af42fc43546184c050338b..4d0d163d600681ffe26fa34cee7cd7cbd9505bc4 100644
--- a/modules/statistics/www/style.css
+++ b/modules/statistics/www/assets/css/statistics.css
@@ -1,6 +1,4 @@
 @media all {
-    .ui-tabs-panel { padding: .5em }
-
     div#content {
         margin: .4em ! important;
     }
@@ -35,10 +33,6 @@
         text-align: right;
     }
 
-    div.corner_t {
-        max-width: none ! important;
-    }
-
     table.timeseries tr.odd td {
         background-color: #f4f4f4;
     }
@@ -92,4 +86,42 @@
     table#statmeta {
         width: 100%;
     }
+
+    ul.tabset_tabs {
+        margin: 0px;
+        padding: 0px;
+        list-style: none;
+    }
+
+    ul.tabset_tabs li {
+        background: none;
+        color: #222;
+        display: inline-block;
+        padding: 10px 15px;
+        cursor: pointer;
+    }
+
+    ul.tabset_tabs li.current {
+        background: #ededed;
+        color: #222;
+    }
+
+    .tabset_content {
+        display: none;
+        background: #ededed;
+        padding: 15px;
+    }
+
+    .tabset_content.current {
+        display: inherit;
+    }
+
+    #graph img {
+        max-width: 77%;
+        height: auto;
+    }
+    #table img {
+        max-width: 77%;
+        height: auto;
+    }
 }
diff --git a/modules/statistics/www/assets/js/statistics.js b/modules/statistics/www/assets/js/statistics.js
new file mode 100644
index 0000000000000000000000000000000000000000..54a72551d90bc1b501e5c2d01f0b83879af7efcc
--- /dev/null
+++ b/modules/statistics/www/assets/js/statistics.js
@@ -0,0 +1,8 @@
+$(document).ready(function () {
+    $("#tabdiv").tabs();
+    $('ul.tabset_tabs li').click(
+        function () {
+            $("html, body").animate({ scrollTop: 0 }, "slow");
+        }
+    )
+});
diff --git a/modules/statistics/www/assets/statistics.css b/modules/statistics/www/assets/statistics.css
new file mode 100644
index 0000000000000000000000000000000000000000..4d0d163d600681ffe26fa34cee7cd7cbd9505bc4
--- /dev/null
+++ b/modules/statistics/www/assets/statistics.css
@@ -0,0 +1,127 @@
+@media all {
+    div#content {
+        margin: .4em ! important;
+    }
+
+    .tableview {
+        border-collapse: collapse;
+        border: 1px solid #ccc;
+        margin: 1em;
+        width: 80%;
+    }
+
+    .tableview th, .tableview td {
+        border: 1px solid #ccc;
+        padding: 0px 5px;
+    }
+
+    .tableview th {
+        background: #e5e5e5;
+    }
+
+    .tableview tr.total td {
+        color: #500; font-weight: bold;
+    }
+
+    .tableview tr.even td {
+        background: #f5f5f5;
+        border-top: 1px solid #e0e0e0;
+        border-bottom: 1px solid #e0e0e0;
+    }
+
+    .tableview th.value, .tableview td.value {
+        text-align: right;
+    }
+
+    table.timeseries tr.odd td {
+        background-color: #f4f4f4;
+    }
+
+    table.timeseries td {
+        padding-right: 2em; border: 1px solid #ccc
+    }
+
+    td.datacontent {
+        text-align: right;
+    }
+
+    table.selecttime {
+        width: 100%;
+        border: 1px solid #ccc;
+        background: #eee;
+        margin: 1px 0px; padding: 0px;
+    }
+
+    td.selecttime_icon {
+        width: 50px;
+        padding: 0px;
+    }
+
+    td.selecttime_icon img {
+        margin: 0px;
+    }
+
+    td.selecttime_link_grey {
+        color: #ccc;
+    }
+
+    td.td_right {
+        text-align: right;
+    }
+    td.td_next_right {
+        padding-right: 4px;
+    }
+    td.td_left {
+        text-align: left;
+    }
+
+    p.p_right {
+        text-align: right;
+    }
+
+    form {
+        display: inline;
+    }
+
+    table#statmeta {
+        width: 100%;
+    }
+
+    ul.tabset_tabs {
+        margin: 0px;
+        padding: 0px;
+        list-style: none;
+    }
+
+    ul.tabset_tabs li {
+        background: none;
+        color: #222;
+        display: inline-block;
+        padding: 10px 15px;
+        cursor: pointer;
+    }
+
+    ul.tabset_tabs li.current {
+        background: #ededed;
+        color: #222;
+    }
+
+    .tabset_content {
+        display: none;
+        background: #ededed;
+        padding: 15px;
+    }
+
+    .tabset_content.current {
+        display: inherit;
+    }
+
+    #graph img {
+        max-width: 77%;
+        height: auto;
+    }
+    #table img {
+        max-width: 77%;
+        height: auto;
+    }
+}
diff --git a/modules/statistics/www/assets/statistics.js b/modules/statistics/www/assets/statistics.js
new file mode 100644
index 0000000000000000000000000000000000000000..54a72551d90bc1b501e5c2d01f0b83879af7efcc
--- /dev/null
+++ b/modules/statistics/www/assets/statistics.js
@@ -0,0 +1,8 @@
+$(document).ready(function () {
+    $("#tabdiv").tabs();
+    $('ul.tabset_tabs li').click(
+        function () {
+            $("html, body").animate({ scrollTop: 0 }, "slow");
+        }
+    )
+});
diff --git a/modules/statistics/www/javascript.js b/modules/statistics/www/javascript.js
deleted file mode 100644
index a5aa421a67fffda6c3c2f4527c8227e58b1b9cde..0000000000000000000000000000000000000000
--- a/modules/statistics/www/javascript.js
+++ /dev/null
@@ -1,4 +0,0 @@
-$(document).ready(function() {
-        $("#tabdiv").tabs();
-});
-
diff --git a/modules/statistics/www/showstats.php b/modules/statistics/www/showstats.php
index 051dc9aa55440fd3cd87059ce0a15fe6ab1dc302..a8a2f247b7c87014fa225b465535b1ef12918e7f 100644
--- a/modules/statistics/www/showstats.php
+++ b/modules/statistics/www/showstats.php
@@ -1,10 +1,10 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
-$statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
-$session = SimpleSAML_Session::getSessionFromRequest();
+$config = \SimpleSAML\Configuration::getInstance();
+$statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
-sspmod_statistics_AccessCheck::checkAccess($statconfig);
+\SimpleSAML\Module\statistics\AccessCheck::checkAccess($statconfig);
 
 /*
  * Check input parameters
@@ -29,6 +29,7 @@ if (array_key_exists('res', $_REQUEST)) {
 }
 if (array_key_exists('d', $_REQUEST)) {
     $delimiter = $_REQUEST['d'];
+    $t->data['request_d'] = $delimiter;
 }
 
 if ($preferRule2 === '_') {
@@ -38,12 +39,41 @@ if ($preferRule2 === '_') {
 /*
  * Create statistics data.
  */
-$ruleset = new sspmod_statistics_Ruleset($statconfig);
+$ruleset = new \SimpleSAML\Module\statistics\Ruleset($statconfig);
 $statrule = $ruleset->getRule($preferRule);
 $rule = $statrule->getRuleID();
 
-$dataset = $statrule->getDataset($preferTimeRes, $preferTime);
-$dataset->setDelimiter($delimiter);
+$t = new \SimpleSAML\XHTML\Template($config, 'statistics:statistics.tpl.php');
+$t->data['pageid'] = 'statistics';
+$t->data['header'] = 'stat';
+$t->data['available_rules'] = $ruleset->availableRulesNames();
+$t->data['selected_rule'] = $rule;
+$t->data['selected_rule2'] = $preferRule2;
+
+$t->data['post_d'] = getBaseURL($t, 'post', 'd');
+
+try {
+    $dataset = $statrule->getDataset($preferTimeRes, $preferTime);
+    $dataset->setDelimiter($delimiter);
+    $dataset->aggregateSummary();
+    $dataset->calculateMax();
+
+    if (array_key_exists('output', $_REQUEST) && $_REQUEST['output'] === 'csv') {
+        header('Content-type: text/csv');
+        header('Content-Disposition: attachment; filename="simplesamlphp-data.csv"');
+        $data = $dataset->getDebugData();
+        foreach ($data as $de) {
+            if (isset($de[1])) {
+                echo '"'.$de[0].'",'.$de[1]."\n";
+            }
+        }
+        exit;
+    }
+} catch (\Exception $e) {
+    $t->data['error'] = "No data available";
+    $t->show();
+    exit;
+}
 
 $delimiter = $dataset->getDelimiter();
 
@@ -53,95 +83,87 @@ $availableFileSlots = $statrule->availableFileSlots($timeres);
 
 $timeNavigation = $statrule->getTimeNavigation($timeres, $preferTime);
 
-$dataset->aggregateSummary();
-$dataset->calculateMax();
-
 $piedata = $dataset->getPieData();
 
-$datasets = array();
+$datasets = [];
 $datasets[] = $dataset->getPercentValues();
 
 $axis = $dataset->getAxis();
 
-$maxes = array();
+$maxes = [];
 
 $maxes[] = $dataset->getMax();
 
 if (isset($preferRule2)) {
     $statrule = $ruleset->getRule($preferRule2);
-    $dataset2 = $statrule->getDataset($preferTimeRes, $preferTime);
-    $dataset2->aggregateSummary();
-    $dataset2->calculateMax();
-
-    $datasets[] = $dataset2->getPercentValues();
-    $maxes[] = $dataset2->getMax();
+    try {
+        $dataset2 = $statrule->getDataset($preferTimeRes, $preferTime);
+        $dataset2->aggregateSummary();
+        $dataset2->calculateMax();
+
+        $datasets[] = $dataset2->getPercentValues();
+        $maxes[] = $dataset2->getMax();
+    } catch (\Exception $e) {
+        $t->data['error'] = "No data available to compare";
+        $t->show();
+        exit;
+    }
 }
 
 $dimx = $statconfig->getValue('dimension.x', 800);
 $dimy = $statconfig->getValue('dimension.y', 350);
-$grapher = new sspmod_statistics_Graph_GoogleCharts($dimx, $dimy);
-
-if (array_key_exists('output', $_REQUEST) && $_REQUEST['output'] === 'csv') {
-    header('Content-type: text/csv');
-    header('Content-Disposition: attachment; filename="simplesamlphp-data.csv"');
-    $data = $dataset->getDebugData();
-    foreach ($data as $de) {
-        if (isset($de[1])) {
-            echo '"' . $de[0] . '",' . $de[1] . "\n";
-        }
-    }
-    exit;
-}
+$grapher = new \SimpleSAML\Module\statistics\Graph\GoogleCharts($dimx, $dimy);
 
-$t = new SimpleSAML_XHTML_Template($config, 'statistics:statistics.tpl.php');
-$t->data['pageid'] = 'statistics';
-$t->data['header'] = 'stat';
 $t->data['imgurl'] = $grapher->show($axis['axis'], $axis['axispos'], $datasets, $maxes);
 if (isset($piedata)) {
-    $t->data['pieimgurl'] = $grapher->showPie( $dataset->getDelimiterPresentationPie(), $piedata);
+    $t->data['pieimgurl'] = $grapher->showPie($dataset->getDelimiterPresentationPie(), $piedata);
 }
-$t->data['available.rules'] = $ruleset->availableRulesNames();
-$t->data['available.times'] = $statrule->availableFileSlots($timeres);
-$t->data['available.timeres'] = $statrule->availableTimeRes();
-$t->data['available.times.prev'] = $timeNavigation['prev'];
-$t->data['available.times.next'] = $timeNavigation['next'];
-
-$t->data['selected.rule']= $rule;
-$t->data['selected.rule2']= $preferRule2;
-$t->data['selected.time'] = $fileslot;
-$t->data['selected.timeres'] = $timeres;
-$t->data['selected.delimiter'] = $delimiter;
+
+$t->data['available_rules'] = $ruleset->availableRulesNames();
+$t->data['available_times'] = $statrule->availableFileSlots($timeres);
+$t->data['available_timeres'] = $statrule->availableTimeRes();
+$t->data['available_times_prev'] = $timeNavigation['prev'];
+$t->data['available_times_next'] = $timeNavigation['next'];
+
+$t->data['current_rule'] = $t->data['available_rules'][$rule];
+
+$t->data['selected_rule'] = $rule;
+$t->data['selected_rule2'] = $preferRule2;
+$t->data['selected_time'] = $fileslot;
+$t->data['selected_timeres'] = $timeres;
+$t->data['selected_delimiter'] = $delimiter;
 
 $t->data['debugdata'] = $dataset->getDebugData();
 $t->data['results'] = $dataset->getResults();
 $t->data['summaryDataset'] = $dataset->getSummary();
 $t->data['topdelimiters'] = $dataset->getTopDelimiters();
-$t->data['availdelimiters'] = $dataset->availDelimiters();
-
-$t->data['delimiterPresentation'] =  $dataset->getDelimiterPresentation();
 
 $t->data['post_rule'] = getBaseURL($t, 'post', 'rule');
 $t->data['post_rule2'] = getBaseURL($t, 'post', 'rule2');
-$t->data['post_d'] = getBaseURL($t, 'post', 'd');
 $t->data['post_res'] = getBaseURL($t, 'post', 'res');
 $t->data['post_time'] = getBaseURL($t, 'post', 'time');
-$t->data['get_times_prev'] = getBaseURL($t, 'get', 'time', $t->data['available.times.prev']);
-$t->data['get_times_next'] = getBaseURL($t, 'get', 'time', $t->data['available.times.next']);
+$t->data['get_times_prev'] = getBaseURL($t, 'get', 'time', $t->data['available_times_prev']);
+$t->data['get_times_next'] = getBaseURL($t, 'get', 'time', $t->data['available_times_next']);
+
+$t->data['availdelimiters'] = $dataset->availDelimiters();
+$t->data['delimiterPresentation'] = $dataset->getDelimiterPresentation();
+
+$t->data['jquery'] = ['core' => false, 'ui' => true, 'css' => true];
 
 $t->show();
 
 function getBaseURL($t, $type = 'get', $key = null, $value = null)
 {
-    $vars = array(
-        'rule' => $t->data['selected.rule'],
-        'time' => $t->data['selected.time'],
-        'res' => $t->data['selected.timeres'],
-    );
-    if (isset($t->data['selected.delimiter'])) {
-        $vars['d'] = $t->data['selected.delimiter'];
+    $vars = [
+        'rule' => $t->data['selected_rule'],
+        'time' => $t->data['selected_time'],
+        'res' => $t->data['selected_timeres'],
+    ];
+    if (isset($t->data['selected_delimiter'])) {
+        $vars['d'] = $t->data['selected_delimiter'];
     }
-    if (!empty($t->data['selected.rule2']) && $t->data['selected.rule2'] !== '_') {
-        $vars['rule2'] = $t->data['selected.rule2'];
+    if (!empty($t->data['selected_rule2']) && $t->data['selected_rule2'] !== '_') {
+        $vars['rule2'] = $t->data['selected_rule2'];
     }
 
     if (isset($key)) {
@@ -154,12 +176,8 @@ function getBaseURL($t, $type = 'get', $key = null, $value = null)
     }
 
     if ($type === 'get') {
-        return SimpleSAML\Module::getModuleURL("statistics/showstats.php") . '?' . http_build_query($vars, '', '&amp;');
-    } else {
-        $text = '';
-        foreach($vars as $k => $v) {
-            $text .= '<input type="hidden" name="' . $k . '" value="'. htmlspecialchars($v) . '" />' . "\n";
-        }
-        return $text;
+        return \SimpleSAML\Module::getModuleURL("statistics/showstats.php").'?'.http_build_query($vars, '', '&amp;');
     }
+
+    return $vars;
 }
diff --git a/modules/statistics/www/statmeta.php b/modules/statistics/www/statmeta.php
index 91a5fe4aa4ad7bdb04884594f1b671250864c7f5..dd252bb26e1b66f21b21e5c63ca3b9067be4c8c3 100644
--- a/modules/statistics/www/statmeta.php
+++ b/modules/statistics/www/statmeta.php
@@ -1,15 +1,15 @@
 <?php
 
-$config = SimpleSAML_Configuration::getInstance();
-$statconfig = SimpleSAML_Configuration::getConfig('module_statistics.php');
+$config = \SimpleSAML\Configuration::getInstance();
+$statconfig = \SimpleSAML\Configuration::getConfig('module_statistics.php');
 
-sspmod_statistics_AccessCheck::checkAccess($statconfig);
+\SimpleSAML\Module\statistics\AccessCheck::checkAccess($statconfig);
 
-$aggr = new sspmod_statistics_Aggregator();
+$aggr = new \SimpleSAML\Module\statistics\Aggregator();
 $aggr->loadMetadata();
 $metadata = $aggr->getMetadata();
 
-$t = new SimpleSAML_XHTML_Template($config, 'statistics:statmeta.tpl.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'statistics:statmeta.tpl.php');
 
 if ($metadata !== null) {
     if (in_array('lastrun', $metadata, true)) {
@@ -25,4 +25,3 @@ if ($metadata !== null) {
 }
 
 $t->show();
-
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..77297bfdcb2ac048121e5eee3fe724ecc4614a6e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "yarn",
+  "version": "1.0.0",
+  "description": "yarn pkgmanager",
+  "main": "index.js",
+  "repository": "https://github.com/simplesamlphp/simplesamlphp",
+  "author": "olimpiam",
+  "license": "MIT",
+  "dependencies": {
+    "clipboard": "^2.0.1",
+    "font-awesome": "^4.7.0",
+    "jquery": "^3.3.1",
+    "jquery-ui": "^1.12.1",
+    "purecss": "^1.0.0",
+    "selectize": "^0.12.6"
+  }
+}
diff --git a/tools/phpunit/phpunit.xml b/phpunit.xml
similarity index 64%
rename from tools/phpunit/phpunit.xml
rename to phpunit.xml
index b82bc2077bff517bf5f5c806da56498b6bf68133..6915e5c0b1ba3648aa2142556c471024390568ec 100644
--- a/tools/phpunit/phpunit.xml
+++ b/phpunit.xml
@@ -8,21 +8,22 @@
          processIsolation="false"
          stopOnFailure="false"
          syntaxCheck="false"
-         bootstrap="./../../tests/bootstrap.php">
+         bootstrap="./tests/bootstrap.php">
     <testsuites>
         <testsuite name="Unit tests">
-            <directory>./../../tests/</directory>
+            <directory>./tests/</directory>
         </testsuite>
     </testsuites>
     <filter>
         <whitelist processUncoveredFilesFromWhitelist="true">
-            <directory suffix=".php">./../../lib/</directory>
-            <directory suffix=".php">./../../modules/consent/lib/</directory>
-            <directory suffix=".php">./../../modules/core/lib/</directory>
-            <directory suffix=".php">./../../modules/saml/lib/</directory>
+            <directory suffix=".php">./lib/</directory>
+            <directory suffix=".php">./modules/consent/lib/</directory>
+            <directory suffix=".php">./modules/core/lib/</directory>
+            <directory suffix=".php">./modules/saml/lib/</directory>
             <exclude>
-                <directory>./../../vendor/</directory>
-                <directory>./../../tests/</directory>
+                <directory>./vendor/</directory>
+                <directory>./tests/</directory>
+                <file>./lib/SimpleSAML/Utils/HttpAdapter.php</file>
             </exclude>
         </whitelist>
     </filter>
diff --git a/psalm.xml b/psalm.xml
index 575f74033ee2f2ee3b0c63ed984e962d179ac302..0ccc8b80b8654966efad5c3df94f7d520c6dc7d9 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -23,6 +23,8 @@
 
         <PropertyNotSetInConstructor errorLevel="info" />
         <MissingConstructor errorLevel="info" />
+        <MissingClosureParamType errorLevel="info" />
+        <MissingParamType errorLevel="info" />
         <UnusedClass errorLevel="info" />
         <PossiblyUnusedMethod errorLevel="info" />
         <UntypedParam errorLevel="info" />
diff --git a/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd b/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd
index dee3a3e261a6a2bb4b64a05b48d4fdf4221b7bbf..1516399bf93cd77f3d129f892c08b8f3094f5988 100644
--- a/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd
+++ b/schemas/oasis-sstc-saml-schema-assertion-1.1.xsd
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <schema targetNamespace="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified" version="1.1">
-	<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd"/>
+	<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
 	<annotation>
 		<documentation>
                 Document identifier: oasis-sstc-saml-schema-assertion-1.1
diff --git a/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd b/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd
index 8bea3a9444e892105c01cb33fa5f41ee153c3199..ea440772588bb1120a8cd281f8d0611c41f43854 100644
--- a/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd
+++ b/schemas/oasis-sstc-saml-schema-protocol-1.1.xsd
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <schema targetNamespace="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified" version="1.1">
 	<import namespace="urn:oasis:names:tc:SAML:1.0:assertion" schemaLocation="oasis-sstc-saml-schema-assertion-1.1.xsd"/>
-	<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd"/>
+	<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
 	<annotation>
 		<documentation>
                 Document identifier: oasis-sstc-saml-schema-protocol-1.1
diff --git a/schemas/saml-schema-assertion-2.0.xsd b/schemas/saml-schema-assertion-2.0.xsd
index 9bbfa26e316d2328666d3ed4b9d530f4fd37aff3..2b2f7b8018a7390584352c42a5db5654d6bd6033 100644
--- a/schemas/saml-schema-assertion-2.0.xsd
+++ b/schemas/saml-schema-assertion-2.0.xsd
@@ -10,9 +10,9 @@
     blockDefault="substitution"
     version="2.0">
     <import namespace="http://www.w3.org/2000/09/xmldsig#"
-        schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
+        schemaLocation="xmldsig-core-schema.xsd"/>
     <import namespace="http://www.w3.org/2001/04/xmlenc#"
-        schemaLocation="http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd"/>
+        schemaLocation="xenc-schema.xsd"/>
     <annotation>
         <documentation>
             Document identifier: saml-schema-assertion-2.0
diff --git a/schemas/saml-schema-metadata-2.0.xsd b/schemas/saml-schema-metadata-2.0.xsd
index 923b598bf890348da4a064762550b3417815ed1c..b656d4f414dcbcac4bb98ccb729af280ea7b2a48 100644
--- a/schemas/saml-schema-metadata-2.0.xsd
+++ b/schemas/saml-schema-metadata-2.0.xsd
@@ -11,13 +11,13 @@
     blockDefault="substitution"
     version="2.0">
     <import namespace="http://www.w3.org/2000/09/xmldsig#"
-        schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
+        schemaLocation="xmldsig-core-schema.xsd"/>
     <import namespace="http://www.w3.org/2001/04/xmlenc#"
-        schemaLocation="http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd"/>
+        schemaLocation="xenc-schema.xsd"/>
     <import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
         schemaLocation="saml-schema-assertion-2.0.xsd"/>
     <import namespace="http://www.w3.org/XML/1998/namespace"
-        schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+        schemaLocation="xml.xsd"/>
     <annotation>
         <documentation>
             Document identifier: saml-schema-metadata-2.0
diff --git a/schemas/saml-schema-protocol-2.0.xsd b/schemas/saml-schema-protocol-2.0.xsd
index 13656b18ae222ce83d2d2a7973ccacd6133bc693..7fa6f489d684a7375e0581bcf53ca9e34a4e6d10 100644
--- a/schemas/saml-schema-protocol-2.0.xsd
+++ b/schemas/saml-schema-protocol-2.0.xsd
@@ -12,7 +12,7 @@
     <import namespace="urn:oasis:names:tc:SAML:2.0:assertion"
         schemaLocation="saml-schema-assertion-2.0.xsd"/>
     <import namespace="http://www.w3.org/2000/09/xmldsig#"
-        schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd"/>
+        schemaLocation="xmldsig-core-schema.xsd"/>
     <annotation>
         <documentation>
             Document identifier: saml-schema-protocol-2.0
diff --git a/schemas/xenc-schema.xsd b/schemas/xenc-schema.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..d61229fd50c3da59409a86aebbee2ca83df4cb58
--- /dev/null
+++ b/schemas/xenc-schema.xsd
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE schema  PUBLIC "-//W3C//DTD XMLSchema 200102//EN"
+ "http://www.w3.org/2001/XMLSchema.dtd"
+ [
+   <!ATTLIST schema
+     xmlns:xenc CDATA #FIXED 'http://www.w3.org/2001/04/xmlenc#'
+     xmlns:ds CDATA #FIXED 'http://www.w3.org/2000/09/xmldsig#'>
+   <!ENTITY xenc 'http://www.w3.org/2001/04/xmlenc#'>
+   <!ENTITY % p ''>
+   <!ENTITY % s ''>
+  ]>
+
+<schema xmlns='http://www.w3.org/2001/XMLSchema' version='1.0'
+        xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'
+        xmlns:ds='http://www.w3.org/2000/09/xmldsig#'
+        targetNamespace='http://www.w3.org/2001/04/xmlenc#'
+        elementFormDefault='qualified'>
+
+  <import namespace='http://www.w3.org/2000/09/xmldsig#'
+          schemaLocation='xmldsig-core-schema.xsd'/>
+
+  <complexType name='EncryptedType' abstract='true'>
+    <sequence>
+      <element name='EncryptionMethod' type='xenc:EncryptionMethodType'
+       minOccurs='0'/>
+      <element ref='ds:KeyInfo' minOccurs='0'/>
+      <element ref='xenc:CipherData'/>
+      <element ref='xenc:EncryptionProperties' minOccurs='0'/>
+    </sequence>
+    <attribute name='Id' type='ID' use='optional'/>
+    <attribute name='Type' type='anyURI' use='optional'/>
+    <attribute name='MimeType' type='string' use='optional'/>
+    <attribute name='Encoding' type='anyURI' use='optional'/>
+  </complexType>
+  
+  <complexType name='EncryptionMethodType' mixed='true'>
+    <sequence>
+      <element name='KeySize' minOccurs='0' type='xenc:KeySizeType'/>
+      <element name='OAEPparams' minOccurs='0' type='base64Binary'/>
+      <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
+    </sequence>
+    <attribute name='Algorithm' type='anyURI' use='required'/>
+  </complexType>
+
+    <simpleType name='KeySizeType'>
+      <restriction base="integer"/>
+    </simpleType>
+
+  <element name='CipherData' type='xenc:CipherDataType'/>
+  <complexType name='CipherDataType'>
+     <choice>
+       <element name='CipherValue' type='base64Binary'/>
+       <element ref='xenc:CipherReference'/>
+     </choice>
+    </complexType>
+
+   <element name='CipherReference' type='xenc:CipherReferenceType'/>
+   <complexType name='CipherReferenceType'>
+       <choice>
+         <element name='Transforms' type='xenc:TransformsType' minOccurs='0'/>
+       </choice>
+       <attribute name='URI' type='anyURI' use='required'/>
+   </complexType>
+
+     <complexType name='TransformsType'>
+       <sequence>
+         <element ref='ds:Transform' maxOccurs='unbounded'/>
+       </sequence>
+     </complexType>
+
+
+  <element name='EncryptedData' type='xenc:EncryptedDataType'/>
+  <complexType name='EncryptedDataType'>
+    <complexContent>
+      <extension base='xenc:EncryptedType'>
+       </extension>
+    </complexContent>
+  </complexType>
+
+  <!-- Children of ds:KeyInfo -->
+
+  <element name='EncryptedKey' type='xenc:EncryptedKeyType'/>
+  <complexType name='EncryptedKeyType'>
+    <complexContent>
+      <extension base='xenc:EncryptedType'>
+        <sequence>
+          <element ref='xenc:ReferenceList' minOccurs='0'/>
+          <element name='CarriedKeyName' type='string' minOccurs='0'/>
+        </sequence>
+        <attribute name='Recipient' type='string'
+         use='optional'/>
+      </extension>
+    </complexContent>
+  </complexType>
+
+    <element name="AgreementMethod" type="xenc:AgreementMethodType"/>
+    <complexType name="AgreementMethodType" mixed="true">
+      <sequence>
+        <element name="KA-Nonce" minOccurs="0" type="base64Binary"/>
+        <!-- <element ref="ds:DigestMethod" minOccurs="0"/> -->
+        <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+        <element name="OriginatorKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
+        <element name="RecipientKeyInfo" minOccurs="0" type="ds:KeyInfoType"/>
+      </sequence>
+      <attribute name="Algorithm" type="anyURI" use="required"/>
+    </complexType>
+
+  <!-- End Children of ds:KeyInfo -->
+
+  <element name='ReferenceList'>
+    <complexType>
+      <choice minOccurs='1' maxOccurs='unbounded'>
+        <element name='DataReference' type='xenc:ReferenceType'/>
+        <element name='KeyReference' type='xenc:ReferenceType'/>
+      </choice>
+    </complexType>
+  </element>
+
+  <complexType name='ReferenceType'>
+    <sequence>
+      <any namespace='##other' minOccurs='0' maxOccurs='unbounded'/>
+    </sequence>
+    <attribute name='URI' type='anyURI' use='required'/>
+  </complexType>
+
+
+  <element name='EncryptionProperties' type='xenc:EncryptionPropertiesType'/>
+  <complexType name='EncryptionPropertiesType'>
+    <sequence>
+      <element ref='xenc:EncryptionProperty' maxOccurs='unbounded'/>
+    </sequence>
+    <attribute name='Id' type='ID' use='optional'/>
+  </complexType>
+
+    <element name='EncryptionProperty' type='xenc:EncryptionPropertyType'/>
+    <complexType name='EncryptionPropertyType' mixed='true'>
+      <choice maxOccurs='unbounded'>
+        <any namespace='##other' processContents='lax'/>
+      </choice>
+      <attribute name='Target' type='anyURI' use='optional'/>
+      <attribute name='Id' type='ID' use='optional'/>
+      <anyAttribute namespace="http://www.w3.org/XML/1998/namespace"/>
+    </complexType>
+
+</schema>
+
diff --git a/schemas/xml.xsd b/schemas/xml.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..aea7d0db0a423b962247aa2b4d3d48fc73cda659
--- /dev/null
+++ b/schemas/xml.xsd
@@ -0,0 +1,287 @@
+<?xml version='1.0'?>
+<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
+<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" 
+  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
+  xmlns   ="http://www.w3.org/1999/xhtml"
+  xml:lang="en">
+
+ <xs:annotation>
+  <xs:documentation>
+   <div>
+    <h1>About the XML namespace</h1>
+
+    <div class="bodytext">
+     <p>
+      This schema document describes the XML namespace, in a form
+      suitable for import by other schema documents.
+     </p>
+     <p>
+      See <a href="http://www.w3.org/XML/1998/namespace.html">
+      http://www.w3.org/XML/1998/namespace.html</a> and
+      <a href="http://www.w3.org/TR/REC-xml">
+      http://www.w3.org/TR/REC-xml</a> for information 
+      about this namespace.
+     </p>
+     <p>
+      Note that local names in this namespace are intended to be
+      defined only by the World Wide Web Consortium or its subgroups.
+      The names currently defined in this namespace are listed below.
+      They should not be used with conflicting semantics by any Working
+      Group, specification, or document instance.
+     </p>
+     <p>   
+      See further below in this document for more information about <a
+      href="#usage">how to refer to this schema document from your own
+      XSD schema documents</a> and about <a href="#nsversioning">the
+      namespace-versioning policy governing this schema document</a>.
+     </p>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:attribute name="lang">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>lang (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose value
+       is a language code for the natural language of the content of
+       any element; its value is inherited.  This name is reserved
+       by virtue of its definition in the XML specification.</p>
+     
+    </div>
+    <div>
+     <h4>Notes</h4>
+     <p>
+      Attempting to install the relevant ISO 2- and 3-letter
+      codes as the enumerated possible values is probably never
+      going to be a realistic possibility.  
+     </p>
+     <p>
+      See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
+       http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
+      and the IANA language subtag registry at
+      <a href="http://www.iana.org/assignments/language-subtag-registry">
+       http://www.iana.org/assignments/language-subtag-registry</a>
+      for further information.
+     </p>
+     <p>
+      The union allows for the 'un-declaration' of xml:lang with
+      the empty string.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+  <xs:simpleType>
+   <xs:union memberTypes="xs:language">
+    <xs:simpleType>    
+     <xs:restriction base="xs:string">
+      <xs:enumeration value=""/>
+     </xs:restriction>
+    </xs:simpleType>
+   </xs:union>
+  </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="space">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>space (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose
+       value is a keyword indicating what whitespace processing
+       discipline is intended for the content of the element; its
+       value is inherited.  This name is reserved by virtue of its
+       definition in the XML specification.</p>
+     
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+  <xs:simpleType>
+   <xs:restriction base="xs:NCName">
+    <xs:enumeration value="default"/>
+    <xs:enumeration value="preserve"/>
+   </xs:restriction>
+  </xs:simpleType>
+ </xs:attribute>
+ 
+ <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>base (as an attribute name)</h3>
+      <p>
+       denotes an attribute whose value
+       provides a URI to be used as the base for interpreting any
+       relative URIs in the scope of the element on which it
+       appears; its value is inherited.  This name is reserved
+       by virtue of its definition in the XML Base specification.</p>
+     
+     <p>
+      See <a
+      href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
+      for information about this attribute.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+ 
+ <xs:attribute name="id" type="xs:ID">
+  <xs:annotation>
+   <xs:documentation>
+    <div>
+     
+      <h3>id (as an attribute name)</h3> 
+      <p>
+       denotes an attribute whose value
+       should be interpreted as if declared to be of type ID.
+       This name is reserved by virtue of its definition in the
+       xml:id specification.</p>
+     
+     <p>
+      See <a
+      href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
+      for information about this attribute.
+     </p>
+    </div>
+   </xs:documentation>
+  </xs:annotation>
+ </xs:attribute>
+
+ <xs:attributeGroup name="specialAttrs">
+  <xs:attribute ref="xml:base"/>
+  <xs:attribute ref="xml:lang"/>
+  <xs:attribute ref="xml:space"/>
+  <xs:attribute ref="xml:id"/>
+ </xs:attributeGroup>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div>
+   
+    <h3>Father (in any context at all)</h3> 
+
+    <div class="bodytext">
+     <p>
+      denotes Jon Bosak, the chair of 
+      the original XML Working Group.  This name is reserved by 
+      the following decision of the W3C XML Plenary and 
+      XML Coordination groups:
+     </p>
+     <blockquote>
+       <p>
+	In appreciation for his vision, leadership and
+	dedication the W3C XML Plenary on this 10th day of
+	February, 2000, reserves for Jon Bosak in perpetuity
+	the XML name "xml:Father".
+       </p>
+     </blockquote>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div xml:id="usage" id="usage">
+    <h2><a name="usage">About this schema document</a></h2>
+
+    <div class="bodytext">
+     <p>
+      This schema defines attributes and an attribute group suitable
+      for use by schemas wishing to allow <code>xml:base</code>,
+      <code>xml:lang</code>, <code>xml:space</code> or
+      <code>xml:id</code> attributes on elements they define.
+     </p>
+     <p>
+      To enable this, such a schema must import this schema for
+      the XML namespace, e.g. as follows:
+     </p>
+     <pre>
+          &lt;schema . . .>
+           . . .
+           &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     </pre>
+     <p>
+      or
+     </p>
+     <pre>
+           &lt;import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     </pre>
+     <p>
+      Subsequently, qualified reference to any of the attributes or the
+      group defined below will have the desired effect, e.g.
+     </p>
+     <pre>
+          &lt;type . . .>
+           . . .
+           &lt;attributeGroup ref="xml:specialAttrs"/>
+     </pre>
+     <p>
+      will define a type which will schema-validate an instance element
+      with any of those attributes.
+     </p>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+ <xs:annotation>
+  <xs:documentation>
+   <div id="nsversioning" xml:id="nsversioning">
+    <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
+    <div class="bodytext">
+     <p>
+      In keeping with the XML Schema WG's standard versioning
+      policy, this schema document will persist at
+      <a href="http://www.w3.org/2009/01/xml.xsd">
+       http://www.w3.org/2009/01/xml.xsd</a>.
+     </p>
+     <p>
+      At the date of issue it can also be found at
+      <a href="http://www.w3.org/2001/xml.xsd">
+       http://www.w3.org/2001/xml.xsd</a>.
+     </p>
+     <p>
+      The schema document at that URI may however change in the future,
+      in order to remain compatible with the latest version of XML
+      Schema itself, or with the XML namespace itself.  In other words,
+      if the XML Schema or XML namespaces change, the version of this
+      document at <a href="http://www.w3.org/2001/xml.xsd">
+       http://www.w3.org/2001/xml.xsd 
+      </a> 
+      will change accordingly; the version at 
+      <a href="http://www.w3.org/2009/01/xml.xsd">
+       http://www.w3.org/2009/01/xml.xsd 
+      </a> 
+      will not change.
+     </p>
+     <p>
+      Previous dated (and unchanging) versions of this schema 
+      document are at:
+     </p>
+     <ul>
+      <li><a href="http://www.w3.org/2009/01/xml.xsd">
+	http://www.w3.org/2009/01/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2007/08/xml.xsd">
+	http://www.w3.org/2007/08/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2004/10/xml.xsd">
+	http://www.w3.org/2004/10/xml.xsd</a></li>
+      <li><a href="http://www.w3.org/2001/03/xml.xsd">
+	http://www.w3.org/2001/03/xml.xsd</a></li>
+     </ul>
+    </div>
+   </div>
+  </xs:documentation>
+ </xs:annotation>
+
+</xs:schema>
+
diff --git a/schemas/xmldsig-core-schema.xsd b/schemas/xmldsig-core-schema.xsd
new file mode 100644
index 0000000000000000000000000000000000000000..df126b30e684091b32a748cd2e408f5fb9d651a9
--- /dev/null
+++ b/schemas/xmldsig-core-schema.xsd
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE schema
+  PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd"
+ [
+   <!ATTLIST schema 
+     xmlns:ds CDATA #FIXED "http://www.w3.org/2000/09/xmldsig#">
+   <!ENTITY dsig 'http://www.w3.org/2000/09/xmldsig#'>
+   <!ENTITY % p ''>
+   <!ENTITY % s ''>
+  ]>
+
+<!-- Schema for XML Signatures
+    http://www.w3.org/2000/09/xmldsig#
+    $Revision: 1.1 $ on $Date: 2002/02/08 20:32:26 $ by $Author: reagle $
+
+    Copyright 2001 The Internet Society and W3C (Massachusetts Institute
+    of Technology, Institut National de Recherche en Informatique et en
+    Automatique, Keio University). All Rights Reserved.
+    http://www.w3.org/Consortium/Legal/
+
+    This document is governed by the W3C Software License [1] as described
+    in the FAQ [2].
+
+    [1] http://www.w3.org/Consortium/Legal/copyright-software-19980720
+    [2] http://www.w3.org/Consortium/Legal/IPR-FAQ-20000620.html#DTD
+-->
+
+
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+        xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+        targetNamespace="http://www.w3.org/2000/09/xmldsig#"
+        version="0.1" elementFormDefault="qualified"> 
+
+<!-- Basic Types Defined for Signatures -->
+
+<simpleType name="CryptoBinary">
+  <restriction base="base64Binary">
+  </restriction>
+</simpleType>
+
+<!-- Start Signature -->
+
+<element name="Signature" type="ds:SignatureType"/>
+<complexType name="SignatureType">
+  <sequence> 
+    <element ref="ds:SignedInfo"/> 
+    <element ref="ds:SignatureValue"/> 
+    <element ref="ds:KeyInfo" minOccurs="0"/> 
+    <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> 
+  </sequence>  
+  <attribute name="Id" type="ID" use="optional"/>
+</complexType>
+
+  <element name="SignatureValue" type="ds:SignatureValueType"/> 
+  <complexType name="SignatureValueType">
+    <simpleContent>
+      <extension base="base64Binary">
+        <attribute name="Id" type="ID" use="optional"/>
+      </extension>
+    </simpleContent>
+  </complexType>
+
+<!-- Start SignedInfo -->
+
+<element name="SignedInfo" type="ds:SignedInfoType"/>
+<complexType name="SignedInfoType">
+  <sequence> 
+    <element ref="ds:CanonicalizationMethod"/> 
+    <element ref="ds:SignatureMethod"/> 
+    <element ref="ds:Reference" maxOccurs="unbounded"/> 
+  </sequence>  
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+  <element name="CanonicalizationMethod" type="ds:CanonicalizationMethodType"/> 
+  <complexType name="CanonicalizationMethodType" mixed="true">
+    <sequence>
+      <any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
+      <!-- (0,unbounded) elements from (1,1) namespace -->
+    </sequence>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+  <element name="SignatureMethod" type="ds:SignatureMethodType"/>
+  <complexType name="SignatureMethodType" mixed="true">
+    <sequence>
+      <element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
+      <any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
+      <!-- (0,unbounded) elements from (1,1) external namespace -->
+    </sequence>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+<!-- Start Reference -->
+
+<element name="Reference" type="ds:ReferenceType"/>
+<complexType name="ReferenceType">
+  <sequence> 
+    <element ref="ds:Transforms" minOccurs="0"/> 
+    <element ref="ds:DigestMethod"/> 
+    <element ref="ds:DigestValue"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+  <attribute name="URI" type="anyURI" use="optional"/> 
+  <attribute name="Type" type="anyURI" use="optional"/> 
+</complexType>
+
+  <element name="Transforms" type="ds:TransformsType"/>
+  <complexType name="TransformsType">
+    <sequence>
+      <element ref="ds:Transform" maxOccurs="unbounded"/>  
+    </sequence>
+  </complexType>
+
+  <element name="Transform" type="ds:TransformType"/>
+  <complexType name="TransformType" mixed="true">
+    <choice minOccurs="0" maxOccurs="unbounded"> 
+      <any namespace="##other" processContents="lax"/>
+      <!-- (1,1) elements from (0,unbounded) namespaces -->
+      <element name="XPath" type="string"/> 
+    </choice>
+    <attribute name="Algorithm" type="anyURI" use="required"/> 
+  </complexType>
+
+<!-- End Reference -->
+
+<element name="DigestMethod" type="ds:DigestMethodType"/>
+<complexType name="DigestMethodType" mixed="true"> 
+  <sequence>
+    <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
+  </sequence>    
+  <attribute name="Algorithm" type="anyURI" use="required"/> 
+</complexType>
+
+<element name="DigestValue" type="ds:DigestValueType"/>
+<simpleType name="DigestValueType">
+  <restriction base="base64Binary"/>
+</simpleType>
+
+<!-- End SignedInfo -->
+
+<!-- Start KeyInfo -->
+
+<element name="KeyInfo" type="ds:KeyInfoType"/> 
+<complexType name="KeyInfoType" mixed="true">
+  <choice maxOccurs="unbounded">     
+    <element ref="ds:KeyName"/> 
+    <element ref="ds:KeyValue"/> 
+    <element ref="ds:RetrievalMethod"/> 
+    <element ref="ds:X509Data"/> 
+    <element ref="ds:PGPData"/> 
+    <element ref="ds:SPKIData"/>
+    <element ref="ds:MgmtData"/>
+    <any processContents="lax" namespace="##other"/>
+    <!-- (1,1) elements from (0,unbounded) namespaces -->
+  </choice>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+  <element name="KeyName" type="string"/>
+  <element name="MgmtData" type="string"/>
+
+  <element name="KeyValue" type="ds:KeyValueType"/> 
+  <complexType name="KeyValueType" mixed="true">
+   <choice>
+     <element ref="ds:DSAKeyValue"/>
+     <element ref="ds:RSAKeyValue"/>
+     <any namespace="##other" processContents="lax"/>
+   </choice>
+  </complexType>
+
+  <element name="RetrievalMethod" type="ds:RetrievalMethodType"/> 
+  <complexType name="RetrievalMethodType">
+    <sequence>
+      <element ref="ds:Transforms" minOccurs="0"/> 
+    </sequence>  
+    <attribute name="URI" type="anyURI"/>
+    <attribute name="Type" type="anyURI" use="optional"/>
+  </complexType>
+
+<!-- Start X509Data -->
+
+<element name="X509Data" type="ds:X509DataType"/> 
+<complexType name="X509DataType">
+  <sequence maxOccurs="unbounded">
+    <choice>
+      <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
+      <element name="X509SKI" type="base64Binary"/>
+      <element name="X509SubjectName" type="string"/>
+      <element name="X509Certificate" type="base64Binary"/>
+      <element name="X509CRL" type="base64Binary"/>
+      <any namespace="##other" processContents="lax"/>
+    </choice>
+  </sequence>
+</complexType>
+
+<complexType name="X509IssuerSerialType"> 
+  <sequence> 
+    <element name="X509IssuerName" type="string"/> 
+    <element name="X509SerialNumber" type="integer"/> 
+  </sequence>
+</complexType>
+
+<!-- End X509Data -->
+
+<!-- Begin PGPData -->
+
+<element name="PGPData" type="ds:PGPDataType"/> 
+<complexType name="PGPDataType"> 
+  <choice>
+    <sequence>
+      <element name="PGPKeyID" type="base64Binary"/> 
+      <element name="PGPKeyPacket" type="base64Binary" minOccurs="0"/> 
+      <any namespace="##other" processContents="lax" minOccurs="0"
+       maxOccurs="unbounded"/>
+    </sequence>
+    <sequence>
+      <element name="PGPKeyPacket" type="base64Binary"/> 
+      <any namespace="##other" processContents="lax" minOccurs="0"
+       maxOccurs="unbounded"/>
+    </sequence>
+  </choice>
+</complexType>
+
+<!-- End PGPData -->
+
+<!-- Begin SPKIData -->
+
+<element name="SPKIData" type="ds:SPKIDataType"/> 
+<complexType name="SPKIDataType">
+  <sequence maxOccurs="unbounded">
+    <element name="SPKISexp" type="base64Binary"/>
+    <any namespace="##other" processContents="lax" minOccurs="0"/>
+  </sequence>
+</complexType> 
+
+<!-- End SPKIData -->
+
+<!-- End KeyInfo -->
+
+<!-- Start Object (Manifest, SignatureProperty) -->
+
+<element name="Object" type="ds:ObjectType"/> 
+<complexType name="ObjectType" mixed="true">
+  <sequence minOccurs="0" maxOccurs="unbounded">
+    <any namespace="##any" processContents="lax"/>
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+  <attribute name="MimeType" type="string" use="optional"/> <!-- add a grep facet -->
+  <attribute name="Encoding" type="anyURI" use="optional"/> 
+</complexType>
+
+<element name="Manifest" type="ds:ManifestType"/> 
+<complexType name="ManifestType">
+  <sequence>
+    <element ref="ds:Reference" maxOccurs="unbounded"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+<element name="SignatureProperties" type="ds:SignaturePropertiesType"/> 
+<complexType name="SignaturePropertiesType">
+  <sequence>
+    <element ref="ds:SignatureProperty" maxOccurs="unbounded"/> 
+  </sequence>
+  <attribute name="Id" type="ID" use="optional"/> 
+</complexType>
+
+   <element name="SignatureProperty" type="ds:SignaturePropertyType"/> 
+   <complexType name="SignaturePropertyType" mixed="true">
+     <choice maxOccurs="unbounded">
+       <any namespace="##other" processContents="lax"/>
+       <!-- (1,1) elements from (1,unbounded) namespaces -->
+     </choice>
+     <attribute name="Target" type="anyURI" use="required"/> 
+     <attribute name="Id" type="ID" use="optional"/> 
+   </complexType>
+
+<!-- End Object (Manifest, SignatureProperty) -->
+
+<!-- Start Algorithm Parameters -->
+
+<simpleType name="HMACOutputLengthType">
+  <restriction base="integer"/>
+</simpleType>
+
+<!-- Start KeyValue Element-types -->
+
+<element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
+<complexType name="DSAKeyValueType">
+  <sequence>
+    <sequence minOccurs="0">
+      <element name="P" type="ds:CryptoBinary"/>
+      <element name="Q" type="ds:CryptoBinary"/>
+    </sequence>
+    <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
+    <element name="Y" type="ds:CryptoBinary"/>
+    <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
+    <sequence minOccurs="0">
+      <element name="Seed" type="ds:CryptoBinary"/>
+      <element name="PgenCounter" type="ds:CryptoBinary"/>
+    </sequence>
+  </sequence>
+</complexType>
+
+<element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
+<complexType name="RSAKeyValueType">
+  <sequence>
+    <element name="Modulus" type="ds:CryptoBinary"/> 
+    <element name="Exponent" type="ds:CryptoBinary"/> 
+  </sequence>
+</complexType> 
+
+<!-- End KeyValue Element-types -->
+
+<!-- End Signature -->
+
+</schema>
diff --git a/templates/IFrameLogoutHandler.twig b/templates/IFrameLogoutHandler.twig
new file mode 100644
index 0000000000000000000000000000000000000000..ad4d4a69856df57610541a23844c1d6f8046f667
--- /dev/null
+++ b/templates/IFrameLogoutHandler.twig
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Logout response from {{ assocId|escape('html') }}</title>
+        <script>
+{% if errorMsg is defined %}
+            window.parent.logoutFailed("{{ spId }}", "{{ errorMsg|escape }}");
+{% else %}
+            window.parent.logoutCompleted("{{ spId }}");
+{% endif %}
+        </script>
+    </head>
+    <body>
+    </body>
+</html>
+
diff --git a/templates/_footer.twig b/templates/_footer.twig
index f789441c151aca1a93b009605cfe2fba765fe1a2..432e1daef212cf028e84b84318bf77fe0a9f4dc5 100644
--- a/templates/_footer.twig
+++ b/templates/_footer.twig
@@ -1,6 +1,13 @@
-    <hr>
-
-    <img src="/{{ baseurlpath }}resources/icons/ssplogo-fish-small.png" alt="Small fish logo" style="float: right">
-    Copyright © 2007-2016 <a href="http://uninett.no/">UNINETT AS</a>
-
-    <br style="clear: right">
+        <div id="footer">
+            <div class="wrap">
+                <div class="center copyrights dark-bg">
+                    <br>Copyright © 2007-2018
+                    <a href="https://simplesamlphp.org/">SimpleSAMLphp</a>
+                </div>
+                <div class="logo-footer-right">
+                    <div class="logo-footer">
+                        <img class="pure-img" src="/{{ baseurlpath }}resources/icons/ssplogo-fish-small.png" alt="Small fish logo">
+                    </div>
+                </div>
+            </div>
+        </div>
diff --git a/templates/_header.twig b/templates/_header.twig
index 461dfd25d1b2eacd5ea6d27d908728972f116b59..7158b0b96fc3875fad99f2d3968d3fbc2cf03b0d 100644
--- a/templates/_header.twig
+++ b/templates/_header.twig
@@ -1,22 +1,72 @@
-<div id="header">
-    <h1><a style="text-decoration: none; color: white" href="/{{ baseurlpath }}">{{ pagetitle }}</a></h1>
-</div>
+        <div id="header">
+            <div class="wrap">
+                <div class="left">
+                    <div class="v-center logo-header">
+                        <div id="logo">
+                            <span class="simple">Simple</span><span class="saml">SAML</span><span class="simple">php</span>
+                            <img class="pure-img hidden" src="" alt="LOGO">
+                        </div>
+                    </div>
+                </div>
+                <div class="right">
+                    <a href="#menu" id="menuLink" class="menu-link hide-for-large">
+                        <!-- Hamburger icon -->
+                        <span class="fa fa-language fa-2x" aria-hidden="true"></span>
+                    </a>
+                </div>
 
-{% if not hideLanguageBar %}
-<div id="languagebar">
-    {% for lang in languageBar %}
-        {%- if not loop.first -%}|{% endif -%}
-        {% if lang.url %}
-            <a href="{{ lang.url -}}
-            {%- if queryParams %}&{% endif -%}
-            {%- for name, value in queryParams -%}
-                {%- if not loop.first %}&{% endif -%}
-                {%- if value %}{{ name }}={{ value }}{% else %}{{ name }}{% endif -%}
-            {%- endfor %}">{{ lang.name }}</a>
-        {% else %}
-            {{ lang.name }}
-        {% endif %}
+                {% if not hideLanguageBar -%}
+                    <div id="languagebar">
+                        <div id="menu">
+                            <div class="pure-menu">
+                                <ul class="pure-menu-list">
+                                {% for key, lang in languageBar -%}
+                                    {% if key == currentLanguage -%}
+                                    <li><a class="pure-menu-heading" href="#">{{ lang.name }}</a><li>
+                                    {% else -%}
+                                    {% if lang.url -%}
+                                    <li class="pure-menu-item"><a href="{{ lang.url }}{%- spaceless %}
+                                        {% if queryParams -%}&{% endif -%}
+                                        {% for name, value in queryParams -%}
+                                            {%- if not loop.first %}&{% endif -%}
+                                            {%- if value %}{{ name }}={{ value }}{% else %}{{ name }}{%- endif %}
+                                        {%- endfor %}"{% endspaceless %} class="pure-menu-link">{{ lang.name }}</a></li>
+                                    {% endif -%}
+                                {% endif -%}
+                            {% endfor -%}
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                {%- endif %}
+
+                <div class="right show-for-large">
+                    <div class="v-center language-bar">
+                        <form id="SelectLang" class="pure-form" method="get">
+                            {% if not hideLanguageBar -%}
+                            <div id="languagebar">
+                            {% for name, value in queryParams -%}
+                                {% if value -%}
+                                <input type="hidden" name="{{ name }}" value="{{ value }}" />
+                                {%- else -%}
+                                <input type="hidden" name="{{ name }}" />
+                                {%- endif -%}
+                            {%- endfor %}
+
+                                <select  class="pure-input-1-4 language-menu selectize" name="language" id="language_selector">
+                                    {% for key, lang in languageBar -%}
+                                    {% if key == currentLanguage -%}
+                                    <option value="{{ key }}" selected="selected">&#xf1ab;  {{ lang.name }}</option>
+                                    {% else -%}
+                                    <option value="{{ key }}">{{ lang.name }}</option>
+                                    {% endif -%}
+                                {% endfor -%}
+                                </select>
+                            </div>
+                        {% endif -%}
+                        </form>
+                    </div> <!--language-bar-->
+                </div><!--show-for-large-->
+            </div> <!-- wrap -->
+        </div> <!-- header -->
 
-    {% endfor %}
-</div>
-{% endif %}
diff --git a/templates/_table.twig b/templates/_table.twig
new file mode 100644
index 0000000000000000000000000000000000000000..6af434995d808f3d2ca72ff0f279d6a94b91fcd5
--- /dev/null
+++ b/templates/_table.twig
@@ -0,0 +1,24 @@
+
+<table id="table_with_attributes" class="attributes pure-table pure-table-striped pure-table-attributes" summary="attribute overview">
+
+{% for name, values in items %}
+    <tr class="{{ cycle(['odd', 'even'], loop.index0) }}">
+        {% block namecol -%}
+            <td class="attrname">{{ name }}</td>
+        {%- endblock %}
+
+        <td class="attrvalue">{% spaceless %}
+                {% for value in values %}
+                    {% if loop.length>1 and loop.first %}<ul>{% endif %}
+                    {% if loop.length>1 %}<li>{% endif -%}
+
+                    {% block value %}{% endblock %}
+
+                    {% if loop.length>1 %}</li>{% endif %}
+                    {% if loop.length>1 and loop.last %}</ul>{% endif %}
+                {% endfor %}
+            {% endspaceless -%}
+        </td>
+    </tr>
+{% endfor %}
+</table><br>
diff --git a/templates/attributequery.php b/templates/attributequery.php
index cdad3a86c6d42c34f9686abaf0e143f85f24c567..996d59edb3eefd80f1e5008de7d468289b25fe50 100644
--- a/templates/attributequery.php
+++ b/templates/attributequery.php
@@ -19,11 +19,8 @@ assert(is_string($nameIdQualifier));
 $nameIdSPQualifier = $this->data['nameIdSPQualifier'];
 assert(is_string($nameIdSPQualifier));
 
-
 $attributes = $this->data['attributes'];
 assert($attributes === null || is_array($attributes));
-
-
 ?>
 
 <h2>Attribute query test</h2>
@@ -64,17 +61,16 @@ assert($attributes === null || is_array($attributes));
 </form>
 
 <?php
-if ($attributes !== NULL) {
-
-	echo('<h3>Attributes received</h3><dl>');
-	foreach ($attributes as $name => $values) {
-		echo('<dt>' . htmlspecialchars($name) . '</dt><dd><ul>');
-		foreach ($values as $value) {
-			echo('<li>' . htmlspecialchars($value) . '</li>');
-		}
-		echo('</dd>');
-	}
-	echo('</dl>');
+if ($attributes !== null) {
+    echo '<h3>Attributes received</h3><dl>';
+    foreach ($attributes as $name => $values) {
+        echo '<dt>'.htmlspecialchars($name).'</dt><dd><ul>';
+        foreach ($values as $value) {
+            echo '<li>'.htmlspecialchars($value).'</li>';
+        }
+        echo '</dd>';
+    }
+    echo '</dl>';
 }
 ?>
 
diff --git a/templates/auth_status.twig b/templates/auth_status.twig
new file mode 100644
index 0000000000000000000000000000000000000000..a36cb7623d17b9913e665c0b68e8f710de79c2c3
--- /dev/null
+++ b/templates/auth_status.twig
@@ -0,0 +1,82 @@
+{% set pagetitle = 'Authentication status'|trans %}
+{% extends 'base.twig' %}
+
+{% block content %}
+<h2>{{ pagetitle }}</h2>
+
+    <p>{% trans %}Hi, this is the status page of SimpleSAMLphp. Here you can see if your session is timed out, how long it lasts until it times out and all the attributes that are attached to your session.{% endtrans %}</p>
+
+{% if remaining %}
+    <p>{% trans %}Your session is valid for {{ remaining }} seconds from now.{% endtrans %}</p>
+{% endif %}
+
+
+<h2>{{ 'Your attributes'|trans }}</h2>
+    {% set items = attributes %}
+
+{% embed '_table.twig' -%}
+
+    {% block namecol -%}
+    {% set attr = ('{attributes:attribute_'~(name|lower)~'}') %}
+    {% set translated = attr|trans %}
+    <td class="attrname">{% if translated != attr %} {{ translated }} <br>{% endif %} <samp>{{ name }}</samp></td>
+    {% endblock %}
+
+
+    {% block value -%}
+    {% if name =='jpegPhoto'-%}
+        <img src="data:image/jpeg;base64,{{ value }}" />
+    {% else %}{{ value }}{% endif -%}
+    {% endblock %}
+
+{%- endembed %}
+
+
+{% if nameid %}
+    <h2>{{ 'SAML Subject'|trans }}</h2>
+
+    {%  set items = {'NameId' : nameid.value} %}
+
+    {% if not nameid.value %}
+        {%  set items = items|merge({'NameId' : 'not set'|trans}) %}
+    {% endif %}
+
+    {% if nameid.Format %}
+        {% set items = items|merge({('Format'|trans) : nameid.Format}) %}
+    {% endif %}
+
+    {% if nameid.NameQualifier %}
+        {% set items = items|merge({'NameQualifier' : nameid.NameQualifier}) %}
+    {% endif %}
+
+    {% if nameid.SPNameQualifier %}
+        {% set items = items|merge({'SPNameQualifier' : nameid.SPNameQualifier}) %}
+    {% endif %}
+
+    {% if nameid.SPProvidedID %}
+        {% set items = items|merge({'SPProvidedID' : nameid.SPProvidedID}) %}
+    {% endif %}
+
+    <table id="table_with_attributes"  class="attributes pure-table pure-table-striped pure-table-attributes" summary="attribute overview">
+        {% for name, value in items %}
+            <tr class="{{ cycle(['odd', 'even'], loop.index0) }}">
+                <td class="attrname">{{ name }}</td>
+                <td class="attrname">{{ value }}</td>
+            </tr>
+        {% endfor %}
+    </table><br>
+
+{% endif %}
+
+
+{% if logout %}
+    <h2>{% trans %}Logout{% endtrans %}</h2>
+    <p> {{ logout }}</p>
+{% endif %}
+
+{% if logouturl %}
+    <div class="center">
+        <a class="pure-button pure-button-red" href="{{ logouturl }}">{{ 'Logout'|trans }}</a>
+    </div>
+{% endif %}
+{% endblock %}
diff --git a/templates/base.twig b/templates/base.twig
index 249cb2e23c1aaf14d11f43179e46f1fc7f8a1a7f..e366f37522b22418abf8947615ba2f587e22dfa3 100644
--- a/templates/base.twig
+++ b/templates/base.twig
@@ -4,50 +4,55 @@
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     <meta name="viewport" content="initial-scale=1.0">
     <title>{{ pagetitle }}</title>
-    <link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}resources/default.css">
+    <link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}assets/css/lib/pure-min.css">
+    <link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}assets/css/lib/selectize.default.css">
+    <link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}assets/css/lib/font-awesome/css/font-awesome.css">
+    <link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}assets/css/src/default.css">
     <link rel="icon" type="image/icon" href="/{{ baseurlpath }}resources/icons/favicon.ico">
     {% if jquery and jquery.css %}
     <link rel="stylesheet" media="screen" type="text/css" href="/{{ baseurlpath }}resources/uitheme1.8/jquery-ui.css" />
     {% endif %}
-    {% if isRTL %}<link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}resources/default-rtl.css" />{% endif %}
+    {%- if isRTL %}<link rel="stylesheet" type="text/css" href="/{{ baseurlpath }}assets/css/src/default-rtl.css" />{% endif -%}
     <meta name="robots" content="noindex, nofollow">
     {% block preload %}{% endblock %}
 </head>
-<body>
-    <div id="wrap">
-
-        {% block header %}{% include "_header.twig" %}{% endblock %}
-
+<body id="{{ templateId }}">
+    <div id="layout">
+{% block header %}{% include "_header.twig" %}{% endblock %}
         <div id="content">
-        {% block contentwrapper %}
-        {% block content %}{% endblock %}
-        {% endblock %}
-        </div><!-- #content -->
-
-        <div id="footer">
-            {% block footer %}{% include "_footer.twig" %}{% endblock %}
-        </div>
+            <div class="wrap">
+                {% block contentwrapper -%}
+                    {% block content %}{% endblock -%}
+                {% endblock %}
+            </div>
+        </div><!-- content -->
+        <div id="push"></div>
+    </div><!-- layout -->
 
-    </div><!-- #wrap -->
+    <div id="foot">
+{% block footer %}{% include "_footer.twig" %}{% endblock %}
+    </div>
 
     <!-- postload javascript -->
-    <script type="text/javascript" src="/{{ baseurlpath }}resources/script.js"></script>
-    {% if jquery %}
-    {% set version = '1.8' %}
-    {% if jquery.version %}
-    {% set version = jquery.version %}
-    {% endif %}
-    {% if version == '1.8' %}
-    {% if jquery.core %}
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/lib/jquery-3.3.1.min.js"></script>
+    {% spaceless %}{% if jquery %}
+        {% set version = '1.8' %}
+        {% if jquery.version %}
+            {% set version = jquery.version %}
+        {% endif %}
+        {% if version == '1.8' %}
+            {% if jquery.core %}
     <script type="text/javascript" src="/{{ baseurlpath }}resources/jquery-1.8.js"></script>
-    {% endif %}
-    {% if jquery.ui %}
+            {% endif %}
+            {% if jquery.ui %}
     <script type="text/javascript" src="/{{ baseurlpath }}resources/jquery-ui-1.8.js"></script>
-    {% endif %}
-    {% endif %}
-    {% endif %}
-    {% if clipboard %}
-    <script type="text/javascript" src="/{{ baseurlpath }}resources/clipboard.min.js"></script>
-    {% endif %}
-    {% block postload %}{% endblock %}
+            {% endif %}
+        {% endif %}
+    {% endif %}{% endspaceless -%}
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/lib/clipboard.min.js"></script>
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/lib/selectize.min.js"></script>
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/src/language.js"></script>
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/src/side_menu.js"></script>
+    <script type="text/javascript" src="/{{ baseurlpath }}assets/js/src/script.js"></script>
+{% block postload %}{% endblock %}
 </body></html>
diff --git a/templates/error.php b/templates/error.php
index fc0b145a0f92e05e7c51b20cf49eb1bf0aea355e..1acf83de34f47464709edd15b53fd7ad2ebd7280 100644
--- a/templates/error.php
+++ b/templates/error.php
@@ -68,7 +68,7 @@ if (isset($this->data['errorReportAddress'])) {
     <h2 style="clear: both"><?php echo $this->t('howto_header'); ?></h2>
     <p><?php echo $this->t('howto_text'); ?></p>
     <script type="text/javascript">
-        var clipboard = new Clipboard('#btntrackid');
+        var clipboard = new ClipboardJS('#btntrackid');
     </script>
 <?php
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/templates/error.twig b/templates/error.twig
new file mode 100644
index 0000000000000000000000000000000000000000..311aa2925e979d05b9c89068b038a40019b9d79f
--- /dev/null
+++ b/templates/error.twig
@@ -0,0 +1,56 @@
+
+{% set pagetitle = dictTitle | trans %}
+{% extends "base.twig" %}
+{% block content %}
+    <h2>{{ dictTitle | trans }}</h2>
+    {{ dictDescr | trans(parameters) }}
+
+    {# include optional information for error
+       Some exceptions set 'includeTemplate' to the name of a template to include.
+       e.g. "core:no_state.tpl.php". The format is "<module>:<template name>"
+    #}
+    {% if includeTemplate -%}
+        {% include(includeTemplate) %}
+    {%- endif %}
+
+    <div class="message-box">
+        <p>{{ '{errors:report_trackid}' | trans }}</p>
+        <div class="pure-button-group two-elements" role="group">
+            <label class="pure-button hollow" disabled><pre id="trackid">{{ error.trackId }}</pre></label>
+            <button data-clipboard-target="#trackid" id="btntrackid" class="pure-button clipboard-btn">
+                <i class="fa fa-copy"></i>
+            </button>
+        </div>
+    </div>
+
+    {# print out exception only if the exception is available #}
+    {% if showerrors -%}
+        <h2>{{'{errors:debuginfo_header}' | trans}}</h2>
+        <p>{{'{errors:debuginfo_text}' | trans}}</p>
+        <div class="code-box code-box-content">
+            <pre>{{ error.exceptionMsg }}<br />{{ error.exceptionTrace }}
+            </pre>
+        </div>
+    {%- endif %}
+
+    {# Add error report submit section if we have a valid technical contact. 'errorreportaddress' will only be set if
+       the technical contact email address has been set. #}
+    {% if errorReportAddress -%}
+        <h2>{{ '{errors:report_header}' | trans }}</h2>
+        <form action="{{ errorReportAddress }}" class="pure-form" method="post">
+            <p>{{ '{errors:report_text}' | trans }}</p>
+            <label for="email">{{ '{errors:report_email}' | trans }}</label>
+                <input type="email" name="email" id="email" class="edge" value="{{ email }}" />
+
+            <textarea class="text-area edge" name="text" rows="6" cols="50" placeholder="{{ '{errors:report_explain}' | trans }}" required></textarea>
+        <p class="center">
+            <input type="hidden" name="reportId" value="{{ error.reportId }}" />
+            <input type="submit" name="send" class="pure-button pure-button-red" value="{{ '{errors:report_submit}' | trans }}" />
+        </p>
+        </form>
+    {%- endif %}
+
+    <h2>{{ '{errors:howto_header}' | trans }}</h2>
+    <p>{{ '{errors:howto_text}' | trans }}</p>
+
+{% endblock %}
diff --git a/templates/errorreport.php b/templates/errorreport.php
index 278d483856938f92c89221463bc90e8c3a16ca35..e1154fa8dd025634754573786dd85fdc528e63d3 100644
--- a/templates/errorreport.php
+++ b/templates/errorreport.php
@@ -1,9 +1,9 @@
 <?php
-	$this->data['header'] = $this->t('errorreport_header');
-	$this->includeAtTemplateBase('includes/header.php');
+    $this->data['header'] = $this->t('errorreport_header');
+    $this->includeAtTemplateBase('includes/header.php');
 ?>
 
-
 <h2><?php echo $this->t('errorreport_header'); ?></h2>
 <p><?php echo $this->t('errorreport_text'); ?></p>
-<?php $this->includeAtTemplateBase('includes/footer.php');
+<?php
+    $this->includeAtTemplateBase('includes/footer.php');
diff --git a/templates/errorreport.twig b/templates/errorreport.twig
new file mode 100644
index 0000000000000000000000000000000000000000..d491aaa8cdf29195e1b86680f534c6e04c9cb61c
--- /dev/null
+++ b/templates/errorreport.twig
@@ -0,0 +1,8 @@
+{% set pagetitle = 'Error report sent'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ pagetitle }}</h2>
+
+    <p>{{ 'The error report has been sent to the administrators.' |trans }}</p>
+{% endblock %}
diff --git a/templates/hostnames.php b/templates/hostnames.php
index 45ea32f7fd07ede97475c8e382ffc48abaa1662b..2404638accde6cd145b732de6cf739f5033cb699 100644
--- a/templates/hostnames.php
+++ b/templates/hostnames.php
@@ -3,7 +3,7 @@ $this->data['header'] = $this->t('{status:header_diagnostics}');
 $this->includeAtTemplateBase('includes/header.php');
 $this->includeAtTemplateBase('includes/attributes.php');
 
-echo "<h2>" . $this->t('{core:frontpage:link_diagnostics}') . "</h2>";
+echo "<h2>".$this->t('{core:frontpage:link_diagnostics}')."</h2>";
 
 $attributes = $this->data['attributes'];
 
diff --git a/templates/hostnames.twig b/templates/hostnames.twig
new file mode 100644
index 0000000000000000000000000000000000000000..79f6411f034b1202436513f6d76d345237ec4f34
--- /dev/null
+++ b/templates/hostnames.twig
@@ -0,0 +1,20 @@
+{% set pagetitle = 'Diagnostics on hostname, port and protocol'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ pagetitle }}</h2>
+    {% set items = attributes %}
+
+    {% embed '_table.twig' %}
+
+        {% block namecol %}
+            <td class="attrname"><samp>{{ name }}</samp></td>
+        {% endblock %}
+
+        {% block value %}
+                {{ value }}
+        {% endblock %}
+
+    {% endembed %}
+
+{% endblock %}
diff --git a/templates/includes/attributes.php b/templates/includes/attributes.php
index 79aae3130d4579957302e6f23983a796c63a7ec4..78b862f48aa582c928b4079b55661307950c28ab 100644
--- a/templates/includes/attributes.php
+++ b/templates/includes/attributes.php
@@ -33,32 +33,32 @@ function present_assoc($attr)
 
 function present_eptid(\SimpleSAML\Locale\Translate $t, \SAML2\XML\saml\NameID $nameID)
 {
-    $eptid = array(
-        'NameID' => array($nameID->value),
-    );
+    $eptid = [
+        'NameID' => [$nameID->value],
+    ];
     if (!empty($nameID->Format)) {
-        $eptid[$t->t('{status:subject_format}')] = array($nameID->Format);
+        $eptid[$t->t('{status:subject_format}')] = [$nameID->Format];
     }
     if (!empty($nameID->NameQualifier)) {
-        $eptid['NameQualifier'] = array($nameID->NameQualifier);
+        $eptid['NameQualifier'] = [$nameID->NameQualifier];
     }
     if (!empty($nameID->SPNameQualifier)) {
-        $eptid['SPNameQualifier'] = array($nameID->SPNameQualifier);
+        $eptid['SPNameQualifier'] = [$nameID->SPNameQualifier];
     }
     if (!empty($nameID->SPProvidedID)) {
-        $eptid['SPProvidedID'] = array($nameID->SPProvidedID);
+        $eptid['SPProvidedID'] = [$nameID->SPProvidedID];
     }
     return '<td class="attrvalue">'.present_assoc($eptid);
 }
 
-function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $nameParent)
+function present_attributes(\SimpleSAML\XHTML\Template $t, $attributes, $nameParent)
 {
-    $alternate = array('odd', 'even');
+    $alternate = ['odd', 'even'];
     $i = 0;
 
     $parentStr = (strlen($nameParent) > 0) ? strtolower($nameParent).'_' : '';
     $str = (strlen($nameParent) > 0) ? '<table class="attributes" summary="attribute overview">' :
-        '<table id="table_with_attributes"  class="attributes" summary="attribute overview">';
+        '<table id="table_with_attributes" class="attributes" summary="attribute overview">';
 
     foreach ($attributes as $name => $value) {
         $nameraw = $name;
@@ -78,7 +78,7 @@ function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $namePare
                 if ($nameraw !== $name) {
                     $str .= htmlspecialchars($name).'<br/>';
                 }
-                $str .= '<tt>'.htmlspecialchars($nameraw).'</tt>';
+                $str .= '<code>'.htmlspecialchars($nameraw).'</code>';
                 $str .= '</td><td class="attrvalue"><ul>';
                 foreach ($value as $listitem) {
                     if ($nameraw === 'jpegPhoto') {
@@ -93,18 +93,18 @@ function present_attributes(SimpleSAML_XHTML_Template $t, $attributes, $namePare
                 if ($nameraw !== $name) {
                     $str .= htmlspecialchars($name).'<br/>';
                 }
-                $str .= '<tt>'.htmlspecialchars($nameraw).'</tt>';
+                $str .= '<code>'.htmlspecialchars($nameraw).'</code>';
                 $str .= '</td>';
                 if ($nameraw === 'jpegPhoto') {
                     $str .= '<td class="attrvalue"><img src="data:image/jpeg;base64,'.htmlspecialchars($value[0]).
                         '" /></td></tr>';
                 } elseif (is_a($value[0], 'DOMNodeList')) {
                     // try to see if we have a NameID here
-                    /** @var DOMNodeList $value [0] */
+                    /** @var \DOMNodeList $value [0] */
                     $n = $value[0]->length;
                     for ($idx = 0; $idx < $n; $idx++) {
                         $elem = $value[0]->item($idx);
-                        /* @var DOMElement $elem */
+                        /* @var \DOMElement $elem */
                         if (!($elem->localName === 'NameID' && $elem->namespaceURI === \SAML2\Constants::NS_SAML)) {
                             continue;
                         }
diff --git a/templates/includes/footer.php b/templates/includes/footer.php
index 0ca7e12c1166440517eb477a77f83541b26e6987..75e8e00185f05c8dcc59455b005c57741e8bee97 100644
--- a/templates/includes/footer.php
+++ b/templates/includes/footer.php
@@ -1,22 +1,19 @@
 <?php
-if(!empty($this->data['htmlinject']['htmlContentPost'])) {
-	foreach($this->data['htmlinject']['htmlContentPost'] AS $c) {
-		echo $c;
-	}
+if (!empty($this->data['htmlinject']['htmlContentPost'])) {
+    foreach ($this->data['htmlinject']['htmlContentPost'] as $c) {
+        echo $c;
+    }
 }
 ?>
-	</div><!-- #content -->
-	<div id="footer">
-		<hr />
+            </div><!-- #content -->
+            <div id="footer">
+                <hr />
+                <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/ssplogo-fish-small.png" alt="Small fish logo" style="float: right" />		
+                    Copyright &copy; 2007-2018 <a href="http://uninett.no/">UNINETT AS</a>
 
-		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/ssplogo-fish-small.png" alt="Small fish logo" style="float: right" />		
-		Copyright &copy; 2007-2017 <a href="http://uninett.no/">UNINETT AS</a>
-		
-		<br style="clear: right" />
-	
-	</div><!-- #footer -->
+                <br style="clear: right" />
 
-</div><!-- #wrap -->
-
-</body>
+            </div><!-- #footer -->
+        </div><!-- #wrap -->
+    </body>
 </html>
diff --git a/templates/includes/header-embed.php b/templates/includes/header-embed.php
index 874932502189dfb268b7fbdc6d7cfeb11e16568f..5b83cbf7da33e845cbdbd65f7d462221fa811522 100644
--- a/templates/includes/header-embed.php
+++ b/templates/includes/header-embed.php
@@ -1,23 +1,24 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<title><?php
-if(array_key_exists('header', $this->data)) {
-	echo $this->data['header'];
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>
+<?php
+if (array_key_exists('header', $this->data)) {
+    echo $this->data['header'];
 } else {
-	echo 'SimpleSAMLphp';
+    echo 'SimpleSAMLphp';
 }
-?></title>
-
-	<link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default.css" />
-	<meta name="robots" content="noindex, nofollow" />
+?>
+    </title>
+    <link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default.css" />
+    <meta name="robots" content="noindex, nofollow" />
 
 <?php
-if(array_key_exists('head', $this->data)) {
-	echo '<!-- head -->' . $this->data['head'] . '<!-- /head -->';
+if (array_key_exists('head', $this->data)) {
+    echo '<!-- head -->'.$this->data['head'].'<!-- /head -->';
 }
 ?>
-</head>
-<body class="body-embed">
+    </head>
+    <body class="body-embed">
 
diff --git a/templates/includes/header.php b/templates/includes/header.php
index 2b3365128c0f7ce966e6b417af4a65e0e2442d89..82c894fb9246bfd994e7f177a9499993eeccd1fd 100644
--- a/templates/includes/header.php
+++ b/templates/includes/header.php
@@ -1,30 +1,29 @@
 <?php
 
-
-
 /**
  * Support the htmlinject hook, which allows modules to change header, pre and post body on all pages.
  */
-$this->data['htmlinject'] = array(
-	'htmlContentPre' => array(),
-	'htmlContentPost' => array(),
-	'htmlContentHead' => array(),
-);
-
-
-$jquery = array();
-if (array_key_exists('jquery', $this->data)) $jquery = $this->data['jquery'];
+$this->data['htmlinject'] = [
+    'htmlContentPre' => [],
+    'htmlContentPost' => [],
+    'htmlContentHead' => [],
+];
+
+$jquery = [];
+if (array_key_exists('jquery', $this->data)) {
+    $jquery = $this->data['jquery'];
+}
 
 if (array_key_exists('pageid', $this->data)) {
-	$hookinfo = array(
-		'pre' => &$this->data['htmlinject']['htmlContentPre'], 
-		'post' => &$this->data['htmlinject']['htmlContentPost'], 
-		'head' => &$this->data['htmlinject']['htmlContentHead'], 
-		'jquery' => &$jquery, 
-		'page' => $this->data['pageid']
-	);
-		
-	SimpleSAML\Module::callHooks('htmlinject', $hookinfo);
+    $hookinfo = [
+        'pre' => &$this->data['htmlinject']['htmlContentPre'],
+        'post' => &$this->data['htmlinject']['htmlContentPost'],
+        'head' => &$this->data['htmlinject']['htmlContentHead'],
+        'jquery' => &$jquery,
+        'page' => $this->data['pageid']
+    ];
+        
+    SimpleSAML\Module::callHooks('htmlinject', $hookinfo);
 }
 // - o - o - o - o - o - o - o - o - o - o - o - o -
 
@@ -44,172 +43,164 @@ header('X-Frame-Options: SAMEORIGIN');
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 <meta name="viewport" content="initial-scale=1.0" />
-<script type="text/javascript" src="/<?php echo $this->data['baseurlpath']; ?>resources/script.js"></script>
+<script type="text/javascript" src="/<?php echo $this->data['baseurlpath']; ?>assets/js/src/script.js"></script>
 <title><?php
-if(array_key_exists('header', $this->data)) {
-	echo $this->data['header'];
+if (array_key_exists('header', $this->data)) {
+    echo $this->data['header'];
 } else {
-	echo 'SimpleSAMLphp';
+    echo 'SimpleSAMLphp';
 }
 ?></title>
 
-	<link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default.css" />
-	<link rel="icon" type="image/icon" href="/<?php echo $this->data['baseurlpath']; ?>resources/icons/favicon.ico" />
+    <link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default.css" />
+    <link rel="icon" type="image/icon" href="/<?php echo $this->data['baseurlpath']; ?>resources/icons/favicon.ico" />
 
 <?php
 
-if(!empty($jquery)) {
-	$version = '1.8';
-	if (array_key_exists('version', $jquery))
-		$version = $jquery['version'];
-		
-	if ($version == '1.8') {
-		if (isset($jquery['core']) && $jquery['core'])
-			echo('<script type="text/javascript" src="/' . $this->data['baseurlpath'] . 'resources/jquery-1.8.js"></script>' . "\n");
-	
-		if (isset($jquery['ui']) && $jquery['ui'])
-			echo('<script type="text/javascript" src="/' . $this->data['baseurlpath'] . 'resources/jquery-ui-1.8.js"></script>' . "\n");
-	
-		if (isset($jquery['css']) && $jquery['css'])
-			echo('<link rel="stylesheet" media="screen" type="text/css" href="/' . $this->data['baseurlpath'] . 
-				'resources/uitheme1.8/jquery-ui.css" />' . "\n");
-	}
+if (!empty($jquery)) {
+    $version = '1.8';
+    if (array_key_exists('version', $jquery)) {
+        $version = $jquery['version'];
+    }
+
+    if ($version == '1.8') {
+        if (isset($jquery['core']) && $jquery['core']) {
+            echo '<script type="text/javascript" src="/'.$this->data['baseurlpath'].'resources/jquery-1.8.js"></script>'."\n";
+        }
+
+        if (isset($jquery['ui']) && $jquery['ui']) {
+            echo '<script type="text/javascript" src="/'.$this->data['baseurlpath'].'resources/jquery-ui-1.8.js"></script>'."\n";
+        }
+
+        if (isset($jquery['css']) && $jquery['css']) {
+            echo '<link rel="stylesheet" media="screen" type="text/css" href="/'.$this->data['baseurlpath'].
+                'resources/uitheme1.8/jquery-ui.css" />'."\n";
+        }
+    }
 }
 
 if (isset($this->data['clipboard.js'])) {
-	echo '<script type="text/javascript" src="/'. $this->data['baseurlpath'] .
-		 'resources/clipboard.min.js"></script>'."\n";
+    echo '<script type="text/javascript" src="/'.$this->data['baseurlpath'].'resources/clipboard.min.js"></script>'."\n";
 }
 
-if(!empty($this->data['htmlinject']['htmlContentHead'])) {
-	foreach($this->data['htmlinject']['htmlContentHead'] AS $c) {
-		echo $c;
-	}
+if (!empty($this->data['htmlinject']['htmlContentHead'])) {
+    foreach ($this->data['htmlinject']['htmlContentHead'] as $c) {
+        echo $c;
+    }
 }
 
-
-
-
 if ($this->isLanguageRTL()) {
-?>
-	<link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default-rtl.css" />
-<?php	
+    ?>
+    <link rel="stylesheet" type="text/css" href="/<?php echo $this->data['baseurlpath']; ?>resources/default-rtl.css" />
+<?php
 }
 ?>
+    <meta name="robots" content="noindex, nofollow" />
 
-	
-	<meta name="robots" content="noindex, nofollow" />
-	
-
-<?php	
-if(array_key_exists('head', $this->data)) {
-	echo '<!-- head -->' . $this->data['head'] . '<!-- /head -->';
+<?php
+if (array_key_exists('head', $this->data)) {
+    echo '<!-- head -->'.$this->data['head'].'<!-- /head -->';
 }
 ?>
 </head>
 <?php
 $onLoad = '';
-if(array_key_exists('autofocus', $this->data)) {
-	$onLoad .= 'SimpleSAML_focus(\'' . $this->data['autofocus'] . '\');';
-}
-if (isset($this->data['onLoad'])) {
-	$onLoad .= $this->data['onLoad']; 
-}
-
-if($onLoad !== '') {
-	$onLoad = ' onload="' . $onLoad . '"';
+if (array_key_exists('autofocus', $this->data)) {
+    $onLoad .= ' onload="SimpleSAML_focus(\''.$this->data['autofocus'].'\');"';
 }
 ?>
 <body<?php echo $onLoad; ?>>
 
 <div id="wrap">
-	
-	<div id="header">
-		<h1><a href="/<?php echo $this->data['baseurlpath']; ?>"><?php
-			echo (isset($this->data['header']) ? $this->data['header'] : 'SimpleSAMLphp');
-		?></a></h1>
-	</div>
-
-	
-	<?php 
-	
-	$includeLanguageBar = TRUE;
-	if (!empty($_POST)) 
-		$includeLanguageBar = FALSE;
-	if (isset($this->data['hideLanguageBar']) && $this->data['hideLanguageBar'] === TRUE) 
-		$includeLanguageBar = FALSE;
-	
-	if ($includeLanguageBar) {
-		
-		$languages = $this->getLanguageList();
-		if ( count($languages) > 1 ) {
-			echo '<div id="languagebar">';
-			$langnames = array(
-						'no' => 'BokmĂĄl', // Norwegian BokmĂĄl
-						'nn' => 'Nynorsk', // Norwegian Nynorsk
-						'se' => 'Sámegiella', // Northern Sami
-						'da' => 'Dansk', // Danish
-						'en' => 'English',
-						'de' => 'Deutsch', // German
-						'sv' => 'Svenska', // Swedish
-						'fi' => 'Suomeksi', // Finnish
-						'es' => 'Español', // Spanish
-						'fr' => 'Français', // French
-						'it' => 'Italiano', // Italian
-						'nl' => 'Nederlands', // Dutch
-						'lb' => 'LĂ«tzebuergesch', // Luxembourgish
-						'cs' => 'Čeština', // Czech
-						'sl' => 'Slovenščina', // Slovensk
-						'lt' => 'LietuviĹł kalba', // Lithuanian
-						'hr' => 'Hrvatski', // Croatian
-						'hu' => 'Magyar', // Hungarian
-						'pl' => 'Język polski', // Polish
-						'pt' => 'PortuguĂŞs', // Portuguese
-						'pt-br' => 'PortuguĂŞs brasileiro', // Portuguese
-						'ru' => 'русский язык', // Russian
-						'et' => 'eesti keel', // Estonian
-						'tr' => 'Türkçe', // Turkish
-						'el' => 'ελληνικά', // Greek
-						'ja' => '日本語', // Japanese
-						'zh' => '简体中文', // Chinese (simplified)
-						'zh-tw' => '繁體中文', // Chinese (traditional)
-						'ar' => 'العربية', // Arabic
-						'he' => 'עִבְרִית', // Hebrew
-						'id' => 'Bahasa Indonesia', // Indonesian
-						'sr' => 'Srpski', // Serbian
-						'lv' => 'Latviešu', // Latvian
-						'ro' => 'Românește', // Romanian
-						'eu' => 'Euskara', // Basque
-						'af' => 'Afrikaans', // Afrikaans
-			);
-			
-			$textarray = array();
-			foreach ($languages AS $lang => $current) {
-				$lang = strtolower($lang);
-				if ($current) {
-					$textarray[] = $langnames[$lang];
-				} else {
-					$textarray[] = '<a href="' . htmlspecialchars(\SimpleSAML\Utils\HTTP::addURLParameters(\SimpleSAML\Utils\HTTP::getSelfURL(), array($this->getTranslator()->getLanguage()->getLanguageParameterName() => $lang))) . '">' .
-						$langnames[$lang] . '</a>';
-				}
-			}
-			echo join(' | ', $textarray);
-			echo '</div>';
-		}
-
-	}
-
-
-
-	?>
-	<div id="content">
-
 
+    <div id="header">
+        <h1><a href="/<?php echo $this->data['baseurlpath']; ?>"><?php
+            echo(isset($this->data['header']) ? $this->data['header'] : 'SimpleSAMLphp');
+        ?></a></h1>
+    </div>
+
+
+    <?php
+
+    $includeLanguageBar = true;
+    if (!empty($_POST)) {
+        $includeLanguageBar = false;
+    }
+    if (isset($this->data['hideLanguageBar']) && $this->data['hideLanguageBar'] === true) {
+        $includeLanguageBar = false;
+    }
+
+    if ($includeLanguageBar) {
+        $languages = $this->getLanguageList();
+        ksort($languages);
+        if (count($languages) > 1) {
+            echo '<div id="languagebar">';
+            $langnames = [
+                'no' => 'BokmĂĄl', // Norwegian BokmĂĄl
+                'nn' => 'Nynorsk', // Norwegian Nynorsk
+                'se' => 'Sámegiella', // Northern Sami
+                'da' => 'Dansk', // Danish
+                'en' => 'English',
+                'de' => 'Deutsch', // German
+                'sv' => 'Svenska', // Swedish
+                'fi' => 'Suomeksi', // Finnish
+                'es' => 'Español', // Spanish
+                'ca' => 'CatalĂ ', // Catalan
+                'fr' => 'Français', // French
+                'it' => 'Italiano', // Italian
+                'nl' => 'Nederlands', // Dutch
+                'lb' => 'LĂ«tzebuergesch', // Luxembourgish
+                'cs' => 'Čeština', // Czech
+                'sl' => 'Slovenščina', // Slovensk
+                'lt' => 'LietuviĹł kalba', // Lithuanian
+                'hr' => 'Hrvatski', // Croatian
+                'hu' => 'Magyar', // Hungarian
+                'pl' => 'Język polski', // Polish
+                'pt' => 'PortuguĂŞs', // Portuguese
+                'pt-br' => 'PortuguĂŞs brasileiro', // Portuguese
+                'ru' => 'русский язык', // Russian
+                'et' => 'eesti keel', // Estonian
+                'tr' => 'Türkçe', // Turkish
+                'el' => 'ελληνικά', // Greek
+                'ja' => '日本語', // Japanese
+                'zh' => '简体中文', // Chinese (simplified)
+                'zh-tw' => '繁體中文', // Chinese (traditional)
+                'ar' => 'العربية', // Arabic
+                'he' => 'עִבְרִית', // Hebrew
+                'id' => 'Bahasa Indonesia', // Indonesian
+                'sr' => 'Srpski', // Serbian
+                'lv' => 'Latviešu', // Latvian
+                'ro' => 'Românește', // Romanian
+                'eu' => 'Euskara', // Basque
+                'af' => 'Afrikaans', // Afrikaans
+            ];
+
+            $textarray = [];
+            foreach ($languages as $lang => $current) {
+                $lang = strtolower($lang);
+                if ($current) {
+                    $textarray[] = $langnames[$lang];
+                } else {
+                    $textarray[] = '<a href="'.htmlspecialchars(
+                        \SimpleSAML\Utils\HTTP::addURLParameters(
+                            \SimpleSAML\Utils\HTTP::getSelfURL(),
+                            [$this->getTranslator()->getLanguage()->getLanguageParameterName() => $lang]
+                        )
+                    ).'">'.$langnames[$lang].'</a>';
+                }
+            }
+            echo join(' | ', $textarray);
+            echo '</div>';
+        }
+    }
+
+    ?>
+    <div id="content">
 
 <?php
 
-if(!empty($this->data['htmlinject']['htmlContentPre'])) {
-	foreach($this->data['htmlinject']['htmlContentPre'] AS $c) {
-		echo $c;
-	}
+if (!empty($this->data['htmlinject']['htmlContentPre'])) {
+    foreach ($this->data['htmlinject']['htmlContentPre'] as $c) {
+        echo $c;
+    }
 }
diff --git a/templates/index.twig b/templates/index.twig
index 2a6004aa06f112da48320488c242a7ad286dd17c..e80a9ad701acc62fb8dffc2c41a2e57e55119419 100644
--- a/templates/index.twig
+++ b/templates/index.twig
@@ -2,21 +2,21 @@
 {% block content %}
     <div id="portalmenu" class="ui-tabs ui-widget ui-widget-content ui-corner-all">
         <ul class="tabset_tabs ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">
-            <li class="ui-state-default ui-corner-top"><a href="http://simplesaml.arrakis.uninett.no/simplesaml/module.php/core/frontpage_welcome.php">Welcome</a></li>
             <li class="ui-state-default ui-corner-top ui-tabs-selected ui-state-active"><a href="#">Configuration</a></li>
-            <li class="ui-state-default ui-corner-top"><a href="http://simplesaml.arrakis.uninett.no/simplesaml/module.php/core/frontpage_auth.php">Authentication</a></li>
-            <li class="ui-state-default ui-corner-top"><a href="http://simplesaml.arrakis.uninett.no/simplesaml/module.php/core/frontpage_federation.php">Federation</a></li>
+            <li class="ui-state-default ui-corner-top"><a href="/{{ baseurlpath }}module.php/core/frontpage_auth.php">Authentication</a></li>
+            <li class="ui-state-default ui-corner-top"><a href="/{{ baseurlpath }}module.php/core/frontpage_federation.php">Federation</a></li>
         </ul>
+        <a class='float-r' href='{{ logouturl }}'>{{ '{core:frontpage:logout}'|trans }}</a>
         <div id="portalcontent" class="ui-tabs-panel ui-widget-content ui-corner-bottom">
 
         <div style="clear: both" class="enablebox mini">
             <table>
 
                 <tr class="disabled"><td>SAML 2.0 IdP</td>
-                    <td><img src="/{{ baseurlpath }}resources/icons/silk/delete.png" alt="disabled" /></td></tr>
+                    <td><i class="fa fa-ban"></i></td></tr>
 
                 <tr class="disabled"><td>Shib 1.3 IdP</td>
-                    <td><img src="/{{ baseurlpath }}resources/icons/silk/delete.png" alt="disabled" /></td></tr>
+                    <td><i class="fa fa-ban"></i></td></tr>
 
             </table>
         </div>
diff --git a/templates/login-ldapmulti.php b/templates/login-ldapmulti.php
index 6f73d5a5d2e0608e83fb487942a7616886218a78..a53da3ebed54eb61a64264c295818351feb173a4 100644
--- a/templates/login-ldapmulti.php
+++ b/templates/login-ldapmulti.php
@@ -1,74 +1,64 @@
 <?php 
-	$this->includeAtTemplateBase('includes/header.php'); 
+    $this->includeAtTemplateBase('includes/header.php'); 
 ?>
 
+<?php
+if (isset($this->data['error'])) {
+?>
+    <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+        <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l erroricon" style="margin: 15px" alt="" />
+        <h2><?php echo $this->t('error_header'); ?></h2>
+
+        <p class="logintext"><?php echo htmlspecialchars($this->data['error']); ?> </p>
+    </div>
+<?php
+}
+?>
+    <h2 style="break: both"><?php echo $this->t('user_pass_header'); ?></h2>
+
+    <p><?php echo $this->t('user_pass_text'); ?></p>
 
-		<?php if (isset($this->data['error'])) { ?>
-		<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
-		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l erroricon" style="margin: 15px" alt="" />
-		<h2><?php echo $this->t('error_header'); ?></h2>
-		
-		<p class="logintext"><?php echo htmlspecialchars($this->data['error']); ?> </p>
-		</div>
-		<?php } ?>
-	
-		<h2 style="break: both"><?php echo $this->t('user_pass_header'); ?></h2>
-		
-		<p>
-			<?php echo $this->t('user_pass_text'); ?>
-		</p>
-		
-		<form action="?" method="post" name="f">
+    <form action="?" method="post" name="f">
 
-		<table>
-			<tr>
-				<td rowspan="3"><img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-authentication.48x48.png" id="loginicon" alt="" /></td>
-				<td style="padding: .3em;"><?php echo $this->t('username'); ?></td>
-				<td><input type="text" tabindex="1" name="username" 
-					<?php if (isset($this->data['username'])) {
-						echo 'value="' . htmlspecialchars($this->data['username']) . '"';
-					} ?> /></td>
+        <table>
+            <tr>
+                <td rowspan="3"><img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-authentication.48x48.png" id="loginicon" alt="" /></td>
+                <td style="padding: .3em;"><?php echo $this->t('username'); ?></td>
+                <td><input type="text" tabindex="1" name="username"
+<?php
+if (isset($this->data['username'])) {
+    echo 'value="'.htmlspecialchars($this->data['username']).'"';
+}
+?>
+ /></td>
+
+                <td style="padding: .4em;" rowspan="3">
+                    <button type="submit" tabindex="3" id="regularsubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
+                    <input type="hidden" name="RelayState" value="<?php echo htmlspecialchars($this->data['relaystate']); ?>" />
+                </td>
+            </tr>
+            <tr>
+                <td style="padding: .3em;"><?php echo $this->t('organization'); ?></td>
+                <td><select name="org" tabindex="2">
+<?php
+foreach ($this->data['ldapconfig'] as $key => $entry) {
+    echo '<option '.($key == $this->data['org'] ? 'selected="selected" ' : '').
+        'value="'.htmlspecialchars($key).'">'.htmlspecialchars($entry['description']).'</option>';
+}
+?>
+                </select></td>
+            </tr>
 
-					
-				<td style="padding: .4em;" rowspan="3">
-					<button type="submit" tabindex="3" id="regularsubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
-					<input type="hidden" name="RelayState" value="<?php echo htmlspecialchars($this->data['relaystate']); ?>" />
-				</td>
-			</tr>
-			
-			<tr>
-				<td style="padding: .3em;"><?php echo $this->t('organization'); ?></td>
-				<td><select name="org" tabindex="2">
-					<?php
-					
-					foreach ($this->data['ldapconfig'] AS $key => $entry) {
-						echo '<option ' .
-							($key == $this->data['org'] ? 'selected="selected" ' : '')
-							. 'value="' . htmlspecialchars($key) . '">' . htmlspecialchars($entry['description']) . '</option>';
-					}
-					
-					?>
-				</select></td>
-			</tr>
-			
-			<tr>
-				<td style="padding: .3em;"><?php echo $this->t('password'); ?></td>
-				<td><input type="password" tabindex="2" name="password" /></td>
-			</tr>
-		<tr><td></td><td>
-		<button type="submit" tabindex="5" id="mobilesubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
-		</td></tr>
-		</table>
-		
-		
-		</form>
-		
-		
-		<h2 class="logintext"><?php echo $this->t('help_header'); ?>.</h2>
-		
-		
-		<p class="logintext"><?php echo $this->t('help_text'); ?>!</p>
-		
-		
-		
-<?php $this->includeAtTemplateBase('includes/footer.php'); ?>
+            <tr>
+                <td style="padding: .3em;"><?php echo $this->t('password'); ?></td>
+                <td><input type="password" tabindex="2" name="password" /></td>
+            </tr>
+            <tr><td></td><td>
+                <button type="submit" tabindex="5" id="mobilesubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
+            </td></tr>
+        </table>
+    </form>
+    <h2 class="logintext"><?php echo $this->t('help_header'); ?>.</h2>
+    <p class="logintext"><?php echo $this->t('help_text'); ?>!</p>
+<?php
+    $this->includeAtTemplateBase('includes/footer.php');
diff --git a/templates/login.php b/templates/login.php
index fc4e8b28dce39a9518ab7da50c8a418ea224c34f..fd0755db98d529e77df255ba1baf0424a8a3ec47 100644
--- a/templates/login.php
+++ b/templates/login.php
@@ -1,71 +1,60 @@
 <?php 
-	if (!isset($this->data['autofocus'])) {
-		$this->data['autofocus'] = 'username';
-	}
-	$this->includeAtTemplateBase('includes/header.php'); 
+    if (!isset($this->data['autofocus'])) {
+        $this->data['autofocus'] = 'username';
+    }
+    $this->includeAtTemplateBase('includes/header.php'); 
+    if (isset($this->data['error'])) {
 ?>
+    <div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
+        <img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l erroricon" style="margin: 15px" alt="" />
+        <h2><?php echo $this->t('error_header'); ?></h2>
 
-	<?php if (isset($this->data['error'])) { ?>
-		<div style="border-left: 1px solid #e8e8e8; border-bottom: 1px solid #e8e8e8; background: #f5f5f5">
-		<img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-error.48x48.png" class="float-l erroricon" style="margin: 15px" alt="" />
-		<h2><?php echo $this->t('error_header'); ?></h2>
-		
-		<p><?php echo $this->t($this->data['error']); ?> </p>
-		</div>
-	<?php } ?>
-
-	<h2 style="break: both"><?php echo $this->t('user_pass_header'); ?></h2>
-	
-	<p class="logintext"><?php echo $this->t('user_pass_text'); ?></p>
-	
-	<form action="?" method="post" name="f">
-
-	<table>
-		<tr>
-			<td rowspan="2"><img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-authentication.48x48.png" id="loginicon" alt="" /></td>
-			<td style="padding: .3em;"><?php echo $this->t('username'); ?></td>
-			
-			
-			<td>
-			<?php
-			
-				if (array_key_exists('admin', $this->data)) {
-					echo '<strong style="font-size: medium">Administrator</strong>';
-				} else {
-				
-					echo '<input type="text" id="username" tabindex="1" name="username" ';
-					if (isset($this->data['username'])) {
-						echo 'value="' . htmlspecialchars($this->data['username']) . '"';
-					}
-					echo '/>';
-				}
-			
-			
-			?>
-			</td>
+        <p><?php echo $this->t($this->data['error']); ?> </p>
+    </div>
+<?php
+}
+?>
+    <h2 style="break: both"><?php echo $this->t('user_pass_header'); ?></h2>
+    <p class="logintext"><?php echo $this->t('user_pass_text'); ?></p>
 
-			<td style="padding: .4em;" rowspan="2">
-				<button type="submit" class="regularsubmit" tabindex="3" class="btn"><?php echo $this->t('login_button'); ?></button>
-				<input type="hidden" name="RelayState" value="<?php echo htmlspecialchars($this->data['relaystate']); ?>" />
-			</td>
-		</tr>
-		<tr>
-			<td style="padding: .3em;"><?php echo $this->t('password'); ?></td>
-			<td><input id="password" type="password" tabindex="2" name="password" /></td>
-		</tr>
-        <tr><td></td><td></td><td>
-	        <button type="submit" tabindex="5" id="mobilesubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
-	    </td></tr>
-	</table>
-	
-	
-	</form>
-	
-	
-	<h2 class="logintext"><?php echo $this->t('help_header'); ?></h2>
-	
-	
-	<p class="logintext"><?php echo $this->t('help_text'); ?></p>
-	
+    <form action="?" method="post" name="f">
 
-<?php $this->includeAtTemplateBase('includes/footer.php');
+        <table>
+            <tr>
+                <td rowspan="2"><img src="/<?php echo $this->data['baseurlpath']; ?>resources/icons/experience/gtk-dialog-authentication.48x48.png" id="loginicon" alt="" /></td>
+                <td style="padding: .3em;"><?php echo $this->t('username'); ?></td>
+                <td>
+<?php
+if (array_key_exists('admin', $this->data)) {
+    echo '<strong style="font-size: medium">Administrator</strong>';
+} else {
+    echo '<input type="text" id="username" tabindex="1" name="username" ';
+    if (isset($this->data['username'])) {
+        echo 'value="'.htmlspecialchars($this->data['username']).'"';
+    }
+    echo '/>';
+}
+?>
+                </td>
+                <td style="padding: .4em;" rowspan="2">
+                    <button type="submit" class="regularsubmit" tabindex="3" class="btn"><?php echo $this->t('login_button'); ?></button>
+                    <input type="hidden" name="RelayState" value="<?php echo htmlspecialchars($this->data['relaystate']); ?>" />
+                </td>
+            </tr>
+            <tr>
+                <td style="padding: .3em;"><?php echo $this->t('password'); ?></td>
+                <td><input id="password" type="password" tabindex="2" name="password" /></td>
+            </tr>
+            <tr>
+                <td></td>
+                <td></td>
+                <td>
+                    <button type="submit" tabindex="5" id="mobilesubmit" class="btn"><?php echo $this->t('login_button'); ?></button>
+                </td>
+            </tr>
+        </table>
+    </form>
+        <h2 class="logintext"><?php echo $this->t('help_header'); ?></h2>
+        <p class="logintext"><?php echo $this->t('help_text'); ?></p>
+<?php
+    $this->includeAtTemplateBase('includes/footer.php');
diff --git a/templates/logout.php b/templates/logout.php
index 0672ce7259115e49ae0c80d9e1eafc390ca7dd45..92ecd7ae4f7609c0e594eb4b4ea442e8d33bc1e1 100644
--- a/templates/logout.php
+++ b/templates/logout.php
@@ -4,15 +4,13 @@ $this->data['header'] = $this->t('{logout:title}');
 
 $this->includeAtTemplateBase('includes/header.php');
 
+echo '<h2>'.$this->data['header'].'</h2>';
+echo '<p>'.$this->t('{logout:logged_out_text}').'</p>';
 
-
-echo('<h2>' . $this->data['header'] . '</h2>');
-echo('<p>' . $this->t('{logout:logged_out_text}') . '</p>');
-
-if($this->getTranslator()->getTag($this->data['text']) !== NULL) {
-	$this->data['text'] = $this->t($this->data['text']);
+if ($this->getTranslator()->getTag($this->data['text']) !== null) {
+    $this->data['text'] = $this->t($this->data['text']);
 }
-echo('<p>[ <a href="' . htmlspecialchars($this->data['link']) . '">' .
-	htmlspecialchars($this->data['text']) . '</a> ]</p>');
+echo '<p>[ <a href="'.htmlspecialchars($this->data['link']).'">'.
+    htmlspecialchars($this->data['text']).'</a> ]</p>';
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/templates/logout.twig b/templates/logout.twig
new file mode 100644
index 0000000000000000000000000000000000000000..e860aff557443d4a5283f43bb98f9dfc2f613fac
--- /dev/null
+++ b/templates/logout.twig
@@ -0,0 +1,12 @@
+{% set pagetitle = 'Logged out'|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h1>{{ 'Logged out'|trans }}</h1>
+    <br>
+    <h3>{% trans %}You have been logged out.{% endtrans %}</h3>
+    <br>
+    {% if text %}
+    <p><a href="{{ link }}">{{ text|trans }}</a></p>
+    {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/templates/metadata-converter.php b/templates/metadata-converter.php
index e784cea2e5039405cabf76d5d9d53552da40d83c..bc46d3a949d8d3279f5539788b72889341810dd4 100644
--- a/templates/metadata-converter.php
+++ b/templates/metadata-converter.php
@@ -48,10 +48,10 @@ if (!empty($output)) {
 <?php
     for ($j = 1; $j <= $i; $j++) {
 ?>
-        var clipboard<?php echo $j; ?> = new Clipboard('#btn<?php echo $j; ?>');
+        var clipboard<?php echo $j; ?> = new ClipboardJS('#btn<?php echo $j; ?>');
 <?php
     }
- ?>
+?>
     </script>
 <?php
 }
diff --git a/templates/metadata-converter.twig b/templates/metadata-converter.twig
new file mode 100644
index 0000000000000000000000000000000000000000..fff4d685fed2abf8cfaf3a6909fa2289404d74b1
--- /dev/null
+++ b/templates/metadata-converter.twig
@@ -0,0 +1,49 @@
+{% set pagetitle = 'Metadata parser'|trans %}
+{% extends "base.twig" %}
+
+{%  set i=1 %}
+{% block content %}
+    <h1>{{ pagetitle }}</h1>
+    <form method="post" class="pure-form" enctype="multipart/form-data">
+        <h3> {% trans 'XML metadata' %}</h3>
+        <div class="pure-control-group">
+            <textarea name="xmldata" rows="20" class="text-area edge">{{ xmldata }}</textarea>
+        </div>
+        <br>
+        <div class="center">
+            <div class="pure-button-group two-elements" role="group">
+                <label class="pure-button">
+                    <span class="fa fa-folder-open"></span>{{ 'or select a file:'|trans }}
+                    <input type="file" name="xmlfile" class="hidden" multiple>
+                </label>
+                {#needs translation#}
+                <label id="show-file" class="pure-button hollow show-files" disabled>No file selected.</label>
+            </div>
+            <br>
+            <button class="pure-button pure-button-red pure-input-1-3">{{ 'Parse'|trans }}</button>
+        </div>
+    </form>
+
+    {% if output -%}
+    <br>
+    <h2>{{ 'Converted metadata'|trans }}</h2>
+        {% for type, text in output if text -%}
+    <div class="code-box">
+        <div class="code-box-title">
+            <h3> {{ type }}</h3>
+            <button data-clipboard-target="#metadata{{ loop.index }}" id="btn{{ loop.index }}" class="pure-button right clipboard-btn">
+                <i class="fa fa-copy"></i>
+            </button>
+        </div>
+        <div class="code-box-content">
+            <pre id="metadata{{ loop.index }}">
+                {%- spaceless %}{{ text|escape }}{% endspaceless -%}
+            </pre>
+        </div>
+    </div>
+            <br><br>
+            {%- set i=i+1 %}
+        {%- endfor -%}
+    {% endif -%}
+{% endblock content -%}
+
diff --git a/templates/metadata.php b/templates/metadata.php
index cd43769c2428f72f75db005a5b387186536cfcae..c851afea27b49696fd6fecfd714ffddab3720402 100644
--- a/templates/metadata.php
+++ b/templates/metadata.php
@@ -4,7 +4,7 @@ $this->includeAtTemplateBase('includes/header.php'); ?>
     <h2><?php echo $this->data['header']; ?></h2>
     <p><?php echo $this->t('metadata_intro'); ?></p>
 <?php if (isset($this->data['metaurl'])) { ?>
-    <p><?php echo($this->t('metadata_xmlurl', array('%METAURL%' => htmlspecialchars($this->data['metaurl'])))); ?></p>
+    <p><?php echo($this->t('metadata_xmlurl', ['%METAURL%' => htmlspecialchars($this->data['metaurl'])])); ?></p>
     <div class="input-group">
         <pre id="metadataurl" class="input-left"><?php echo htmlspecialchars($this->data['metaurl']); ?></pre>
         <button data-clipboard-target="#metadataurl" id="btnurl" class="btnaddonright">
@@ -32,9 +32,9 @@ $this->includeAtTemplateBase('includes/header.php'); ?>
         <pre id="phpmetadata"><?php echo $this->data['metadataflat']; ?></pre>
     </div>
     <script type="text/javascript">
-        var clipboard1 = new Clipboard('#btnurl'),
-            clipboard2 = new Clipboard('#btnxml'),
-            clipboard3 = new Clipboard('#btnphp');
+        var clipboard1 = new ClipboardJS('#btnurl'),
+            clipboard2 = new ClipboardJS('#btnxml'),
+            clipboard3 = new ClipboardJS('#btnphp');
     </script>
 <?php
 if (array_key_exists('available_certs', $this->data)) { ?>
@@ -50,8 +50,8 @@ if (array_key_exists('available_certs', $this->data)) { ?>
         if ($this->data['available_certs'][$certName]['certFingerprint'][0] ===
             'afe71c28ef740bc87425be13a2263d37971da1f9') {
             echo '&nbsp; <img style="display: inline;" src="/'.$this->data['baseurlpath'].
-                 'resources/icons/silk/exclamation.png" alt="default certificate" />'.
-                 'This is the default certificate. Generate a new certificate if this is a production system.';
+                'resources/icons/silk/exclamation.png" alt="default certificate" />'.
+                'This is the default certificate. Generate a new certificate if this is a production system.';
         }
         echo '</li>';
     } ?>
diff --git a/templates/metadata.twig b/templates/metadata.twig
new file mode 100644
index 0000000000000000000000000000000000000000..f62aa13a63de424c49fdf92649d063af9f360f4b
--- /dev/null
+++ b/templates/metadata.twig
@@ -0,0 +1,54 @@
+{% set pagetile = 'SimpleSAMLphp Show Metadata'|trans %}
+{% extends 'base.twig' %}
+{% block content %}
+    <h2>{{ header }}</h2>
+    <p>{{ metadata_intro }}</p>
+
+{% if metaurl is defined %}
+    <p>{{ 'You can get the metadata xml on a dedicated URL:' | trans }}</p>
+    <div class="input-group">
+        <pre id="metadataurl" class="input-left">{{ metaurl }}</pre>
+        <button data-clipboard-target="#metadataurl" id="btnurl" class="pure-button right clipboard-btn">
+            <span class="fa fa-copy"></span>
+        </button>
+    </div>
+{% endif %}
+
+    <h2>{{ 'Metadata' | trans }}</h2>
+    <div class="code-box">
+        <div class="code-box-title">
+    <p>{{ 'In SAML 2.0 Metadata XML format:' | trans }}</p>
+            <button data-clipboard-target="#xmlmetadata" id="btnxml" class="pure-button right clipboard-btn">
+                <span class="fa fa-copy"></span>
+            </button>
+        </div>
+        <div class="code-box-content">
+            <pre id="xmlmetadata">{{ metadata | raw }}</pre>
+        </div>
+    </div>
+
+    <div class="code-box">
+        <div class="code-box-title">
+    <p>{{ 'In SimpleSAMLphp flat file format - use this if you are using a SimpleSAMLphp entity on the other side:' | trans }}</p>
+            <button data-clipboard-target="#phpmetadata" id="btnphp" class="pure-button right clipboard-btn">
+                <span class="fa fa-copy"></span>
+            </button>
+        </div>
+        <div class="code-box-content">
+            <pre id="phpmetadata">{{ metadataflat | raw }}</pre>
+        </div>
+    </div>
+
+{% if certdata is defined %}
+    <h2>{{ 'Certificates' |trans }}</h2>
+    <p>{{ 'Download the X509 certificates as PEM-encoded files.' |trans }}</p>
+
+    <ul>
+    {% for cert in certdata %}
+        <li><a href="{{ cert.url }}">{{ cert.name }}</a> {{ cert.comment }}</li>
+    {% endfor %}
+    </ul>
+
+{% endif %}
+
+{% endblock content %}
diff --git a/templates/post.php b/templates/post.php
index 353a24a383c3cc019bfe85099a2e1fdf7a2b6494..643f08e7789a17da50b5bc5bb0498227647e59d6 100644
--- a/templates/post.php
+++ b/templates/post.php
@@ -31,10 +31,10 @@ if (array_key_exists('post', $this->data)) {
     assert(array_key_exists('response', $this->data));
     assert(array_key_exists('RelayStateName', $this->data));
     assert(array_key_exists('RelayState', $this->data));
-        $post = array(
+        $post = [
         'SAMLResponse' => $this->data['response'],
         $this->data['RelayStateName'] => $this->data['RelayState'],
-    );
+        ];
 }
 
 /**
@@ -47,18 +47,19 @@ if (array_key_exists('post', $this->data)) {
  * @param string $name  The name of the element.
  * @param string|array $value  The value of the element.
  */
-function printItem($name, $value) {
+function printItem($name, $value)
+{
     assert(is_string($name));
     assert(is_string($value) || is_array($value));
     if (is_string($value)) {
-        echo '<input type="hidden" name="' . 
-            htmlspecialchars($name) . '" value="' . 
-            htmlspecialchars($value) . '" />';
+        echo '<input type="hidden" name="'.
+            htmlspecialchars($name).'" value="'.
+            htmlspecialchars($value).'" />';
         return;
     }
     // This is an array...
     foreach ($value as $index => $item) {
-        printItem($name . '[' . $index . ']', $item);
+        printItem($name.'['.$index.']', $item);
     }
 }
 
@@ -66,7 +67,6 @@ foreach ($post as $name => $value) {
     printItem($name, $value);
 }
 ?>
-
         <noscript>
             <button type="submit" class="btn">Submit</button>
         </noscript>
diff --git a/templates/selectidp-dropdown.php b/templates/selectidp-dropdown.php
index a3c4d2bf1d014c5720cdd389d689e5eee267c3e5..4fa03d6ff05a5c07a3d98e2d961a026f894283f7 100644
--- a/templates/selectidp-dropdown.php
+++ b/templates/selectidp-dropdown.php
@@ -7,20 +7,21 @@ $this->data['header'] = $this->t($this->data['header']);
 $this->data['autofocus'] = 'dropdownlist';
 $this->includeAtTemplateBase('includes/header.php');
 
+$translator = $this->getTranslator();
 foreach ($this->data['idplist'] as $idpentry) {
     if (!empty($idpentry['name'])) {
-        $this->getTranslator()->includeInlineTranslation(
+        $translator->includeInlineTranslation(
             'idpname_'.$idpentry['entityid'],
             $idpentry['name']
         );
     } elseif (!empty($idpentry['OrganizationDisplayName'])) {
-        $this->getTranslator()->includeInlineTranslation(
+        $translator->includeInlineTranslation(
             'idpname_'.$idpentry['entityid'],
             $idpentry['OrganizationDisplayName']
         );
     }
     if (!empty($idpentry['description'])) {
-        $this->getTranslator()->includeInlineTranslation('idpdesc_'.$idpentry['entityid'], $idpentry['description']);
+        $translator->includeInlineTranslation('idpdesc_'.$idpentry['entityid'], $idpentry['description']);
     }
 }
 ?>
@@ -33,8 +34,8 @@ foreach ($this->data['idplist'] as $idpentry) {
                value="<?php echo htmlspecialchars($this->data['returnIDParam']); ?>"/>
         <select id="dropdownlist" name="idpentityid">
             <?php
-            usort($this->data['idplist'], function ($idpentry1, $idpentry2) {
-                return strcmp(
+            usort($this->data['idplist'], function($idpentry1, $idpentry2) {
+                return strcasecmp(
                     $this->t('idpname_'.$idpentry1['entityid']),
                     $this->t('idpname_'.$idpentry2['entityid'])
                 );
diff --git a/templates/selectidp-dropdown.twig b/templates/selectidp-dropdown.twig
new file mode 100644
index 0000000000000000000000000000000000000000..22b8f22206f8a573468d088c22799d55aa156805
--- /dev/null
+++ b/templates/selectidp-dropdown.twig
@@ -0,0 +1,31 @@
+{% set pagetitle = "Select your identity provider"|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ pagetitle }}</h2>
+
+    <p>{{ "Please select the identity provider where you want to authenticate:" | trans }}</p>
+    <form method="get" action="{{ urlpattern }}" class="pure-form">
+        <input type="hidden" name="entityID" value="{{ entityID }}">
+        <input type="hidden" name="return" value="{{ return }}">
+        <input type="hidden" name="returnIDParam" value="{{ returnIDParam }}">
+        <div class="pure-control-group">
+        <select id="dropdownlist" name="idpentityid" autofocus>
+        {% for idpentry in idplist %}
+            <option value="{{ idpentry.entityid }}"
+            {% if idpentry.entityid == preferredidp %}
+                 selected
+            {% endif %}
+            >{{ idpentry.name }}</option>
+        {% endfor %}
+        </select>
+        <button class="btn pure-button" type="submit">{{ 'Select' | trans }}</button>
+        </div>
+        {% if rememberenabled %}
+        <div class="pure-control-group">
+            <input type="checkbox" name="remember" id="remember" value="1">
+            <label for="remember">{{ 'Remember my choice' | trans }}</label>
+        </div>
+        {% endif %}
+    </form>
+{% endblock %}
diff --git a/templates/selectidp-links.php b/templates/selectidp-links.php
index b8f2d6e3d89d6c6dd40244993108b3e1d8bfcded..9791882917fd967f95fe75f27e3633ef504bf2ff 100644
--- a/templates/selectidp-links.php
+++ b/templates/selectidp-links.php
@@ -34,13 +34,19 @@ foreach ($this->data['idplist'] as $idpentry) {
             }
             ?></p>
 <?php
+        usort($this->data['idplist'], function($idpentry1, $idpentry2) {
+            return strcasecmp(
+                $this->t('idpname_'.$idpentry1['entityid']),
+                $this->t('idpname_'.$idpentry2['entityid'])
+            );
+        });
         if (!empty($this->data['preferredidp']) &&
             array_key_exists($this->data['preferredidp'], $this->data['idplist'])
         ) {
             $idpentry = $this->data['idplist'][$this->data['preferredidp']];
             echo '<div class="preferredidp">';
             echo '	<img src="/'.$this->data['baseurlpath'].
-                 'resources/icons/experience/gtk-about.64x64.png" class="float-r" alt="'.
+                'resources/icons/experience/gtk-about.64x64.png" class="float-r" alt="'.
                 $this->t('icon_prefered_idp').'" />';
 
             if (array_key_exists('icon', $idpentry) && $idpentry['icon'] !== null) {
@@ -65,7 +71,7 @@ foreach ($this->data['idplist'] as $idpentry) {
                 if (array_key_exists('icon', $idpentry) && $idpentry['icon'] !== null) {
                     $iconUrl = \SimpleSAML\Utils\HTTP::resolveURL($idpentry['icon']);
                     echo '<img class="float-l" style="clear: both; margin: 1em; padding: 3px; border: 1px solid #999"'.
-                         ' src="'.htmlspecialchars($iconUrl).'" />';
+                        ' src="'.htmlspecialchars($iconUrl).'" />';
                 }
                 echo "\n".'	<h3 style="margin-top: 8px">'.htmlspecialchars($this->t('idpname_'.$idpentry['entityid']));
                 echo '</h3>';
diff --git a/templates/selectidp-links.twig b/templates/selectidp-links.twig
new file mode 100644
index 0000000000000000000000000000000000000000..a7bf1103fdfe0b210988767bc99f69736edf4c26
--- /dev/null
+++ b/templates/selectidp-links.twig
@@ -0,0 +1,45 @@
+{% set pagetitle = "Select your identity provider"|trans %}
+{% extends "base.twig" %}
+
+{% block content %}
+    <h2>{{ pagetitle }}</h2>
+
+    <p>{{ "Please select the identity provider where you want to authenticate:" | trans }}</p>
+    <form method="get" action="{{ urlpattern }}">
+        <input type="hidden" name="entityID" value="{{ entityID }}">
+        <input type="hidden" name="return" value="{{ return }}">
+        <input type="hidden" name="returnIDParam" value="{{ returnIDParam }}">
+        {% if rememberenabled %}
+            <p><input type="checkbox" name="remember" id="remember" value="1">
+            <label for="remember">{{ 'Remember my choice' | trans }}</label></p>
+        {% endif %}
+
+        {% for idpentry in idplist %}
+        {% if idpentry.entityid == preferredidp %}
+                <div class="preferredidp">
+                {% if idpentry.iconurl %}
+                    <img class="float-l" src="{{ idpentry.iconurl }}">
+                {% endif %}
+                <h3><i class="fa fa-star"></i> {{ idpentry.name }}</h3>
+                {% if idpentry.description %}
+                    <p>{{ idpentry.description }}</p>
+                {% endif %}
+                <button type="submit" class="btn" name="idp_{{ idpentry.entityid }}">{{'Select'|trans}}</button>
+                </div>
+        {% endif %}
+        {% endfor %}
+
+        {% for idpentry in idplist %}
+        {% if idpentry.entityid != preferredidp %}
+                {% if idpentry.iconurl %}
+                    <img class="float-l" src="{{ idpentry.iconurl }}">
+                {% endif %}
+                <h3>{{ idpentry.name }}</h3>
+                {% if idpentry.description %}
+                    <p>{{ idpentry.description }}</p>
+                {% endif %}
+                <button type="submit" class="btn" name="idp_{{ idpentry.entityid }}">{{'Select'|trans}}</button>
+        {% endif %}
+        {% endfor %}
+    </form>
+{% endblock %}
diff --git a/templates/status.php b/templates/status.php
index 798b546acc9bac0ce198e7e412b643675636e36a..6ddc5191123c188d1f7c33b8cbbd4e1d37bde1af 100644
--- a/templates/status.php
+++ b/templates/status.php
@@ -8,65 +8,69 @@ if (array_key_exists('header', $this->data)) {
 $this->includeAtTemplateBase('includes/header.php');
 $this->includeAtTemplateBase('includes/attributes.php');
 ?>
-
     <h2><?php if (isset($this->data['header'])) {
-            echo($this->data['header']);
+            echo $this->data['header'];
         } else {
-            echo($this->t('{status:some_error_occurred}'));
+            echo $this->t('{status:some_error_occurred}');
         } ?></h2>
 
-    <p><?php echo($this->t('{status:intro}')); ?></p>
+    <p><?php echo $this->t('{status:intro}'); ?></p>
 
 <?php
 if (isset($this->data['remaining'])) {
-    echo('<p>'.$this->t('{status:validfor}', array('%SECONDS%' => $this->data['remaining'])).'</p>');
+    echo '<p>'.$this->t('{status:validfor}', ['%SECONDS%' => $this->data['remaining']]).'</p>';
 }
 
 if (isset($this->data['sessionsize'])) {
-    echo('<p>'.$this->t('{status:sessionsize}', array('%SIZE%' => $this->data['sessionsize'])).'</p>');
+    echo '<p>'.$this->t('{status:sessionsize}', ['%SIZE%' => $this->data['sessionsize']]).'</p>';
 }
 ?>
-    <h2><?php echo($this->t('{status:attributes_header}')); ?></h2>
-
+    <h2><?php echo $this->t('{status:attributes_header}'); ?></h2>
 <?php
-
 $attributes = $this->data['attributes'];
-echo(present_attributes($this, $attributes, ''));
+echo present_attributes($this, $attributes, '');
 
 $nameid = $this->data['nameid'];
 if ($nameid !== false) {
     /** @var \SAML2\XML\saml\NameID $nameid */
     echo "<h2>".$this->t('{status:subject_header}')."</h2>";
     if (is_null($nameid->value)) {
-        $list = array("NameID" => array($this->t('{status:subject_notset}')));
+        $list = ["NameID" => [$this->t('{status:subject_notset}')]];
         echo "<p>NameID: <span class=\"notset\">".$this->t('{status:subject_notset}')."</span></p>";
     } else {
-        $list = array(
-            "NameId"                            => array($nameid->value),
-        );
+        $list = [
+            "NameId" => [$nameid->value],
+        ];
         if (!is_null($nameid->Format)) {
-            $list[$this->t('{status:subject_format}')] = array($nameid->Format);
+            $list[$this->t('{status:subject_format}')] = [$nameid->Format];
         }
         if (!is_null($nameid->NameQualifier)) {
-            $list['NameQualifier'] = array($nameid->NameQualifier);
+            $list['NameQualifier'] = [$nameid->NameQualifier];
         }
         if (!is_null($nameid->SPNameQualifier)) {
-            $list['SPNameQualifier'] = array($nameid->SPNameQualifier);
+            $list['SPNameQualifier'] = [$nameid->SPNameQualifier];
         }
         if (!is_null($nameid->SPProvidedID)) {
-            $list['SPProvidedID'] = array($nameid->SPProvidedID);
+            $list['SPProvidedID'] = [$nameid->SPProvidedID];
         }
     }
-    echo(present_attributes($this, $list, ''));
+    echo present_attributes($this, $list, '');
 }
 
+$authData = $this->data['authData'];
+if (!empty($authData)) {
+    echo "<h2>".$this->t('{status:authData_header}')."</h2>";
+    echo '<details><summary>'.$this->t('{status:authData_summary}').'</summary>'; 
+    echo '<pre>'.htmlspecialchars(json_encode($this->data['authData'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)).'</pre>';
+    echo '</details>';
+}
 if (isset($this->data['logout'])) {
-    echo('<h2>'.$this->t('{status:logout}').'</h2>');
-    echo('<p>'.$this->data['logout'].'</p>');
+    echo '<h2>'.$this->t('{status:logout}').'</h2>';
+    echo '<p>'.$this->data['logout'].'</p>';
 }
 
 if (isset($this->data['logouturl'])) {
-    echo('<a href="'.htmlspecialchars($this->data['logouturl']).'">'.$this->t('{status:logout}').'</a>');
+    echo '<a href="'.htmlspecialchars($this->data['logouturl']).'">'.$this->t('{status:logout}').'</a>';
 }
 
 $this->includeAtTemplateBase('includes/footer.php');
diff --git a/tests/BuiltInServer.php b/tests/BuiltInServer.php
index 4f614f5116ec1774e9da58ff03564cf049c07f86..0695e8c7eed2d5a37ffbe53596881130a6f92ad0 100644
--- a/tests/BuiltInServer.php
+++ b/tests/BuiltInServer.php
@@ -9,7 +9,6 @@
 
 namespace SimpleSAML\Test;
 
-
 class BuiltInServer
 {
 
@@ -89,7 +88,7 @@ class BuiltInServer
         );
 
         // execute the command and store the process ID
-        $output = array();
+        $output = [];
         exec($command, $output);
         $this->pid = (int) $output[0];
 
@@ -170,32 +169,32 @@ class BuiltInServer
      *
      * @return array|string The response obtained from the built-in server.
      */
-    public function get($query, $parameters, $curlopts = array())
+    public function get($query, $parameters, $curlopts = [])
     {
         $ch = curl_init();
         $url = 'http://'.$this->address.$query;
         $url .= (!empty($parameters)) ? '?'.http_build_query($parameters) : '';
-        curl_setopt_array($ch, array(
+        curl_setopt_array($ch, [
             CURLOPT_URL => $url,
             CURLOPT_RETURNTRANSFER => 1,
             CURLOPT_HEADER => 1,
-        ));
+        ]);
         curl_setopt_array($ch, $curlopts);
         $resp = curl_exec($ch);
         $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
         list($header, $body) = explode("\r\n\r\n", $resp, 2);
         $raw_headers = explode("\r\n", $header);
         array_shift($raw_headers);
-        $headers = array();
+        $headers = [];
         foreach ($raw_headers as $header) {
             list($name, $value) = explode(':', $header, 2);
             $headers[trim($name)] = trim($value);
         }
         curl_close($ch);
-        return array(
+        return [
             'code' => $code,
             'headers' => $headers,
             'body' => $body,
-        );
+        ];
     }
 }
diff --git a/tests/Utils/ClearStateTestCase.php b/tests/Utils/ClearStateTestCase.php
index 2cecc16b4c5d46af5774f50ee9332737f34b2389..d7d11c8919b324b830c0b68421bc755c447703d5 100644
--- a/tests/Utils/ClearStateTestCase.php
+++ b/tests/Utils/ClearStateTestCase.php
@@ -2,7 +2,7 @@
 
 namespace SimpleSAML\Test\Utils;
 
-include(dirname(__FILE__) . '/StateClearer.php');
+include(dirname(__FILE__).'/StateClearer.php');
 
 use PHPUnit\Framework\TestCase;
 
diff --git a/tests/Utils/ReduceSpillOverTest.php b/tests/Utils/ReduceSpillOverTest.php
index 3c1022209bb38225ad37e6042e82001b2d274839..c744e2a5fda3cfdb43249715a709f06527ff1a81 100644
--- a/tests/Utils/ReduceSpillOverTest.php
+++ b/tests/Utils/ReduceSpillOverTest.php
@@ -15,9 +15,9 @@ class ReduceSpillOverTest extends ClearStateTestCase
     public function testSetState()
     {
         $_SERVER['QUERY_STRING'] = 'a=b';
-        \SimpleSAML_Configuration::loadFromArray(array('a' => 'b'), '[ARRAY]', 'simplesaml');
-        $this->assertEquals('b', \SimpleSAML_Configuration::getInstance()->getString('a'));
-        putenv('SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__);
+        \SimpleSAML\Configuration::loadFromArray(['a' => 'b'], '[ARRAY]', 'simplesaml');
+        $this->assertEquals('b', \SimpleSAML\Configuration::getInstance()->getString('a'));
+        putenv('SIMPLESAMLPHP_CONFIG_DIR='.__DIR__);
     }
 
     /**
@@ -29,7 +29,7 @@ class ReduceSpillOverTest extends ClearStateTestCase
         $this->assertArrayNotHasKey('QUERY_STRING', $_SERVER);
         $this->assertFalse(getenv('SIMPLESAMLPHP_CONFIG_DIR'));
         try {
-            \SimpleSAML_Configuration::getInstance();
+            \SimpleSAML\Configuration::getInstance();
             $this->fail('Expected config configured in other tests to no longer be valid');
         } catch (\SimpleSAML\Error\ConfigurationError $error) {
             // Expected error
diff --git a/tests/Utils/StateClearer.php b/tests/Utils/StateClearer.php
index 7d074d5b1a861a0b1e149a6fa1cf5ee94183352e..880c66bdf6332969503f23ec23743d7d0e6868b7 100644
--- a/tests/Utils/StateClearer.php
+++ b/tests/Utils/StateClearer.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace SimpleSAML\Test\Utils;
 
 /**
@@ -11,19 +12,19 @@ class StateClearer
      * Global state to restore between test runs
      * @var array
      */
-    private $backups = array();
+    private $backups = [];
 
     /**
      * Class that implement \SimpleSAML\Utils\ClearableState and should have clearInternalState called between tests
      * @var array
      */
-    private $clearableState = array('SimpleSAML_Configuration');
+    private $clearableState = ['SimpleSAML\Configuration', 'SimpleSAML\Metadata\MetaDataStorageHandler'];
 
     /**
      * Environmental variables to unset
      * @var array
      */
-    private $vars_to_unset = array('SIMPLESAMLPHP_CONFIG_DIR');
+    private $vars_to_unset = ['SIMPLESAMLPHP_CONFIG_DIR'];
 
     public function backupGlobals()
     {
@@ -35,7 +36,7 @@ class StateClearer
         $this->backups['$_GET'] = $_GET;
         $this->backups['$_POST'] = $_POST;
         $this->backups['$_SERVER'] = $_SERVER;
-        $this->backups['$_SESSION'] = isset($_SESSION) ? $_SESSION : array();
+        $this->backups['$_SESSION'] = isset($_SESSION) ? $_SESSION : [];
         $this->backups['$_REQUEST'] = $_REQUEST;
     }
 
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 4ec9274b9b08c126d52bc3286c5b9c877eed2a4e..82ed397dc1f01a6d83f49ee20bbb44c2dff15267 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,7 +1,7 @@
 <?php
 
 $projectRoot = dirname(__DIR__);
-require_once($projectRoot . '/vendor/autoload.php');
+require_once($projectRoot.'/vendor/autoload.php');
 
 // Current SSP autoloader can't resolve classes from the tests folder.
-include($projectRoot . '/tests/Utils/ClearStateTestCase.php');
+include($projectRoot.'/tests/Utils/ClearStateTestCase.php');
diff --git a/tests/lib/SimpleSAML/Auth/SimpleTest.php b/tests/lib/SimpleSAML/Auth/SimpleTest.php
index 8bd5cf8fdd5f1770ba1b1477a1e15908803f3259..7d667ab46269eb822fce4cb56e1bb8969030912a 100644
--- a/tests/lib/SimpleSAML/Auth/SimpleTest.php
+++ b/tests/lib/SimpleSAML/Auth/SimpleTest.php
@@ -8,7 +8,6 @@ namespace SimpleSAML\Test\Auth;
  */
 class SimpleTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
 {
-
     /**
      * @test
      */
@@ -22,68 +21,68 @@ class SimpleTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
         $_SERVER['REQUEST_URI'] = '/';
 
         // test merging configuration option with passed URL
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'application' => array(
+        \SimpleSAML\Configuration::loadFromArray([
+            'application' => [
                 'baseURL' => 'https://example.org'
-            )
-        ), '[ARRAY]', 'simplesaml');
+            ]
+        ], '[ARRAY]', 'simplesaml');
 
         $s = new \SimpleSAML\Auth\Simple('');
 
-        $this->assertEquals('https://example.org/', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('https://example.org/', $method->invokeArgs($s, [null]));
 
         // test a full URL passed as parameter
         $this->assertEquals(
             'https://example.org/foo/bar?a=b#fragment',
             $method->invokeArgs(
                 $s,
-                array('http://some.overridden.host/foo/bar?a=b#fragment')
+                ['http://some.overridden.host/foo/bar?a=b#fragment']
             )
         );
 
         // test a full, current URL with no parameters
         $_SERVER['REQUEST_URI'] = '/foo/bar?a=b#fragment';
-        $this->assertEquals('https://example.org/foo/bar?a=b#fragment', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('https://example.org/foo/bar?a=b#fragment', $method->invokeArgs($s, [null]));
 
         // test ports are overridden by configuration
         $_SERVER['SERVER_PORT'] = '1234';
-        $this->assertEquals('https://example.org/foo/bar?a=b#fragment', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('https://example.org/foo/bar?a=b#fragment', $method->invokeArgs($s, [null]));
 
         // test config option with ending with / and port
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'application' => array(
+        \SimpleSAML\Configuration::loadFromArray([
+            'application' => [
                 'baseURL' => 'http://example.org:8080/'
-            )
-        ), '[ARRAY]', 'simplesaml');
+            ]
+        ], '[ARRAY]', 'simplesaml');
         $s = new \SimpleSAML\Auth\Simple('');
-        $this->assertEquals('http://example.org:8080/foo/bar?a=b#fragment', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('http://example.org:8080/foo/bar?a=b#fragment', $method->invokeArgs($s, [null]));
 
         // test again with a relative URL as a parameter
         $this->assertEquals(
             'http://example.org:8080/something?foo=bar#something',
-            $method->invokeArgs($s, array('/something?foo=bar#something'))
+            $method->invokeArgs($s, ['/something?foo=bar#something'])
         );
 
         // now test with no configuration
         $_SERVER['SERVER_NAME'] = 'example.org';
-        \SimpleSAML_Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
         $s = new \SimpleSAML\Auth\Simple('');
-        $this->assertEquals('http://example.org:1234/foo/bar?a=b#fragment', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('http://example.org:1234/foo/bar?a=b#fragment', $method->invokeArgs($s, [null]));
 
         // no configuration, https and port
         $_SERVER['HTTPS'] = 'on';
-        $this->assertEquals('https://example.org:1234/foo/bar?a=b#fragment', $method->invokeArgs($s, array(null)));
+        $this->assertEquals('https://example.org:1234/foo/bar?a=b#fragment', $method->invokeArgs($s, [null]));
 
         // no configuration and a relative URL as a parameter
         $this->assertEquals(
             'https://example.org:1234/something?foo=bar#something',
-            $method->invokeArgs($s, array('/something?foo=bar#something'))
+            $method->invokeArgs($s, ['/something?foo=bar#something'])
         );
 
         // finally, no configuration and full URL as a parameter
         $this->assertEquals(
             'https://example.org/one/two/three?foo=bar#fragment',
-            $method->invokeArgs($s, array('https://example.org/one/two/three?foo=bar#fragment'))
+            $method->invokeArgs($s, ['https://example.org/one/two/three?foo=bar#fragment'])
         );
     }
 }
diff --git a/tests/lib/SimpleSAML/Auth/SourceTest.php b/tests/lib/SimpleSAML/Auth/SourceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e51781d72d6392c98eff242d00a2a2c630b0e7b4
--- /dev/null
+++ b/tests/lib/SimpleSAML/Auth/SourceTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace SimpleSAML\Test\Auth;
+
+use SimpleSAML\Auth\SourceFactory;
+use SimpleSAML\Test\Utils\ClearStateTestCase;
+
+/**
+ * Tests for \SimpleSAML\Auth\Source
+ */
+
+class SourceTest extends ClearStateTestCase
+{
+    public function testParseAuthSource()
+    {
+        $class = new \ReflectionClass('\SimpleSAML\Auth\Source');
+        $method = $class->getMethod('parseAuthSource');
+        $method->setAccessible(true);
+
+        // test direct instantiation of the auth source object
+        $authSource = $method->invokeArgs(null, ['test', ['SimpleSAML\Test\Auth\TestAuthSource']]);
+        $this->assertInstanceOf('SimpleSAML\Test\Auth\TestAuthSource', $authSource);
+
+        // test instantiation via an auth source factory
+        $authSource = $method->invokeArgs(null, ['test', ['SimpleSAML\Test\Auth\TestAuthSourceFactory']]);
+        $this->assertInstanceOf('SimpleSAML\Test\Auth\TestAuthSource', $authSource);
+    }
+}
+
+class TestAuthSource extends \SimpleSAML\Auth\Source
+{
+    public function authenticate(&$state)
+    {
+    }
+}
+
+class TestAuthSourceFactory implements SourceFactory
+{
+    public function create(array $info, array $config)
+    {
+        return new TestAuthSource($info, $config);
+    }
+}
diff --git a/tests/lib/SimpleSAML/Auth/StateTest.php b/tests/lib/SimpleSAML/Auth/StateTest.php
index 0edb0b20ec8b2a94549f2e4a09aba1776b0d79fd..cb78b81197a5fa0f349b202b17db90a152631a5f 100644
--- a/tests/lib/SimpleSAML/Auth/StateTest.php
+++ b/tests/lib/SimpleSAML/Auth/StateTest.php
@@ -1,35 +1,34 @@
 <?php
 
+namespace SimpleSAML\Test\Auth;
+
 use PHPUnit\Framework\TestCase;
 
 /**
- * Tests for SimpleSAML_Auth_State
+ * Tests for \SimpleSAML\Auth\State
  */
-class Auth_StateTest extends TestCase
+class StateTest extends TestCase
 {
-
-
     /**
      * Test the getPersistentAuthData() function.
      */
     public function testGetPersistentAuthData()
     {
-
-        $mandatory = array(
-            'Attributes' => array(),
+        $mandatory = [
+            'Attributes' => [],
             'Expire' => 1234,
             'LogoutState' => 'logoutState',
             'AuthInstant' => 123456,
             'RememberMe' => true,
             'saml:sp:NameID' => 'nameID',
-        );
+        ];
 
         // check just mandatory parameters
         $state = $mandatory;
         $expected = $mandatory;
         $this->assertEquals(
             $expected,
-            SimpleSAML_Auth_State::getPersistentAuthData($state),
+            \SimpleSAML\Auth\State::getPersistentAuthData($state),
             'Mandatory state attributes did not survive as expected'.print_r($expected, true)
         );
 
@@ -39,32 +38,32 @@ class Auth_StateTest extends TestCase
         $expected = $state;
         $this->assertEquals(
             $expected,
-            SimpleSAML_Auth_State::getPersistentAuthData($state),
+            \SimpleSAML\Auth\State::getPersistentAuthData($state),
             'Some error occurred with missing mandatory parameters'
         );
 
         // check additional non-persistent parameters
-        $additional = array(
+        $additional = [
             'additional1' => 1,
             'additional2' => 2,
-        );
+        ];
         $state = array_merge($mandatory, $additional);
         $expected = $mandatory;
         $this->assertEquals(
             $expected,
-            SimpleSAML_Auth_State::getPersistentAuthData($state),
+            \SimpleSAML\Auth\State::getPersistentAuthData($state),
             'Additional parameters survived'
         );
 
         // check additional persistent parameters
-        $additional['PersistentAuthData'] = array('additional1');
+        $additional['PersistentAuthData'] = ['additional1'];
         $state = array_merge($mandatory, $additional);
         $expected = $state;
         unset($expected['additional2']);
         unset($expected['PersistentAuthData']);
         $this->assertEquals(
             $expected,
-            SimpleSAML_Auth_State::getPersistentAuthData($state),
+            \SimpleSAML\Auth\State::getPersistentAuthData($state),
             'Some error occurred with additional, persistent parameters'
         );
 
@@ -75,7 +74,7 @@ class Auth_StateTest extends TestCase
         unset($expected['PersistentAuthData']);
         $this->assertEquals(
             $expected,
-            SimpleSAML_Auth_State::getPersistentAuthData($state),
+            \SimpleSAML\Auth\State::getPersistentAuthData($state),
             'Some error occurred with additional, persistent parameters, and no mandatory ones'
         );
     }
diff --git a/tests/lib/SimpleSAML/Auth/TimeLimitedTokenTest.php b/tests/lib/SimpleSAML/Auth/TimeLimitedTokenTest.php
index 2666fb68b7369a3d84a245f1a7317f95e3895bf9..710d3c2d3d53ac382516caf0e1d5f765513e569e 100644
--- a/tests/lib/SimpleSAML/Auth/TimeLimitedTokenTest.php
+++ b/tests/lib/SimpleSAML/Auth/TimeLimitedTokenTest.php
@@ -6,13 +6,12 @@ use SimpleSAML\Auth\TimeLimitedToken;
 
 class TimeLimitedTokenTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
 {
-
     /**
      * Test for malformed tokens.
      */
     public function testMalformedToken()
     {
-        \SimpleSAML_Configuration::loadFromArray(array('secretsalt' => 'random'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['secretsalt' => 'random'], '[ARRAY]', 'simplesaml');
 
         $token = new TimeLimitedToken();
         $this->assertFalse($token->validate('malformed'));
@@ -26,7 +25,7 @@ class TimeLimitedTokenTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
      */
     public function testValidToken()
     {
-        \SimpleSAML_Configuration::loadFromArray(array('secretsalt' => 'random'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['secretsalt' => 'random'], '[ARRAY]', 'simplesaml');
 
         $token = new TimeLimitedToken();
         $t = $token->generate();
@@ -39,7 +38,7 @@ class TimeLimitedTokenTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
      */
     public function testValidTokenWithData()
     {
-        \SimpleSAML_Configuration::loadFromArray(array('secretsalt' => 'random'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['secretsalt' => 'random'], '[ARRAY]', 'simplesaml');
 
         $tokenWithData = new TimeLimitedToken();
         $tokenWithData->addVerificationData('some more random data');
@@ -56,7 +55,7 @@ class TimeLimitedTokenTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
      */
     public function testExpiredToken()
     {
-        \SimpleSAML_Configuration::loadFromArray(array('secretsalt' => 'random'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['secretsalt' => 'random'], '[ARRAY]', 'simplesaml');
 
         $token = new TimeLimitedToken();
         $this->assertFalse($token->validate('7-c0803e76fff1df0ceb222dee80aa1d73f35d84dd'));
@@ -68,7 +67,7 @@ class TimeLimitedTokenTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
      */
     public function testManipulatedToken()
     {
-        \SimpleSAML_Configuration::loadFromArray(array('secretsalt' => 'random'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['secretsalt' => 'random'], '[ARRAY]', 'simplesaml');
 
         $token = new TimeLimitedToken(1);
         $t = $token->generate();
diff --git a/tests/lib/SimpleSAML/ConfigurationTest.php b/tests/lib/SimpleSAML/ConfigurationTest.php
index fced577efb64dd1cf96700502e4939de9d402276..474495e84443c5485883c89bfee1183d7d9269da 100644
--- a/tests/lib/SimpleSAML/ConfigurationTest.php
+++ b/tests/lib/SimpleSAML/ConfigurationTest.php
@@ -1,16 +1,20 @@
 <?php
 
+namespace SimpleSAML\Test;
+
+use \SimpleSAML\Configuration;
+
 /**
- * Tests for SimpleSAML_Configuration
+ * Tests for \SimpleSAML\Configuration
  */
-class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTestCase
+class ConfigurationTest extends \SimpleSAML\Test\Utils\ClearStateTestCase
 {
-
     /**
-     * Test SimpleSAML_Configuration::getVersion()
+     * Test \SimpleSAML\Configuration::getVersion()
      */
-    public function testGetVersion() {
-        $c = SimpleSAML_Configuration::getOptionalConfig();
+    public function testGetVersion()
+    {
+        $c = Configuration::getOptionalConfig();
         $this->assertTrue(is_string($c->getVersion()));
     }
 
@@ -20,8 +24,8 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
      */
     public function testLoadDefaultInstance()
     {
-        SimpleSAML_Configuration::loadFromArray(array('key' => 'value'), '', 'dummy');
-        SimpleSAML_Configuration::getInstance();
+        Configuration::loadFromArray(['key' => 'value'], '', 'dummy');
+        Configuration::getInstance();
     }
 
 
@@ -32,7 +36,7 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
     public function testCriticalConfigurationError()
     {
         try {
-            SimpleSAML_Configuration::getInstance();
+            Configuration::getInstance();
             $this->fail('Exception expected');
         } catch (\SimpleSAML\Error\CriticalConfigurationError $var) {
             // This exception is expected.
@@ -41,18 +45,19 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
          * After the above failure an emergency configuration is create to allow core SSP components to function and
          * possibly log/display the error.
          */
-        $c = SimpleSAML_Configuration::getInstance();
+        $c = Configuration::getInstance();
         $this->assertNotEmpty($c->toArray());
     }
 
     /**
-     * Test SimpleSAML_Configuration::getValue()
+     * Test \SimpleSAML\Configuration::getValue()
      */
-    public function testGetValue() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetValue()
+    {
+        $c = Configuration::loadFromArray([
             'exists_true' => true,
             'exists_null' => null,
-        ));
+        ]);
         $this->assertEquals($c->getValue('missing'), null);
         $this->assertEquals($c->getValue('missing', true), true);
         $this->assertEquals($c->getValue('missing', true), true);
@@ -64,149 +69,113 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
     }
 
     /**
-     * Test SimpleSAML_Configuration::getValue(), REQUIRED_OPTION flag.
+     * Test \SimpleSAML\Configuration::getValue(), REQUIRED_OPTION flag.
      * @expectedException Exception
      */
-    public function testGetValueRequired() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
-        $c->getValue('missing', SimpleSAML_Configuration::REQUIRED_OPTION);
+    public function testGetValueRequired()
+    {
+        $c = Configuration::loadFromArray([]);
+        $c->getValue('missing', Configuration::REQUIRED_OPTION);
     }
 
     /**
-     * Test SimpleSAML_Configuration::hasValue()
+     * Test \SimpleSAML\Configuration::hasValue()
      */
-    public function testHasValue() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testHasValue()
+    {
+        $c = Configuration::loadFromArray([
             'exists_true' => true,
             'exists_null' => null,
-        ));
+        ]);
         $this->assertEquals($c->hasValue('missing'), false);
         $this->assertEquals($c->hasValue('exists_true'), true);
         $this->assertEquals($c->hasValue('exists_null'), true);
     }
 
     /**
-     * Test SimpleSAML_Configuration::hasValue()
+     * Test \SimpleSAML\Configuration::hasValue()
      */
-    public function testHasValueOneOf() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testHasValueOneOf()
+    {
+        $c = Configuration::loadFromArray([
             'exists_true' => true,
             'exists_null' => null,
-        ));
-        $this->assertEquals($c->hasValueOneOf(array()), false);
-        $this->assertEquals($c->hasValueOneOf(array('missing')), false);
-        $this->assertEquals($c->hasValueOneOf(array('exists_true')), true);
-        $this->assertEquals($c->hasValueOneOf(array('exists_null')), true);
-
-        $this->assertEquals($c->hasValueOneOf(array('missing1', 'missing2')), false);
-        $this->assertEquals($c->hasValueOneOf(array('exists_true', 'missing')), true);
-        $this->assertEquals($c->hasValueOneOf(array('missing', 'exists_true')), true);
-    }
-
-    /**
-     * Test SimpleSAML_Configuration::getBaseURL()
-     */
-    public function testGetBaseURL() {
-
-        // Need to set a default configuration because the SSP Logger attempts to use it.
-        SimpleSAML_Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
-        $c = SimpleSAML_Configuration::loadFromArray(array());
-        $this->assertEquals($c->getBaseURL(), 'simplesaml/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'simplesaml/'));
-        $this->assertEquals($c->getBaseURL(), 'simplesaml/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/simplesaml/'));
-        $this->assertEquals($c->getBaseURL(), 'simplesaml/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'path/to/simplesaml/'));
-        $this->assertEquals($c->getBaseURL(), 'path/to/simplesaml/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/path/to/simplesaml/'));
-        $this->assertEquals($c->getBaseURL(), 'path/to/simplesaml/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org/ssp/'));
-        $this->assertEquals($c->getBaseURL(), 'ssp/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org/'));
-        $this->assertEquals($c->getBaseURL(), '');
+        ]);
+        $this->assertEquals($c->hasValueOneOf([]), false);
+        $this->assertEquals($c->hasValueOneOf(['missing']), false);
+        $this->assertEquals($c->hasValueOneOf(['exists_true']), true);
+        $this->assertEquals($c->hasValueOneOf(['exists_null']), true);
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'http://example.org/ssp/'));
-        $this->assertEquals($c->getBaseURL(), 'ssp/');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => ''));
-        $this->assertEquals($c->getBaseURL(), '');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/'));
-        $this->assertEquals($c->getBaseURL(), '');
-
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'simplesaml'));
-        $this->assertEquals($c->getBaseURL(), 'simplesaml/');
+        $this->assertEquals($c->hasValueOneOf(['missing1', 'missing2']), false);
+        $this->assertEquals($c->hasValueOneOf(['exists_true', 'missing']), true);
+        $this->assertEquals($c->hasValueOneOf(['missing', 'exists_true']), true);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getBasePath()
+     * Test \SimpleSAML\Configuration::getBasePath()
      */
-    public function testGetBasePath() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
+    public function testGetBasePath()
+    {
+        $c = Configuration::loadFromArray([]);
         $this->assertEquals($c->getBasePath(), '/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'simplesaml/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'simplesaml/']);
         $this->assertEquals($c->getBasePath(), '/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/simplesaml/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => '/simplesaml/']);
         $this->assertEquals($c->getBasePath(), '/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'simplesaml'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'simplesaml']);
         $this->assertEquals($c->getBasePath(), '/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/simplesaml'));
+        $c = Configuration::loadFromArray(['baseurlpath' => '/simplesaml']);
         $this->assertEquals($c->getBasePath(), '/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'path/to/simplesaml/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'path/to/simplesaml/']);
         $this->assertEquals($c->getBasePath(), '/path/to/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/path/to/simplesaml/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => '/path/to/simplesaml/']);
         $this->assertEquals($c->getBasePath(), '/path/to/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/path/to/simplesaml'));
+        $c = Configuration::loadFromArray(['baseurlpath' => '/path/to/simplesaml']);
         $this->assertEquals($c->getBasePath(), '/path/to/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org/ssp/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'https://example.org/ssp/']);
         $this->assertEquals($c->getBasePath(), '/ssp/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'https://example.org/']);
         $this->assertEquals($c->getBasePath(), '/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'http://example.org/ssp/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'http://example.org/ssp/']);
         $this->assertEquals($c->getBasePath(), '/ssp/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'http://example.org/ssp/simplesaml'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'http://example.org/ssp/simplesaml']);
         $this->assertEquals($c->getBasePath(), '/ssp/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'http://example.org/ssp/simplesaml/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'http://example.org/ssp/simplesaml/']);
         $this->assertEquals($c->getBasePath(), '/ssp/simplesaml/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => ''));
+        $c = Configuration::loadFromArray(['baseurlpath' => '']);
         $this->assertEquals($c->getBasePath(), '/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => '/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => '/']);
         $this->assertEquals($c->getBasePath(), '/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org:8443'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'https://example.org:8443']);
         $this->assertEquals($c->getBasePath(), '/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array('baseurlpath' => 'https://example.org:8443/'));
+        $c = Configuration::loadFromArray(['baseurlpath' => 'https://example.org:8443/']);
         $this->assertEquals($c->getBasePath(), '/');
     }
 
     /**
-     * Test SimpleSAML_Configuration::resolvePath()
+     * Test \SimpleSAML\Configuration::resolvePath()
      */
-    public function testResolvePath() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testResolvePath()
+    {
+        $c = Configuration::loadFromArray([
             'basedir' => '/basedir/',
-        ));
+        ]);
 
         $this->assertEquals($c->resolvePath(null), null);
         $this->assertEquals($c->resolvePath('/otherdir'), '/otherdir');
@@ -214,17 +183,21 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
 
         $this->assertEquals($c->resolvePath('slash/'), '/basedir/slash');
         $this->assertEquals($c->resolvePath('slash//'), '/basedir/slash');
+
+        $this->assertEquals($c->resolvePath('C:\\otherdir'), 'C:/otherdir');
+        $this->assertEquals($c->resolvePath('C:/otherdir'), 'C:/otherdir');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getPathValue()
+     * Test \SimpleSAML\Configuration::getPathValue()
      */
-    public function testGetPathValue() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetPathValue()
+    {
+        $c = Configuration::loadFromArray([
             'basedir' => '/basedir/',
             'path_opt' => 'path',
             'slashes_opt' => 'slashes//',
-        ));
+        ]);
 
         $this->assertEquals($c->getPathValue('missing'), null);
         $this->assertEquals($c->getPathValue('path_opt'), '/basedir/path/');
@@ -232,331 +205,358 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
     }
 
     /**
-     * Test SimpleSAML_Configuration::getBaseDir()
+     * Test \SimpleSAML\Configuration::getBaseDir()
      */
-    public function testGetBaseDir() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
-        $this->assertEquals($c->getBaseDir(), dirname(dirname(dirname(dirname(__FILE__)))) . '/');
+    public function testGetBaseDir()
+    {
+        $c = Configuration::loadFromArray([]);
+        $this->assertEquals($c->getBaseDir(), dirname(dirname(dirname(dirname(__FILE__)))).'/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+        $c = Configuration::loadFromArray([
             'basedir' => '/basedir',
-        ));
+        ]);
         $this->assertEquals($c->getBaseDir(), '/basedir/');
 
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+        $c = Configuration::loadFromArray([
             'basedir' => '/basedir/',
-        ));
+        ]);
         $this->assertEquals($c->getBaseDir(), '/basedir/');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getBoolean()
+     * Test \SimpleSAML\Configuration::getBoolean()
      */
-    public function testGetBoolean() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetBoolean()
+    {
+        $c = Configuration::loadFromArray([
             'true_opt' => true,
             'false_opt' => false,
-        ));
+        ]);
         $this->assertEquals($c->getBoolean('missing_opt', '--missing--'), '--missing--');
         $this->assertEquals($c->getBoolean('true_opt', '--missing--'), true);
         $this->assertEquals($c->getBoolean('false_opt', '--missing--'), false);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getBoolean() missing option
+     * Test \SimpleSAML\Configuration::getBoolean() missing option
      * @expectedException Exception
      */
-    public function testGetBooleanMissing() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
+    public function testGetBooleanMissing()
+    {
+        $c = Configuration::loadFromArray([]);
         $c->getBoolean('missing_opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getBoolean() wrong option
+     * Test \SimpleSAML\Configuration::getBoolean() wrong option
      * @expectedException Exception
      */
-    public function testGetBooleanWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetBooleanWrong()
+    {
+        $c = Configuration::loadFromArray([
             'wrong' => 'true',
-        ));
+        ]);
         $c->getBoolean('wrong');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getString()
+     * Test \SimpleSAML\Configuration::getString()
      */
-    public function testGetString() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetString()
+    {
+        $c = Configuration::loadFromArray([
             'str_opt' => 'Hello World!',
-        ));
+        ]);
         $this->assertEquals($c->getString('missing_opt', '--missing--'), '--missing--');
         $this->assertEquals($c->getString('str_opt', '--missing--'), 'Hello World!');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getString() missing option
+     * Test \SimpleSAML\Configuration::getString() missing option
      * @expectedException Exception
      */
-    public function testGetStringMissing() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
+    public function testGetStringMissing()
+    {
+        $c = Configuration::loadFromArray([]);
         $c->getString('missing_opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getString() wrong option
+     * Test \SimpleSAML\Configuration::getString() wrong option
      * @expectedException Exception
      */
-    public function testGetStringWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetStringWrong()
+    {
+        $c = Configuration::loadFromArray([
             'wrong' => false,
-        ));
+        ]);
         $c->getString('wrong');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getInteger()
+     * Test \SimpleSAML\Configuration::getInteger()
      */
-    public function testGetInteger() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetInteger()
+    {
+        $c = Configuration::loadFromArray([
             'int_opt' => 42,
-        ));
+        ]);
         $this->assertEquals($c->getInteger('missing_opt', '--missing--'), '--missing--');
         $this->assertEquals($c->getInteger('int_opt', '--missing--'), 42);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getInteger() missing option
+     * Test \SimpleSAML\Configuration::getInteger() missing option
      * @expectedException Exception
      */
-    public function testGetIntegerMissing() {
-        $c = SimpleSAML_Configuration::loadFromArray(array());
+    public function testGetIntegerMissing()
+    {
+        $c = Configuration::loadFromArray([]);
         $c->getInteger('missing_opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getInteger() wrong option
+     * Test \SimpleSAML\Configuration::getInteger() wrong option
      * @expectedException Exception
      */
-    public function testGetIntegerWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetIntegerWrong()
+    {
+        $c = Configuration::loadFromArray([
             'wrong' => '42',
-        ));
+        ]);
         $c->getInteger('wrong');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getIntegerRange()
+     * Test \SimpleSAML\Configuration::getIntegerRange()
      */
-    public function testGetIntegerRange() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetIntegerRange()
+    {
+        $c = Configuration::loadFromArray([
             'int_opt' => 42,
-        ));
+        ]);
         $this->assertEquals($c->getIntegerRange('missing_opt', 0, 100, '--missing--'), '--missing--');
         $this->assertEquals($c->getIntegerRange('int_opt', 0, 100), 42);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getIntegerRange() below limit
+     * Test \SimpleSAML\Configuration::getIntegerRange() below limit
      * @expectedException Exception
      */
-    public function testGetIntegerRangeBelow() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetIntegerRangeBelow()
+    {
+        $c = Configuration::loadFromArray([
             'int_opt' => 9,
-        ));
+        ]);
         $this->assertEquals($c->getIntegerRange('int_opt', 10, 100), 42);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getIntegerRange() above limit
+     * Test \SimpleSAML\Configuration::getIntegerRange() above limit
      * @expectedException Exception
      */
-    public function testGetIntegerRangeAbove() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetIntegerRangeAbove()
+    {
+        $c = Configuration::loadFromArray([
             'int_opt' => 101,
-        ));
+        ]);
         $this->assertEquals($c->getIntegerRange('int_opt', 10, 100), 42);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getValueValidate()
+     * Test \SimpleSAML\Configuration::getValueValidate()
      */
-    public function testGetValueValidate() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetValueValidate()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 'b',
-        ));
-        $this->assertEquals($c->getValueValidate('missing_opt', array('a', 'b', 'c'), '--missing--'), '--missing--');
-        $this->assertEquals($c->getValueValidate('opt', array('a', 'b', 'c')), 'b');
+        ]);
+        $this->assertEquals($c->getValueValidate('missing_opt', ['a', 'b', 'c'], '--missing--'), '--missing--');
+        $this->assertEquals($c->getValueValidate('opt', ['a', 'b', 'c']), 'b');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getValueValidate() wrong option
+     * Test \SimpleSAML\Configuration::getValueValidate() wrong option
      * @expectedException Exception
      */
-    public function testGetValueValidateWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetValueValidateWrong()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 'd',
-        ));
-        $c->getValueValidate('opt', array('a', 'b', 'c'));
+        ]);
+        $c->getValueValidate('opt', ['a', 'b', 'c']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getArray()
+     * Test \SimpleSAML\Configuration::getArray()
      */
-    public function testGetArray() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('a', 'b', 'c'),
-        ));
+    public function testGetArray()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['a', 'b', 'c'],
+        ]);
         $this->assertEquals($c->getArray('missing_opt', '--missing--'), '--missing--');
-        $this->assertEquals($c->getArray('opt'), array('a', 'b', 'c'));
+        $this->assertEquals($c->getArray('opt'), ['a', 'b', 'c']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getArray() wrong option
+     * Test \SimpleSAML\Configuration::getArray() wrong option
      * @expectedException Exception
      */
-    public function testGetArrayWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetArrayWrong()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 'not_an_array',
-        ));
+        ]);
         $c->getArray('opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getArrayize()
+     * Test \SimpleSAML\Configuration::getArrayize()
      */
-    public function testGetArrayize() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('a', 'b', 'c'),
+    public function testGetArrayize()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['a', 'b', 'c'],
             'opt_int' => 42,
             'opt_str' => 'string',
-        ));
+        ]);
         $this->assertEquals($c->getArrayize('missing_opt', '--missing--'), '--missing--');
-        $this->assertEquals($c->getArrayize('opt'), array('a', 'b', 'c'));
-        $this->assertEquals($c->getArrayize('opt_int'), array(42));
-        $this->assertEquals($c->getArrayize('opt_str'), array('string'));
+        $this->assertEquals($c->getArrayize('opt'), ['a', 'b', 'c']);
+        $this->assertEquals($c->getArrayize('opt_int'), [42]);
+        $this->assertEquals($c->getArrayize('opt_str'), ['string']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getArrayizeString()
+     * Test \SimpleSAML\Configuration::getArrayizeString()
      */
-    public function testGetArrayizeString() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('a', 'b', 'c'),
+    public function testGetArrayizeString()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['a', 'b', 'c'],
             'opt_str' => 'string',
-        ));
+        ]);
         $this->assertEquals($c->getArrayizeString('missing_opt', '--missing--'), '--missing--');
-        $this->assertEquals($c->getArrayizeString('opt'), array('a', 'b', 'c'));
-        $this->assertEquals($c->getArrayizeString('opt_str'), array('string'));
+        $this->assertEquals($c->getArrayizeString('opt'), ['a', 'b', 'c']);
+        $this->assertEquals($c->getArrayizeString('opt_str'), ['string']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getArrayizeString() option with an array that contains something that isn't a string.
+     * Test \SimpleSAML\Configuration::getArrayizeString() option
+     * with an array that contains something that isn't a string.
      * @expectedException Exception
      */
-    public function testGetArrayizeStringWrongValue() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('a', 'b', 42),
-        ));
+    public function testGetArrayizeStringWrongValue()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['a', 'b', 42],
+        ]);
         $c->getArrayizeString('opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getConfigItem()
+     * Test \SimpleSAML\Configuration::getConfigItem()
      */
-    public function testGetConfigItem() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('a' => 42),
-        ));
+    public function testGetConfigItem()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['a' => 42],
+        ]);
         $this->assertEquals($c->getConfigItem('missing_opt', '--missing--'), '--missing--');
         $opt = $c->getConfigItem('opt');
-        $this->assertInstanceOf('SimpleSAML_Configuration', $opt);
+        $this->assertInstanceOf('SimpleSAML\Configuration', $opt);
         $this->assertEquals($opt->getValue('a'), 42);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getConfigItem() wrong option
+     * Test \SimpleSAML\Configuration::getConfigItem() wrong option
      * @expectedException Exception
      */
-    public function testGetConfigItemWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetConfigItemWrong()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 'not_an_array',
-        ));
+        ]);
         $c->getConfigItem('opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getConfigList()
+     * Test \SimpleSAML\Configuration::getConfigList()
      */
-    public function testGetConfigList() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opts' => array(
-               'a' => array('opt1' => 'value1'),
-               'b' => array('opt2' => 'value2'),
-            ),
-        ));
+    public function testGetConfigList()
+    {
+        $c = Configuration::loadFromArray([
+            'opts' => [
+                'a' => ['opt1' => 'value1'],
+                'b' => ['opt2' => 'value2'],
+            ],
+        ]);
         $this->assertEquals($c->getConfigList('missing_opt', '--missing--'), '--missing--');
         $opts = $c->getConfigList('opts');
         $this->assertInternalType('array', $opts);
-        $this->assertEquals(array_keys($opts), array('a', 'b'));
-        $this->assertInstanceOf('SimpleSAML_Configuration', $opts['a']);
+        $this->assertEquals(array_keys($opts), ['a', 'b']);
+        $this->assertInstanceOf('SimpleSAML\Configuration', $opts['a']);
         $this->assertEquals($opts['a']->getValue('opt1'), 'value1');
-        $this->assertInstanceOf('SimpleSAML_Configuration', $opts['b']);
+        $this->assertInstanceOf('SimpleSAML\Configuration', $opts['b']);
         $this->assertEquals($opts['b']->getValue('opt2'), 'value2');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getConfigList() wrong option
+     * Test \SimpleSAML\Configuration::getConfigList() wrong option
      * @expectedException Exception
      */
-    public function testGetConfigListWrong() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetConfigListWrong()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 'not_an_array',
-        ));
+        ]);
         $c->getConfigList('opt');
     }
 
 
     /**
-     * Test SimpleSAML_Configuration::getConfigList() with an array of wrong options.
+     * Test \SimpleSAML\Configuration::getConfigList() with an array of wrong options.
      * @expectedException Exception
      */
     public function testGetConfigListWrongArrayValues()
     {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opts' => array(
+        $c = Configuration::loadFromArray([
+            'opts' => [
                 'a',
                 'b',
-            ),
-        ));
+            ],
+        ]);
         $c->getConfigList('opts');
     }
 
 
     /**
-     * Test SimpleSAML_Configuration::getOptions()
+     * Test \SimpleSAML\Configuration::getOptions()
      */
-    public function testGetOptions() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetOptions()
+    {
+        $c = Configuration::loadFromArray([
             'a' => true,
             'b' => null,
-        ));
-        $this->assertEquals($c->getOptions(), array('a', 'b'));
+        ]);
+        $this->assertEquals($c->getOptions(), ['a', 'b']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::toArray()
+     * Test \SimpleSAML\Configuration::toArray()
      */
-    public function testToArray() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testToArray()
+    {
+        $c = Configuration::loadFromArray([
             'a' => true,
             'b' => null,
-        ));
-        $this->assertEquals($c->toArray(), array('a' => true, 'b' => null));
+        ]);
+        $this->assertEquals($c->toArray(), ['a' => true, 'b' => null]);
     }
 
 
     /**
-     * Test SimpleSAML_Configuration::getDefaultEndpoint().
+     * Test \SimpleSAML\Configuration::getDefaultEndpoint().
      *
      * Iterate over all different valid definitions of endpoints and check if the expected output is produced.
      */
@@ -567,137 +567,137 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
          * basically AssertionConsumerService and ArtifactResolutionService. Since both are the same, we just run the
          * tests for AssertionConsumerService.
          */
-        $acs_eps = array(
+        $acs_eps = [
             // just a string with the location
             'https://example.com/endpoint.php',
             // an array of strings with location of different endpoints
-            array(
+            [
                 'https://www1.example.com/endpoint.php',
                 'https://www2.example.com/endpoint.php',
-            ),
+            ],
             // define location and binding
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-                ),
-            ),
+                ],
+            ],
             // define the ResponseLocation too
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
                     'ResponseLocation' => 'https://example.com/endpoint.php',
-                ),
-            ),
+                ],
+            ],
             // make sure indexes are NOT taken into account (they just identify endpoints)
-            array(
-                array(
+            [
+                [
                     'index' => 1,
                     'Location' => 'https://www1.example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
-                ),
-                array(
+                ],
+                [
                     'index' => 2,
                     'Location' => 'https://www2.example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-                ),
-            ),
+                ],
+            ],
             // make sure isDefault has priority over indexes
-            array(
-                array(
+            [
+                [
                     'index' => 1,
                     'Location' => 'https://www2.example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-                ),
-                array(
+                ],
+                [
                     'index' => 2,
                     'isDefault' => true,
                     'Location' => 'https://www1.example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
-                ),
-            ),
+                ],
+            ],
             // make sure endpoints with invalid bindings are ignored and those marked as NOT default are still used
-            array(
-                array(
+            [
+                [
                     'index' => 1,
                     'Location' => 'https://www1.example.com/endpoint.php',
                     'Binding' => 'invalid_binding',
-                ),
-                array(
+                ],
+                [
                     'index' => 2,
                     'isDefault' => false,
                     'Location' => 'https://www2.example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-                ),
-            ),
-        );
-        $acs_expected_eps = array(
+                ],
+            ],
+        ];
+        $acs_expected_eps = [
             // output should be completed with the default binding (HTTP-POST for ACS)
-            array(
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-            ),
+            ],
             // we should just get the first endpoint with the default binding
-            array(
+            [
                 'Location' => 'https://www1.example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-            ),
+            ],
             // if we specify the binding, we should get it back
-            array(
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_POST
-            ),
+            ],
             // if we specify ResponseLocation, we should get it back too
-            array(
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
                 'ResponseLocation' => 'https://example.com/endpoint.php',
-            ),
+            ],
             // indexes must NOT be taken into account, order is the only thing that matters here
-            array(
+            [
                 'Location' => 'https://www1.example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 'index' => 1,
-            ),
+            ],
             // isDefault must have higher priority than indexes
-            array(
+            [
                 'Location' => 'https://www1.example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 'isDefault' => true,
                 'index' => 2,
-            ),
+            ],
             // the first valid enpoint should be used even if it's marked as NOT default
-            array(
+            [
                 'index' => 2,
                 'isDefault' => false,
                 'Location' => 'https://www2.example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_POST,
-            )
-        );
+            ]
+        ];
 
-        $a = array(
+        $a = [
             'metadata-set' => 'saml20-sp-remote',
             'ArtifactResolutionService' => 'https://example.com/ars',
             'SingleSignOnService' => 'https://example.com/sso',
-            'SingleLogoutService' => array(
+            'SingleLogoutService' => [
                 'Location' => 'https://example.com/slo',
                 'Binding' => 'valid_binding', // test unknown bindings if we don't specify a list of valid ones
-            ),
-        );
+            ],
+        ];
 
-        $valid_bindings = array(
+        $valid_bindings = [
             \SAML2\Constants::BINDING_HTTP_POST,
             \SAML2\Constants::BINDING_HTTP_REDIRECT,
             \SAML2\Constants::BINDING_HOK_SSO,
             \SAML2\Constants::BINDING_HTTP_ARTIFACT.
             \SAML2\Constants::BINDING_SOAP,
-        );
+        ];
 
         // run all general tests with AssertionConsumerService endpoint type
         foreach ($acs_eps as $i => $ep) {
             $a['AssertionConsumerService'] = $ep;
-            $c = SimpleSAML_Configuration::loadFromArray($a);
+            $c = Configuration::loadFromArray($a);
             $this->assertEquals($acs_expected_eps[$i], $c->getDefaultEndpoint(
                 'AssertionConsumerService',
                 $valid_bindings
@@ -706,153 +706,153 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
 
         // now make sure SingleSignOnService, SingleLogoutService and ArtifactResolutionService works fine
         $a['metadata-set'] = 'shib13-idp-remote';
-        $c = SimpleSAML_Configuration::loadFromArray($a);
+        $c = Configuration::loadFromArray($a);
         $this->assertEquals(
-            array(
+            [
                 'Location' => 'https://example.com/sso',
                 'Binding' => 'urn:mace:shibboleth:1.0:profiles:AuthnRequest',
-            ),
+            ],
             $c->getDefaultEndpoint('SingleSignOnService')
         );
         $a['metadata-set'] = 'saml20-idp-remote';
-        $c = SimpleSAML_Configuration::loadFromArray($a);
+        $c = Configuration::loadFromArray($a);
         $this->assertEquals(
-            array(
+            [
                 'Location' => 'https://example.com/ars',
                 'Binding' => \SAML2\Constants::BINDING_SOAP,
-            ),
+            ],
             $c->getDefaultEndpoint('ArtifactResolutionService')
         );
         $this->assertEquals(
-            array(
+            [
                 'Location' => 'https://example.com/slo',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
-            ),
+            ],
             $c->getDefaultEndpoint('SingleLogoutService')
         );
 
         // test for old shib1.3 AssertionConsumerService
         $a['metadata-set'] = 'shib13-sp-remote';
         $a['AssertionConsumerService'] = 'https://example.com/endpoint.php';
-        $c = SimpleSAML_Configuration::loadFromArray($a);
+        $c = Configuration::loadFromArray($a);
         $this->assertEquals(
-            array(
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => 'urn:oasis:names:tc:SAML:1.0:profiles:browser-post',
-            ),
+            ],
             $c->getDefaultEndpoint('AssertionConsumerService')
         );
 
         // test for no valid endpoints specified
-        $a['SingleLogoutService'] = array(
-            array(
+        $a['SingleLogoutService'] = [
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => 'invalid_binding',
                 'isDefault' => true,
-            ),
-        );
-        $c = SimpleSAML_Configuration::loadFromArray($a);
+            ],
+        ];
+        $c = Configuration::loadFromArray($a);
         try {
             $c->getDefaultEndpoint('SingleLogoutService', $valid_bindings);
             $this->fail('Failed to detect invalid endpoint binding.');
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             $this->assertEquals(
                 '[ARRAY][\'SingleLogoutService\']:Could not find a supported SingleLogoutService '.'endpoint.',
                 $e->getMessage()
             );
         }
         $a['metadata-set'] = 'foo';
-        $c = SimpleSAML_Configuration::loadFromArray($a);
+        $c = Configuration::loadFromArray($a);
         try {
             $c->getDefaultEndpoint('SingleSignOnService');
             $this->fail('No valid metadata set specified.');
-        } catch (Exception $e) {
+        } catch (\Exception $e) {
             $this->assertStringStartsWith('Missing default binding for', $e->getMessage());
         }
     }
 
 
     /**
-     * Test SimpleSAML_Configuration::getEndpoints().
+     * Test \SimpleSAML\Configuration::getEndpoints().
      */
     public function testGetEndpoints()
     {
         // test response location for old-style configurations
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+        $c = Configuration::loadFromArray([
             'metadata-set' => 'saml20-idp-remote',
             'SingleSignOnService' => 'https://example.com/endpoint.php',
             'SingleSignOnServiceResponse' => 'https://example.com/response.php',
-        ));
-        $e = array(
-            array(
+        ]);
+        $e = [
+            [
                 'Location' => 'https://example.com/endpoint.php',
                 'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                 'ResponseLocation' => 'https://example.com/response.php',
-            )
-        );
+            ]
+        ];
         $this->assertEquals($e, $c->getEndpoints('SingleSignOnService'));
 
         // test for input failures
 
         // define a basic configuration array
-        $a = array(
+        $a = [
             'metadata-set' => 'saml20-idp-remote',
             'SingleSignOnService' => null,
-        );
+        ];
 
         // define a set of tests
-        $tests = array(
+        $tests = [
             // invalid endpoint definition
             10,
             // invalid definition of endpoint inside the endpoints array
-            array(
+            [
                 1234
-            ),
+            ],
             // missing location
-            array(
-                array(
+            [
+                [
                     'foo' => 'bar',
-                ),
-            ),
+                ],
+            ],
             // invalid location
-            array(
-                array(
+            [
+                [
                     'Location' => 1234,
-                )
-            ),
+                ]
+            ],
             // missing binding
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
-                ),
-            ),
+                ],
+            ],
             // invalid binding
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
                     'Binding' => 1234,
-                ),
-            ),
+                ],
+            ],
             // invalid response location
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                     'ResponseLocation' => 1234,
-                ),
-            ),
+                ],
+            ],
             // invalid index
-            array(
-                array(
+            [
+                [
                     'Location' => 'https://example.com/endpoint.php',
                     'Binding' => \SAML2\Constants::BINDING_HTTP_REDIRECT,
                     'index' => 'string',
-                ),
-            ),
-        );
+                ],
+            ],
+        ];
 
         // define a set of exception messages to expect
-        $msgs = array(
+        $msgs = [
             'Expected array or string.',
             'Expected a string or an array.',
             'Missing Location.',
@@ -861,15 +861,15 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
             'Binding must be a string.',
             'ResponseLocation must be a string.',
             'index must be an integer.',
-        );
+        ];
 
         // now run all the tests expecting the correct exception message
         foreach ($tests as $i => $test) {
             $a['SingleSignOnService'] = $test;
-            $c = SimpleSAML_Configuration::loadFromArray($a);
+            $c = Configuration::loadFromArray($a);
             try {
                 $c->getEndpoints('SingleSignOnService');
-            } catch (Exception $e) {
+            } catch (\Exception $e) {
                 $this->assertStringEndsWith($msgs[$i], $e->getMessage());
             }
         }
@@ -877,54 +877,81 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
 
 
     /**
-     * Test SimpleSAML_Configuration::getLocalizedString()
+     * Test \SimpleSAML\Configuration::getLocalizedString()
      */
-    public function testGetLocalizedString() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetLocalizedString()
+    {
+        $c = Configuration::loadFromArray([
             'str_opt' => 'Hello World!',
-            'str_array' => array(
+            'str_array' => [
                 'en' => 'Hello World!',
                 'no' => 'Hei Verden!',
-            ),
-        ));
+            ],
+        ]);
         $this->assertEquals($c->getLocalizedString('missing_opt', '--missing--'), '--missing--');
-        $this->assertEquals($c->getLocalizedString('str_opt'), array('en' => 'Hello World!'));
-        $this->assertEquals($c->getLocalizedString('str_array'), array('en' => 'Hello World!', 'no' => 'Hei Verden!'));
+        $this->assertEquals($c->getLocalizedString('str_opt'), ['en' => 'Hello World!']);
+        $this->assertEquals($c->getLocalizedString('str_array'), ['en' => 'Hello World!', 'no' => 'Hei Verden!']);
     }
 
     /**
-     * Test SimpleSAML_Configuration::getLocalizedString() not array nor simple string
+     * Test \SimpleSAML\Configuration::getLocalizedString() not array nor simple string
      * @expectedException Exception
      */
-    public function testGetLocalizedStringNotArray() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
+    public function testGetLocalizedStringNotArray()
+    {
+        $c = Configuration::loadFromArray([
             'opt' => 42,
-        ));
+        ]);
         $c->getLocalizedString('opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getLocalizedString() not string key
+     * Test \SimpleSAML\Configuration::getLocalizedString() not string key
      * @expectedException Exception
      */
-    public function testGetLocalizedStringNotStringKey() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array(42 => 'text'),
-        ));
+    public function testGetLocalizedStringNotStringKey()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => [42 => 'text'],
+        ]);
         $c->getLocalizedString('opt');
     }
 
     /**
-     * Test SimpleSAML_Configuration::getLocalizedString() not string value
+     * Test \SimpleSAML\Configuration::getLocalizedString() not string value
      * @expectedException Exception
      */
-    public function testGetLocalizedStringNotStringValue() {
-        $c = SimpleSAML_Configuration::loadFromArray(array(
-            'opt' => array('en' => 42),
-        ));
+    public function testGetLocalizedStringNotStringValue()
+    {
+        $c = Configuration::loadFromArray([
+            'opt' => ['en' => 42],
+        ]);
         $c->getLocalizedString('opt');
     }
 
+    /**
+     * Test \SimpleSAML\Configuration::getConfig() nonexistent file
+     * @expectedException Exception
+     */
+    public function testGetConfigNonexistentFile()
+    {
+        Configuration::getConfig('nonexistent-nopreload.php');
+    }
+
+    /**
+     * Test \SimpleSAML\Configuration::getConfig() preloaded nonexistent file
+     */
+    public function testGetConfigNonexistentFilePreload()
+    {
+        $c = Configuration::loadFromArray([
+            'key' => 'value'
+        ]);
+        $virtualFile = 'nonexistent-preload.php';
+        Configuration::setPreLoadedConfig($c, $virtualFile);
+        $nc = Configuration::getConfig($virtualFile);
+        $this->assertEquals('value', $nc->getValue('key', null));
+    }
+
     /**
      * Test that Configuration objects can be initialized from an array.
      *
@@ -932,15 +959,15 @@ class Test_SimpleSAML_Configuration extends SimpleSAML\Test\Utils\ClearStateTest
      */
     public function testLoadInstanceFromArray()
     {
-        $c = array(
+        $c = [
             'key' => 'value'
-        );
+        ];
         // test loading a custom instance
-        SimpleSAML_Configuration::loadFromArray($c, '', 'dummy');
-        $this->assertEquals('value', SimpleSAML_Configuration::getInstance('dummy')->getValue('key', null));
+        Configuration::loadFromArray($c, '', 'dummy');
+        $this->assertEquals('value', Configuration::getInstance('dummy')->getValue('key', null));
 
         // test loading the default instance
-        SimpleSAML_Configuration::loadFromArray($c, '', 'simplesaml');
-        $this->assertEquals('value', SimpleSAML_Configuration::getInstance()->getValue('key', null));
+        Configuration::loadFromArray($c, '', 'simplesaml');
+        $this->assertEquals('value', Configuration::getInstance()->getValue('key', null));
     }
 }
diff --git a/tests/lib/SimpleSAML/DatabaseTest.php b/tests/lib/SimpleSAML/DatabaseTest.php
index 5f04dd87b9bf3e0322ccc3da6c367f57212e6bf3..f48246fd2b7503135e4f378cff0ac68ed0d7b2aa 100644
--- a/tests/lib/SimpleSAML/DatabaseTest.php
+++ b/tests/lib/SimpleSAML/DatabaseTest.php
@@ -1,9 +1,11 @@
 <?php
 
+namespace SimpleSAML\Test;
+
 use PHPUnit\Framework\TestCase;
 
 /**
- * This test ensures that the SimpleSAML_Database class can properly
+ * This test ensures that the \SimpleSAML\Database class can properly
  * query a database.
  *
  * It currently uses sqlite to test, but an alternate config.php file
@@ -13,16 +15,16 @@ use PHPUnit\Framework\TestCase;
  * @author Tyler Antonio, University of Alberta. <tantonio@ualberta.ca>
  * @package SimpleSAMLphp
  */
-class SimpleSAML_DatabaseTest extends TestCase
-{
 
+class DatabaseTest extends TestCase
+{
     /**
-     * @var SimpleSAML_Configuration
+     * @var \SimpleSAML\Configuration
      */
     protected $config;
 
     /**
-     * @var SimpleSAML\Database
+     * @var \SimpleSAML\Database
      */
     protected $db;
 
@@ -35,7 +37,7 @@ class SimpleSAML_DatabaseTest extends TestCase
      */
     protected static function getMethod($getMethod)
     {
-        $class = new ReflectionClass('SimpleSAML\Database');
+        $class = new \ReflectionClass('SimpleSAML\Database');
         $method = $class->getMethod($getMethod);
         $method->setAccessible(true);
         return $method;
@@ -50,22 +52,22 @@ class SimpleSAML_DatabaseTest extends TestCase
      */
     public function setUp()
     {
-        $config = array(
+        $config = [
             'database.dsn'        => 'sqlite::memory:',
             'database.username'   => null,
             'database.password'   => null,
             'database.prefix'     => 'phpunit_',
             'database.persistent' => true,
-            'database.slaves'     => array(),
-        );
+            'database.slaves'     => [],
+        ];
 
-        $this->config = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php");
+        $this->config = new \SimpleSAML\Configuration($config, "test/SimpleSAML/DatabaseTest.php");
 
         // Ensure that we have a functional configuration class
-        $this->assertInstanceOf('SimpleSAML_Configuration', $this->config);
+        $this->assertInstanceOf('SimpleSAML\Configuration', $this->config);
         $this->assertEquals($config['database.dsn'], $this->config->getString('database.dsn'));
 
-        $this->db = SimpleSAML\Database::getInstance($this->config);
+        $this->db = \SimpleSAML\Database::getInstance($this->config);
 
         // Ensure that we have a functional database class.
         $this->assertInstanceOf('SimpleSAML\Database', $this->db);
@@ -82,17 +84,17 @@ class SimpleSAML_DatabaseTest extends TestCase
      */
     public function connectionFailure()
     {
-        $config = array(
+        $config = [
             'database.dsn'        => 'mysql:host=localhost;dbname=saml',
             'database.username'   => 'notauser',
             'database.password'   => 'notausersinvalidpassword',
             'database.prefix'     => 'phpunit_',
             'database.persistent' => true,
-            'database.slaves'     => array(),
-        );
+            'database.slaves'     => [],
+        ];
 
-        $this->config = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php");
-        $db = SimpleSAML\Database::getInstance($this->config);
+        $this->config = new \SimpleSAML\Configuration($config, "test/SimpleSAML/DatabaseTest.php");
+        \SimpleSAML\Database::getInstance($this->config);
     }
 
 
@@ -105,36 +107,36 @@ class SimpleSAML_DatabaseTest extends TestCase
      */
     public function instances()
     {
-        $config = array(
+        $config = [
             'database.dsn'        => 'sqlite::memory:',
             'database.username'   => null,
             'database.password'   => null,
             'database.prefix'     => 'phpunit_',
             'database.persistent' => true,
-            'database.slaves'     => array(),
-        );
-        $config2 = array(
+            'database.slaves'     => [],
+        ];
+        $config2 = [
             'database.dsn'        => 'sqlite::memory:',
             'database.username'   => null,
             'database.password'   => null,
             'database.prefix'     => 'phpunit2_',
             'database.persistent' => true,
-            'database.slaves'     => array(),
-        );
+            'database.slaves'     => [],
+        ];
 
-        $config1 = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php");
-        $config2 = new SimpleSAML_Configuration($config2, "test/SimpleSAML/DatabaseTest.php");
-        $config3 = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php");
+        $config1 = new \SimpleSAML\Configuration($config, "test/SimpleSAML/DatabaseTest.php");
+        $config2 = new \SimpleSAML\Configuration($config2, "test/SimpleSAML/DatabaseTest.php");
+        $config3 = new \SimpleSAML\Configuration($config, "test/SimpleSAML/DatabaseTest.php");
 
-        $db1 = SimpleSAML\Database::getInstance($config1);
-        $db2 = SimpleSAML\Database::getInstance($config2);
-        $db3 = SimpleSAML\Database::getInstance($config3);
+        $db1 = \SimpleSAML\Database::getInstance($config1);
+        $db2 = \SimpleSAML\Database::getInstance($config2);
+        $db3 = \SimpleSAML\Database::getInstance($config3);
 
         $generateInstanceId = self::getMethod('generateInstanceId');
 
-        $instance1 = $generateInstanceId->invokeArgs($db1, array($config1));
-        $instance2 = $generateInstanceId->invokeArgs($db2, array($config2));
-        $instance3 = $generateInstanceId->invokeArgs($db3, array($config3));
+        $instance1 = $generateInstanceId->invokeArgs($db1, [$config1]);
+        $instance2 = $generateInstanceId->invokeArgs($db2, [$config2]);
+        $instance3 = $generateInstanceId->invokeArgs($db3, [$config3]);
 
         // Assert that $instance1 and $instance2 have different instance ids
         $this->assertNotEquals(
@@ -176,31 +178,31 @@ class SimpleSAML_DatabaseTest extends TestCase
     {
         $getSlave = self::getMethod('getSlave');
 
-        $master = spl_object_hash(PHPUnit_Framework_Assert::readAttribute($this->db, 'dbMaster'));
-        $slave = spl_object_hash($getSlave->invokeArgs($this->db, array()));
+        $master = spl_object_hash(\PHPUnit_Framework_Assert::readAttribute($this->db, 'dbMaster'));
+        $slave = spl_object_hash($getSlave->invokeArgs($this->db, []));
 
         $this->assertTrue(($master == $slave), "getSlave should have returned the master database object");
 
-        $config = array(
+        $config = [
             'database.dsn'        => 'sqlite::memory:',
             'database.username'   => null,
             'database.password'   => null,
             'database.prefix'     => 'phpunit_',
             'database.persistent' => true,
-            'database.slaves'     => array(
-                array(
+            'database.slaves'     => [
+                [
                     'dsn'      => 'sqlite::memory:',
                     'username' => null,
                     'password' => null,
-                ),
-            ),
-        );
+                ],
+            ],
+        ];
 
-        $sspConfiguration = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php");
-        $msdb = SimpleSAML\Database::getInstance($sspConfiguration);
+        $sspConfiguration = new \SimpleSAML\Configuration($config, "test/SimpleSAML/DatabaseTest.php");
+        $msdb = \SimpleSAML\Database::getInstance($sspConfiguration);
 
-        $slaves = PHPUnit_Framework_Assert::readAttribute($msdb, 'dbSlaves');
-        $gotSlave = spl_object_hash($getSlave->invokeArgs($msdb, array()));
+        $slaves = \PHPUnit_Framework_Assert::readAttribute($msdb, 'dbSlaves');
+        $gotSlave = spl_object_hash($getSlave->invokeArgs($msdb, []));
 
         $this->assertEquals(
             spl_object_hash($slaves[0]),
@@ -248,11 +250,11 @@ class SimpleSAML_DatabaseTest extends TestCase
         $ssp_value = md5(rand(0, 10000));
         $stmt = $this->db->write(
             "INSERT INTO $table (ssp_key, ssp_value) VALUES (:ssp_key, :ssp_value)",
-            array('ssp_key' => array($ssp_key, PDO::PARAM_INT), 'ssp_value' => $ssp_value)
+            ['ssp_key' => [$ssp_key, \PDO::PARAM_INT], 'ssp_value' => $ssp_value]
         );
         $this->assertEquals(1, $stmt, "Could not insert data into $table.");
 
-        $query2 = $this->db->read("SELECT * FROM $table WHERE ssp_key = :ssp_key", array('ssp_key' => $ssp_key));
+        $query2 = $this->db->read("SELECT * FROM $table WHERE ssp_key = :ssp_key", ['ssp_key' => $ssp_key]);
         $data = $query2->fetch();
         $this->assertEquals($data['ssp_value'], $ssp_value, "Inserted data doesn't match what is in the database");
     }
diff --git a/tests/lib/SimpleSAML/Locale/LanguageTest.php b/tests/lib/SimpleSAML/Locale/LanguageTest.php
index 4b76c09d6187570990a2e4e0e45419a0f05e179c..708d6b60c068dd2ada46ff0daed70ef750198482 100644
--- a/tests/lib/SimpleSAML/Locale/LanguageTest.php
+++ b/tests/lib/SimpleSAML/Locale/LanguageTest.php
@@ -3,27 +3,26 @@
 namespace SimpleSAML\Test\Locale;
 
 use PHPUnit\Framework\TestCase;
+use SimpleSAML\Configuration;
 use SimpleSAML\Locale\Language;
 
 class LanguageTest extends TestCase
 {
-
-
     /**
      * Test SimpleSAML\Locale\Language::getDefaultLanguage().
      */
     public function testGetDefaultLanguage()
     {
         // test default
-        $c = \SimpleSAML_Configuration::loadFromArray(array());
+        $c = Configuration::loadFromArray([]);
         $l = new Language($c);
         $this->assertEquals('en', $l->getDefaultLanguage());
 
         // test defaults coming from configuration
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('en', 'es', 'nn'),
+        $c = Configuration::loadFromArray([
+            'language.available' => ['en', 'es', 'nn'],
             'language.default' => 'es',
-        ));
+        ]);
         $l = new Language($c);
         $this->assertEquals('es', $l->getDefaultLanguage());
     }
@@ -35,19 +34,19 @@ class LanguageTest extends TestCase
     public function testGetLanguageCookie()
     {
         // test it works when no cookie is set
-        \SimpleSAML_Configuration::loadFromArray(array(), '', 'simplesaml');
+        Configuration::loadFromArray([], '', 'simplesaml');
         $this->assertNull(Language::getLanguageCookie());
 
         // test that it works fine with defaults
-        \SimpleSAML_Configuration::loadFromArray(array(), '', 'simplesaml');
+        Configuration::loadFromArray([], '', 'simplesaml');
         $_COOKIE['language'] = 'en';
         $this->assertEquals('en', Language::getLanguageCookie());
 
         // test that it works with non-defaults
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('en', 'es', 'nn'),
+        Configuration::loadFromArray([
+            'language.available' => ['en', 'es', 'nn'],
             'language.cookie.name' => 'xyz'
-        ), '', 'simplesaml');
+        ], '', 'simplesaml');
         $_COOKIE['xyz'] = 'Es'; // test values are converted to lowercase too
         $this->assertEquals('es', Language::getLanguageCookie());
     }
@@ -58,11 +57,11 @@ class LanguageTest extends TestCase
      */
     public function testGetLanguageListNoConfig()
     {
-        // test defaults
-        $c = \SimpleSAML_Configuration::loadFromArray(array(), '', 'simplesaml');
+        // test default
+        $c = Configuration::loadFromArray([], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('en');
-        $this->assertEquals(array('en' => true), $l->getLanguageList());
+        $this->assertEquals(['en' => true], $l->getLanguageList());
     }
 
 
@@ -72,16 +71,16 @@ class LanguageTest extends TestCase
     public function testGetLanguageListCorrectConfig()
     {
         // test langs from from language_names
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('en', 'nn', 'es'),
-        ), '', 'simplesaml');
+        $c = Configuration::loadFromArray([
+            'language.available' => ['en', 'nn', 'es'],
+        ], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('es');
-        $this->assertEquals(array(
+        $this->assertEquals([
             'en' => false,
             'es' => true,
             'nn' => false,
-        ), $l->getLanguageList());
+        ], $l->getLanguageList());
     }
 
 
@@ -91,12 +90,12 @@ class LanguageTest extends TestCase
     public function testGetLanguageListIncorrectConfig()
     {
         // test non-existent langs
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('foo', 'bar'),
-        ), '', 'simplesaml');
+        $c = Configuration::loadFromArray([
+            'language.available' => ['foo', 'bar'],
+        ], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('foo');
-        $this->assertEquals(array('en' => true), $l->getLanguageList());
+        $this->assertEquals(['en' => true], $l->getLanguageList());
     }
 
 
@@ -106,14 +105,14 @@ class LanguageTest extends TestCase
     public function testGetLanguageParameterName()
     {
         // test for default configuration
-        $c = \SimpleSAML_Configuration::loadFromArray(array(), '', 'simplesaml');
+        $c = Configuration::loadFromArray([], '', 'simplesaml');
         $l = new Language($c);
         $this->assertEquals('language', $l->getLanguageParameterName());
 
         // test for valid configuration
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
+        $c = Configuration::loadFromArray([
             'language.parameter.name' => 'xyz'
-        ), '', 'simplesaml');
+        ], '', 'simplesaml');
         $l = new Language($c);
         $this->assertEquals('xyz', $l->getLanguageParameterName());
     }
@@ -125,24 +124,24 @@ class LanguageTest extends TestCase
     public function testIsLanguageRTL()
     {
         // test defaults
-        $c = \SimpleSAML_Configuration::loadFromArray(array(), '', 'simplesaml');
+        $c = Configuration::loadFromArray([], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('en');
         $this->assertFalse($l->isLanguageRTL());
 
         // test non-defaults, non-RTL
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.rtl' => array('foo', 'bar'),
-        ), '', 'simplesaml');
+        $c = Configuration::loadFromArray([
+            'language.rtl' => ['foo', 'bar'],
+        ], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('en');
         $this->assertFalse($l->isLanguageRTL());
 
         // test non-defaults, RTL
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('en', 'nn', 'es'),
-            'language.rtl' => array('nn', 'es'),
-        ), '', 'simplesaml');
+        $c = Configuration::loadFromArray([
+            'language.available' => ['en', 'nn', 'es'],
+            'language.rtl' => ['nn', 'es'],
+        ], '', 'simplesaml');
         $l = new Language($c);
         $l->setLanguage('es');
         $this->assertTrue($l->isLanguageRTL());
@@ -155,11 +154,11 @@ class LanguageTest extends TestCase
     public function testSetLanguage()
     {
         // test with valid configuration, no cookies set
-        $c = \SimpleSAML_Configuration::loadFromArray(array(
-            'language.available' => array('en', 'nn', 'es'),
+        $c = Configuration::loadFromArray([
+            'language.available' => ['en', 'nn', 'es'],
             'language.parameter.name' => 'xyz',
             'language.parameter.setcookie' => false,
-        ), '', 'simplesaml');
+        ], '', 'simplesaml');
         $_GET['xyz'] = 'Es'; // test also that lang code is transformed to lower caps
         $l = new Language($c);
         $this->assertEquals('es', $l->getLanguage());
diff --git a/tests/lib/SimpleSAML/Locale/LocalizationTest.php b/tests/lib/SimpleSAML/Locale/LocalizationTest.php
index d38af4add61227531ff0710238450c7c8a1e7c56..cc58f1ebe66632efcd6ffac4b9d4ce21e5391c8a 100644
--- a/tests/lib/SimpleSAML/Locale/LocalizationTest.php
+++ b/tests/lib/SimpleSAML/Locale/LocalizationTest.php
@@ -4,15 +4,14 @@ namespace SimpleSAML\Test\Locale;
 
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Locale\Localization;
-use \SimpleSAML_Configuration as Configuration;
-
+use \SimpleSAML\Configuration;
 
 class LocalizationTest extends TestCase
 {
     protected function setUp()
     {
         // Localization/Language code attempts to load a cookie, and looks in the config for a name of the cookie
-        Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
+        Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
     }
 
 
@@ -22,8 +21,8 @@ class LocalizationTest extends TestCase
     public function testLocalization()
     {
         // The constructor should activate the default domain
-        $c = \SimpleSAML_Configuration::loadFromArray(
-            array('language.i18n.backend' => 'SimpleSAMLphp')
+        $c = Configuration::loadFromArray(
+            ['language.i18n.backend' => 'SimpleSAMLphp']
         );
         $l = new Localization($c);
         $this->assertTrue($l->isI18NBackendDefault());
@@ -35,8 +34,8 @@ class LocalizationTest extends TestCase
      */
     public function testAddDomain()
     {
-        $c = \SimpleSAML_Configuration::loadFromArray(
-            array('language.i18n.backend' => 'gettext/gettext')
+        $c = Configuration::loadFromArray(
+            ['language.i18n.backend' => 'gettext/gettext']
         );
         $l = new Localization($c);
         $newDomain = 'test';
@@ -46,5 +45,4 @@ class LocalizationTest extends TestCase
         $this->assertArrayHasKey($newDomain, $registeredDomains);
         $this->assertEquals($registeredDomains[$newDomain], $newDomainLocaleDir);
     }
-
 }
diff --git a/tests/lib/SimpleSAML/Locale/TranslateTest.php b/tests/lib/SimpleSAML/Locale/TranslateTest.php
index 93d6c441ba830b160c79f06925426331ccb082ff..b1266df4256afdb2f289603e3d82079090eadc6f 100644
--- a/tests/lib/SimpleSAML/Locale/TranslateTest.php
+++ b/tests/lib/SimpleSAML/Locale/TranslateTest.php
@@ -14,7 +14,7 @@ class TranslateTest extends TestCase
     public function testNoop()
     {
         // test default
-        $c = \SimpleSAML_Configuration::loadFromArray(array());
+        $c = \SimpleSAML\Configuration::loadFromArray([]);
         $t = new Translate($c);
         $testString = 'Blablabla';
         $this->assertEquals($testString, $t->noop($testString));
@@ -25,7 +25,7 @@ class TranslateTest extends TestCase
      */
     public function testTFallback()
     {
-        $c = \SimpleSAML_Configuration::loadFromArray(array());
+        $c = \SimpleSAML\Configuration::loadFromArray([]);
         $t = new Translate($c);
         $testString = 'Blablabla';
 
@@ -34,6 +34,6 @@ class TranslateTest extends TestCase
         $this->assertEquals($result, $t->t($testString));
 
         // $fallbackdefault = false, should be a noop
-        $this->assertEquals($testString, $t->t($testString, array(), false));
+        $this->assertEquals($testString, $t->t($testString, [], false));
     }
 }
diff --git a/tests/lib/SimpleSAML/Metadata/MetaDataStorageSourceTest.php b/tests/lib/SimpleSAML/Metadata/MetaDataStorageSourceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7e8f918f7f0af6703f3df62fdfafee039bf267ad
--- /dev/null
+++ b/tests/lib/SimpleSAML/Metadata/MetaDataStorageSourceTest.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace SimpleSAML\Test\Metadata;
+
+/**
+ * Class MetaDataStorageSourceTest
+ */
+
+class MetaDataStorageSourceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Test \SimpleSAML\Metadata\MetaDataStorageSourceTest::getConfig XML bad source
+     * @expectedException \Exception
+     */
+    public function testBadXMLSource()
+    {
+        \SimpleSAML\Metadata\MetaDataStorageSource::getSource(["type"=>"xml", "foo"=>"baa"]);
+    }
+
+    /**
+     * Test \SimpleSAML\Metadata\MetaDataStorageSourceTest::getConfig invalid static XML source
+     * @expectedException Exception
+     */
+    public function testInvalidStaticXMLSource()
+    {
+        $strTestXML = "
+<EntityDescriptor ID=\"_12345678-90ab-cdef-1234-567890abcdef\" entityID=\"https://saml.idp/entityid\" xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\">
+</EntityDescriptor>
+";
+        \SimpleSAML\Metadata\MetaDataStorageSource::getSource(["type"=>"xml", "xml"=>$strTestXML]);
+    }
+
+    /**
+     * Test \SimpleSAML\Metadata\MetaDataStorageSourceTest::getConfig XML static XML source
+     */
+    public function testStaticXMLSource()
+    {
+        $testEntityId = "https://saml.idp/entityid";
+        $strTestXML = "
+<EntityDescriptor ID=\"_12345678-90ab-cdef-1234-567890abcdef\" entityID=\"$testEntityId\" xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\">
+<RoleDescriptor xsi:type=\"fed:ApplicationServiceType\"
+protocolSupportEnumeration=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512 http://schemas.xmlsoap.org/ws/2005/02/trust http://docs.oasis-open.org/wsfed/federation/200706\"
+ServiceDisplayName=\"SimpleSAMLphp Test\"
+xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
+xmlns:fed=\"http://docs.oasis-open.org/wsfed/federation/200706\">
+<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
+<SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://saml.idp/sso/\"/>
+<SingleLogoutService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"https://saml.idp/logout/\"/>
+</RoleDescriptor>
+<IDPSSODescriptor protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\"/>
+</EntityDescriptor>
+";
+        // The primary test here is that - in contrast to the others above - this loads without error
+        // As a secondary thing, check that the entity ID from the static source provided can be extracted
+        $source = \SimpleSAML\Metadata\MetaDataStorageSource::getSource(["type"=>"xml", "xml"=>$strTestXML]);
+        $idpSet = $source->getMetadataSet("saml20-idp-remote");
+        $this->assertArrayHasKey($testEntityId, $idpSet, "Did not extract expected IdP entity ID from static XML source");
+        // Finally verify that a different entity ID does not get loaded
+        $this->assertCount(1, $idpSet, "Unexpectedly got metadata for an alternate entity than that defined");
+    }
+}
diff --git a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php
index d9aa96a5a60c8d9778655eb78f0769c300b96aff..008a26063c5278b949007add51ac873bb0aa8b60 100644
--- a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php
+++ b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php
@@ -1,13 +1,16 @@
 <?php
 
+namespace SimpleSAML\Test\Metadata;
+
 use PHPUnit\Framework\TestCase;
+use SimpleSAML\Metadata\SAMLBuilder;
 
 /**
- * Class SimpleSAML_Metadata_SAMLBuilderTest
+ * Class SAMLBuilderTest
  */
-class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
-{
 
+class SAMLBuilderTest extends TestCase
+{
     /**
      * Test the requested attributes are valued correctly.
      */
@@ -17,19 +20,19 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
 
         //  test SP20 array parsing, no friendly name
         $set = 'saml20-sp-remote';
-        $metadata = array(
+        $metadata = [
             'entityid'     => $entityId,
-            'name'         => array('en' => 'Test SP'),
+            'name'         => ['en' => 'Test SP'],
             'metadata-set' => $set,
-            'attributes'   => array(
+            'attributes'   => [
                 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
                 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
                 'urn:oid:0.9.2342.19200300.100.1.3',
                 'urn:oid:2.5.4.3',
-            ),
-        );
+            ],
+        ];
 
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
 
         $spDesc = $samlBuilder->getEntityDescriptor();
@@ -46,19 +49,19 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
 
         // test SP20 array parsing, no friendly name
         $set = 'saml20-sp-remote';
-        $metadata = array(
+        $metadata = [
             'entityid'     => $entityId,
-            'name'         => array('en' => 'Test SP'),
+            'name'         => ['en' => 'Test SP'],
             'metadata-set' => $set,
-            'attributes'   => array(
+            'attributes'   => [
                 'eduPersonTargetedID'    => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
                 'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
                 'eduPersonOrgDN'         => 'urn:oid:0.9.2342.19200300.100.1.3',
                 'cn'                     => 'urn:oid:2.5.4.3',
-            ),
-        );
+            ],
+        ];
 
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
 
         $spDesc = $samlBuilder->getEntityDescriptor();
@@ -77,19 +80,19 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
 
         //  test SP13 array parsing, no friendly name
         $set = 'shib13-sp-remote';
-        $metadata = array(
+        $metadata = [
             'entityid'     => $entityId,
-            'name'         => array('en' => 'Test SP'),
+            'name'         => ['en' => 'Test SP'],
             'metadata-set' => $set,
-            'attributes'   => array(
+            'attributes'   => [
                 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
                 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
                 'urn:oid:0.9.2342.19200300.100.1.3',
                 'urn:oid:2.5.4.3',
-            ),
-        );
+            ],
+        ];
 
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
 
         $spDesc = $samlBuilder->getEntityDescriptor();
@@ -106,19 +109,19 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
 
         // test SP20 array parsing, no friendly name
         $set = 'shib13-sp-remote';
-        $metadata = array(
+        $metadata = [
             'entityid'     => $entityId,
-            'name'         => array('en' => 'Test SP'),
+            'name'         => ['en' => 'Test SP'],
             'metadata-set' => $set,
-            'attributes'   => array(
+            'attributes'   => [
                 'eduPersonTargetedID'    => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
                 'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
                 'eduPersonOrgDN'         => 'urn:oid:0.9.2342.19200300.100.1.3',
                 'cn'                     => 'urn:oid:2.5.4.3',
-            ),
-        );
+            ],
+        ];
 
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
 
         $spDesc = $samlBuilder->getEntityDescriptor();
@@ -136,6 +139,92 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
         }
     }
 
+    /**
+     * Test the working of the isDefault config option
+     */
+    public function testAttributeConsumingServiceDefault()
+    {
+        $entityId = 'https://entity.example.com/id';
+        $set = 'saml20-sp-remote';
+
+        $metadata = [
+            'entityid'     => $entityId,
+            'name'         => ['en' => 'Test SP'],
+            'metadata-set' => $set,
+            'attributes'   => [
+                'eduPersonTargetedID'    => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
+                'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
+            ],
+        ];
+
+        $samlBuilder = new SAMLBuilder($entityId);
+        $samlBuilder->addMetadata($set, $metadata);
+
+        $spDesc = $samlBuilder->getEntityDescriptor();
+        $acs = $spDesc->getElementsByTagName("AttributeConsumingService");
+        $acs1 = $acs->item(0);
+        $this->assertFalse($acs1->hasAttribute("isDefault"));
+
+        $metadata['attributes.isDefault'] = true;
+
+        $samlBuilder = new SAMLBuilder($entityId);
+        $samlBuilder->addMetadata($set, $metadata);
+        $spDesc = $samlBuilder->getEntityDescriptor();
+        $acs = $spDesc->getElementsByTagName("AttributeConsumingService");
+        $acs1 = $acs->item(0);
+        $this->assertTrue($acs1->hasAttribute("isDefault"));
+        $this->assertEquals("true", $acs1->getAttribute("isDefault"));
+
+        $metadata['attributes.isDefault'] = false;
+
+        $samlBuilder = new SAMLBuilder($entityId);
+        $samlBuilder->addMetadata($set, $metadata);
+        $spDesc = $samlBuilder->getEntityDescriptor();
+        $acs = $spDesc->getElementsByTagName("AttributeConsumingService");
+        $acs1 = $acs->item(0);
+        $this->assertTrue($acs1->hasAttribute("isDefault"));
+        $this->assertEquals("false", $acs1->getAttribute("isDefault"));
+    }
+
+    /**
+     * Test the index option is used correctly.
+     */
+    public function testAttributeConsumingServiceIndex()
+    {
+        $entityId = 'https://entity.example.com/id';
+        $set = 'saml20-sp-remote';
+
+        $metadata = [
+            'entityid'     => $entityId,
+            'name'         => ['en' => 'Test SP'],
+            'metadata-set' => $set,
+            'attributes'   => [
+                'eduPersonTargetedID'    => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10',
+                'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6',
+            ],
+        ];
+
+        $samlBuilder = new SAMLBuilder($entityId);
+        $samlBuilder->addMetadata($set, $metadata);
+
+        $spDesc = $samlBuilder->getEntityDescriptor();
+        $acs = $spDesc->getElementsByTagName("AttributeConsumingService");
+        $acs1 = $acs->item(0);
+        $this->assertTrue($acs1->hasAttribute("index"));
+        $this->assertEquals("0", $acs1->getAttribute("index"));
+
+        $metadata['attributes.index'] = 15;
+
+        $samlBuilder = new SAMLBuilder($entityId);
+        $samlBuilder->addMetadata($set, $metadata);
+
+        $spDesc = $samlBuilder->getEntityDescriptor();
+        $acs = $spDesc->getElementsByTagName("AttributeConsumingService");
+        $acs1 = $acs->item(0);
+        $this->assertTrue($acs1->hasAttribute("index"));
+        $this->assertEquals("15", $acs1->getAttribute("index"));
+    }
+
     /**
      * Test the required protocolSupportEnumeration in AttributeAuthorityDescriptor
      */
@@ -145,21 +234,21 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
         $set = 'attributeauthority-remote';
 
         // without protocolSupportEnumeration fallback to default: urn:oasis:names:tc:SAML:2.0:protocol
-        $metadata = array(
+        $metadata = [
             'entityid'     => $entityId,
-            'name'         => array('en' => 'Test AA'),
+            'name'         => ['en' => 'Test AA'],
             'metadata-set' => $set,
             'AttributeService' =>
-                array (
+                [
                     0 =>
-                        array (
+                        [
                             'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP',
                             'Location' => 'https://entity.example.com:8443/idp/profile/SAML2/SOAP/AttributeQuery',
-                        ),
-                ),
-            );
+                        ],
+                ],
+        ];
 
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
         $entityDescriptorXml = $samlBuilder->getEntityDescriptorText();
 
@@ -170,11 +259,11 @@ class SimpleSAML_Metadata_SAMLBuilderTest extends TestCase
 
         // explicit protocols
         $metadata['protocols'] =
-            array(
+            [
                 0 => 'urn:oasis:names:tc:SAML:1.1:protocol',
                 1 => 'urn:oasis:names:tc:SAML:2.0:protocol',
-            );
-        $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId);
+            ];
+        $samlBuilder = new SAMLBuilder($entityId);
         $samlBuilder->addMetadata($set, $metadata);
         $entityDescriptorXml = $samlBuilder->getEntityDescriptorText();
 
diff --git a/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php b/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php
index 0e34ad063e006f336fe978f7178a51a516eea086..a443d0e313f0acca03e12101d47189deeb9f44c5 100644
--- a/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php
+++ b/tests/lib/SimpleSAML/Metadata/SAMLParserTest.php
@@ -1,5 +1,6 @@
 <?php
-namespace SimpleSAML\Metadata;
+
+namespace SimpleSAML\Test\Metadata;
 
 use PHPUnit\Framework\TestCase;
 
@@ -8,15 +9,14 @@ use PHPUnit\Framework\TestCase;
  */
 class SAMLParserTest extends TestCase
 {
-
     /**
      * Test Registration Info is parsed
      */
     public function testRegistrationInfo()
     {
-        $expected = array(
+        $expected = [
             'registrationAuthority' => 'https://incommon.org',
-        );
+        ];
 
         $document = \SAML2\DOMDocumentFactory::fromString(
             <<<XML
@@ -32,12 +32,11 @@ XML
         );
 
 
-        $entities = \SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($document->documentElement);
+        $entities = \SimpleSAML\Metadata\SAMLParser::parseDescriptorsElement($document->documentElement);
         $this->assertArrayHasKey('theEntityID', $entities);
         // RegistrationInfo is accessible in the SP or IDP metadata accessors
         $metadata = $entities['theEntityID']->getMetadata20SP();
         $this->assertEquals($expected, $metadata['RegistrationInfo']);
-
     }
 
     /**
@@ -46,9 +45,9 @@ XML
      */
     public function testRegistrationInfoInheritance()
     {
-        $expected = array(
+        $expected = [
             'registrationAuthority' => 'https://incommon.org',
-        );
+        ];
 
         $document = \SAML2\DOMDocumentFactory::fromString(
             <<<XML
@@ -74,7 +73,7 @@ XML
 XML
         );
 
-        $entities = \SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($document->documentElement);
+        $entities = \SimpleSAML\Metadata\SAMLParser::parseDescriptorsElement($document->documentElement);
         $this->assertArrayHasKey('theEntityID', $entities);
         $this->assertArrayHasKey('subEntityId', $entities);
         // RegistrationInfo is accessible in the SP or IDP metadata accessors
@@ -116,7 +115,7 @@ XML
 XML
         );
 
-        $entities = \SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($document->documentElement);
+        $entities = \SimpleSAML\Metadata\SAMLParser::parseDescriptorsElement($document->documentElement);
         $this->assertArrayHasKey('theEntityID', $entities);
 
         $metadata = $entities['theEntityID']->getMetadata20SP();
@@ -124,11 +123,14 @@ XML
         $this->assertEquals("Example service", $metadata['name']['en']);
         $this->assertEquals("Dit is een voorbeeld voor de unittest.", $metadata['description']['nl']);
 
-        $expected_a = array("urn:mace:dir:attribute-def:eduPersonPrincipalName", "urn:mace:dir:attribute-def:mail", "urn:mace:dir:attribute-def:displayName");
-        $expected_r = array("urn:mace:dir:attribute-def:eduPersonPrincipalName");
+        $expected_a = [
+            "urn:mace:dir:attribute-def:eduPersonPrincipalName",
+            "urn:mace:dir:attribute-def:mail",
+            "urn:mace:dir:attribute-def:displayName"
+        ];
+        $expected_r = ["urn:mace:dir:attribute-def:eduPersonPrincipalName"];
 
         $this->assertEquals($expected_a, $metadata['attributes']);
         $this->assertEquals($expected_r, $metadata['attributes.required']);
     }
-
 }
diff --git a/tests/lib/SimpleSAML/ModuleTest.php b/tests/lib/SimpleSAML/ModuleTest.php
index 00cff258cabf8d7246cbcebedca1ebd80cc27968..a0c72b5f58d7ee4ab7a744b4dd6f58dab16e5a11 100644
--- a/tests/lib/SimpleSAML/ModuleTest.php
+++ b/tests/lib/SimpleSAML/ModuleTest.php
@@ -1,4 +1,5 @@
 <?php
+
 namespace SimpleSAML\Test;
 
 use PHPUnit\Framework\TestCase;
@@ -6,8 +7,6 @@ use SimpleSAML\Module;
 
 class ModuleTest extends TestCase
 {
-
-
     /**
      * Test for SimpleSAML\Module::isModuleEnabled().
      */
@@ -36,19 +35,19 @@ class ModuleTest extends TestCase
      */
     public function testGetModuleURL()
     {
-        \SimpleSAML_Configuration::loadFromArray(array(
+        \SimpleSAML\Configuration::loadFromArray([
             'baseurlpath' => 'https://example.com/simplesaml/'
-        ), '', 'simplesaml');
+        ], '', 'simplesaml');
         $this->assertEquals(
             'https://example.com/simplesaml/module.php/module/script.php',
             Module::getModuleURL('module/script.php')
         );
         $this->assertEquals(
             'https://example.com/simplesaml/module.php/module/script.php?param1=value1&param2=value2',
-            Module::getModuleURL('module/script.php', array(
+            Module::getModuleURL('module/script.php', [
                 'param1' => 'value1',
                 'param2' => 'value2',
-            ))
+            ])
         );
     }
 
@@ -108,13 +107,16 @@ class ModuleTest extends TestCase
         $this->assertEquals('sspmod_core_ACL', Module::resolveClass('core:ACL', ''));
 
         // test for the $type parameter correctly translated into a path
-        $this->assertEquals('sspmod_core_Auth_Process_PHP', Module::resolveClass('core:PHP', 'Auth_Process'));
+        $this->assertEquals(
+            '\SimpleSAML\Module\core\Auth\Process\PHP',
+            Module::resolveClass('core:PHP', 'Auth_Process')
+        );
 
         // test for valid subclasses
-        $this->assertEquals('sspmod_core_Auth_Process_PHP', Module::resolveClass(
+        $this->assertEquals('\SimpleSAML\Module\core\Auth\Process\PHP', Module::resolveClass(
             'core:PHP',
-            'Auth_Process',
-            'SimpleSAML_Auth_ProcessingFilter'
+            'Auth\Process',
+            '\SimpleSAML\Auth\ProcessingFilter'
         ));
     }
 }
diff --git a/tests/lib/SimpleSAML/Store/RedisTest.php b/tests/lib/SimpleSAML/Store/RedisTest.php
index d17f4473a3f99b48db61f1e2b52f76aebbc23f0b..7774a5dd211cf72b069bd9535bdbb592a3110890 100644
--- a/tests/lib/SimpleSAML/Store/RedisTest.php
+++ b/tests/lib/SimpleSAML/Store/RedisTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\Store;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Store;
 
 /**
@@ -18,24 +18,24 @@ class RedisTest extends TestCase
 {
     protected function setUp()
     {
-        $this->config = array();
+        $this->config = [];
 
         $this->mocked_redis = $this->getMockBuilder('Predis\Client')
-                                   ->setMethods(array('get', 'set', 'setex', 'del', 'disconnect'))
+                                   ->setMethods(['get', 'set', 'setex', 'del', 'disconnect'])
                                    ->disableOriginalConstructor()
                                    ->getMock();
 
         $this->mocked_redis->method('get')
-                           ->will($this->returnCallback(array($this, 'getMocked')));
+                           ->will($this->returnCallback([$this, 'getMocked']));
 
         $this->mocked_redis->method('set')
-                           ->will($this->returnCallback(array($this, 'setMocked')));
+                           ->will($this->returnCallback([$this, 'setMocked']));
 
         $this->mocked_redis->method('setex')
-                           ->will($this->returnCallback(array($this, 'setexMocked')));
+                           ->will($this->returnCallback([$this, 'setexMocked']));
 
         $this->mocked_redis->method('del')
-                           ->will($this->returnCallback(array($this, 'delMocked')));
+                           ->will($this->returnCallback([$this, 'delMocked']));
 
         $nop = function () {
             return;
@@ -75,16 +75,16 @@ class RedisTest extends TestCase
      */
     public function testRedisInstance()
     {
-        $config = Configuration::loadFromArray(array(
+        $config = Configuration::loadFromArray([
             'store.type' => 'redis',
             'store.redis.prefix' => 'phpunit_',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
         $this->assertInstanceOf('SimpleSAML\Store\Redis', $store);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
         $this->clearInstance($store, '\SimpleSAML\Store');
     }
 
diff --git a/tests/lib/SimpleSAML/Store/SQLTest.php b/tests/lib/SimpleSAML/Store/SQLTest.php
index 66170ab19fd77d6c3485043475e7bf56a47bc8f9..cda9dc2908bbdadd580ee2abaf2089380180b84d 100644
--- a/tests/lib/SimpleSAML/Store/SQLTest.php
+++ b/tests/lib/SimpleSAML/Store/SQLTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\Store;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Store;
 
 /**
@@ -19,11 +19,11 @@ class SQLTest extends TestCase
 {
     protected function setUp()
     {
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'store.type'                    => 'sql',
             'store.sql.dsn'                 => 'sqlite::memory:',
             'store.sql.prefix'              => 'phpunit_',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
     }
 
     /**
@@ -176,7 +176,7 @@ class SQLTest extends TestCase
         $config = Configuration::getInstance();
         $store = Store::getInstance();
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
         $this->clearInstance($store, '\SimpleSAML\Store');
     }
 
diff --git a/tests/lib/SimpleSAML/StoreTest.php b/tests/lib/SimpleSAML/StoreTest.php
index 22641681dcd9143f351226d9d55797854ed811f9..ebaa1c5fb09b7d23e52ffdec3bc47746ae5e76e5 100644
--- a/tests/lib/SimpleSAML/StoreTest.php
+++ b/tests/lib/SimpleSAML/StoreTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Store;
 
 /**
@@ -23,8 +23,8 @@ class StoreTest extends TestCase
      */
     public function defaultStore()
     {
-        Configuration::loadFromArray(array(
-        ), '[ARRAY]', 'simplesaml');
+        Configuration::loadFromArray([
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
@@ -38,8 +38,8 @@ class StoreTest extends TestCase
      */
     public function phpSessionStore()
     {
-        Configuration::loadFromArray(array(
-        ), '[ARRAY]', 'simplesaml');
+        Configuration::loadFromArray([
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
@@ -53,9 +53,9 @@ class StoreTest extends TestCase
      */
     public function memcacheStore()
     {
-        Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'store.type'                    => 'memcache',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
@@ -69,11 +69,11 @@ class StoreTest extends TestCase
      */
     public function sqlStore()
     {
-        Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'store.type'                    => 'sql',
             'store.sql.dsn'                 => 'sqlite::memory:',
             'store.sql.prefix'              => 'phpunit_',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
@@ -87,11 +87,11 @@ class StoreTest extends TestCase
      */
     public function pathStore()
     {
-        Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'store.type'                    => '\SimpleSAML\Store\SQL',
             'store.sql.dsn'                 => 'sqlite::memory:',
             'store.sql.prefix'              => 'phpunit_',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $store = Store::getInstance();
 
@@ -106,11 +106,11 @@ class StoreTest extends TestCase
      */
     public function notFoundStoreException()
     {
-        Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'store.type'                    => '\Test\SimpleSAML\Store\Dummy',
             'store.sql.dsn'                 => 'sqlite::memory:',
             'store.sql.prefix'              => 'phpunit_',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         Store::getInstance();
     }
@@ -121,7 +121,7 @@ class StoreTest extends TestCase
         $config = Configuration::getInstance();
         $store = Store::getInstance();
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
         $this->clearInstance($store, '\SimpleSAML\Store');
     }
 
diff --git a/tests/lib/SimpleSAML/Utils/ArraysTest.php b/tests/lib/SimpleSAML/Utils/ArraysTest.php
index 0ec3e29bdf74250eb7a098fa230647db0e54f96f..eb3d1b66843ff302c0bb6657ea7786b2b36db698 100644
--- a/tests/lib/SimpleSAML/Utils/ArraysTest.php
+++ b/tests/lib/SimpleSAML/Utils/ArraysTest.php
@@ -10,30 +10,29 @@ use SimpleSAML\Utils\Arrays;
  */
 class ArraysTest extends TestCase
 {
-
     /**
      * Test the arrayize() function.
      */
     public function testArrayize()
     {
         // check with empty array as input
-        $array = array();
+        $array = [];
         $this->assertEquals($array, Arrays::arrayize($array));
 
         // check non-empty array as input
-        $array = array('key' => 'value');
+        $array = ['key' => 'value'];
         $this->assertEquals($array, Arrays::arrayize($array));
 
         // check indexes are ignored when input is an array
         $this->assertArrayNotHasKey('invalid', Arrays::arrayize($array, 'invalid'));
 
         // check default index
-        $expected = array('string');
+        $expected = ['string'];
         $this->assertEquals($expected, Arrays::arrayize($expected[0]));
 
         // check string index
         $index = 'key';
-        $expected = array($index => 'string');
+        $expected = [$index => 'string'];
         $this->assertEquals($expected, Arrays::arrayize($expected[$index], $index));
     }
 
@@ -48,33 +47,33 @@ class ArraysTest extends TestCase
 
         // check bad arrays
         $this->assertFalse(
-            Arrays::transpose(array('1', '2', '3')),
+            Arrays::transpose(['1', '2', '3']),
             'Invalid two-dimensional array was accepted'
         );
         $this->assertFalse(
-            Arrays::transpose(array('1' => 0, '2' => '0', '3' => array(0))),
+            Arrays::transpose(['1' => 0, '2' => '0', '3' => [0]]),
             'Invalid elements on a two-dimensional array were accepted'
         );
 
         // check array with numerical keys
-        $array = array(
-            'key1' => array(
+        $array = [
+            'key1' => [
                 'value1'
-            ),
-            'key2' => array(
+            ],
+            'key2' => [
                 'value1',
                 'value2'
-            )
-        );
-        $transposed = array(
-            array(
+            ]
+        ];
+        $transposed = [
+            [
                 'key1' => 'value1',
                 'key2' => 'value1'
-            ),
-            array(
+            ],
+            [
                 'key2' => 'value2'
-            )
-        );
+            ]
+        ];
         $this->assertEquals(
             $transposed,
             Arrays::transpose($array),
@@ -82,24 +81,24 @@ class ArraysTest extends TestCase
         );
 
         // check array with string keys
-        $array = array(
-            'key1' => array(
+        $array = [
+            'key1' => [
                 'subkey1' => 'value1'
-            ),
-            'key2' => array(
+            ],
+            'key2' => [
                 'subkey1' => 'value1',
                 'subkey2' => 'value2'
-            )
-        );
-        $transposed = array(
-            'subkey1' => array(
+            ]
+        ];
+        $transposed = [
+            'subkey1' => [
                 'key1' => 'value1',
                 'key2' => 'value1'
-            ),
-            'subkey2' => array(
+            ],
+            'subkey2' => [
                 'key2' => 'value2'
-            )
-        );
+            ]
+        ];
         $this->assertEquals(
             $transposed,
             Arrays::transpose($array),
@@ -107,26 +106,26 @@ class ArraysTest extends TestCase
         );
 
         // check array with no keys in common between sub arrays
-        $array = array(
-            'key1' => array(
+        $array = [
+            'key1' => [
                 'subkey1' => 'value1'
-            ),
-            'key2' => array(
+            ],
+            'key2' => [
                 'subkey2' => 'value1',
                 'subkey3' => 'value2'
-            )
-        );
-        $transposed = array(
-            'subkey1' => array(
+            ]
+        ];
+        $transposed = [
+            'subkey1' => [
                 'key1' => 'value1',
-            ),
-            'subkey2' => array(
+            ],
+            'subkey2' => [
                 'key2' => 'value1'
-            ),
-            'subkey3' => array(
+            ],
+            'subkey3' => [
                 'key2' => 'value2'
-            )
-        );
+            ]
+        ];
         $this->assertEquals(
             $transposed,
             Arrays::transpose($array),
diff --git a/tests/lib/SimpleSAML/Utils/AttributesTest.php b/tests/lib/SimpleSAML/Utils/AttributesTest.php
index 271b506848b0b76a1bcf4d6a94bac2d0b994fc09..42685215a8a07d09ff5eec620d26929379ee21d5 100644
--- a/tests/lib/SimpleSAML/Utils/AttributesTest.php
+++ b/tests/lib/SimpleSAML/Utils/AttributesTest.php
@@ -35,7 +35,7 @@ class AttributesTest extends TestCase
     public function testGetExpectedAttributeInvalidAttributeName()
     {
         // check with invalid attribute name
-        $attributes = array();
+        $attributes = [];
         $expected = false;
         $this->setExpectedException(
             'InvalidArgumentException',
@@ -51,9 +51,9 @@ class AttributesTest extends TestCase
     public function testGetExpectedAttributeNonNormalizedArray()
     {
         // check with non-normalized attributes array
-        $attributes = array(
+        $attributes = [
             'attribute' => 'value',
-        );
+        ];
         $expected = 'attribute';
         $this->setExpectedException(
             'InvalidArgumentException',
@@ -69,12 +69,12 @@ class AttributesTest extends TestCase
     public function testGetExpectedAttributeMissingAttribute()
     {
         // check missing attribute
-        $attributes = array(
-            'attribute' => array('value'),
-        );
+        $attributes = [
+            'attribute' => ['value'],
+        ];
         $expected = 'missing';
         $this->setExpectedException(
-            'SimpleSAML_Error_Exception',
+            '\SimpleSAML\Error\Exception',
             "No such attribute '".$expected."' found."
         );
         Attributes::getExpectedAttribute($attributes, $expected);
@@ -87,12 +87,12 @@ class AttributesTest extends TestCase
     public function testGetExpectedAttributeEmptyAttribute()
     {
         // check empty attribute
-        $attributes = array(
-            'attribute' => array(),
-        );
+        $attributes = [
+            'attribute' => [],
+        ];
         $expected = 'attribute';
         $this->setExpectedException(
-            'SimpleSAML_Error_Exception',
+            '\SimpleSAML\Error\Exception',
             "Empty attribute '".$expected."'.'"
         );
         Attributes::getExpectedAttribute($attributes, $expected);
@@ -105,15 +105,15 @@ class AttributesTest extends TestCase
     public function testGetExpectedAttributeMultipleValues()
     {
         // check attribute with more than value, that being not allowed
-        $attributes = array(
-            'attribute' => array(
+        $attributes = [
+            'attribute' => [
                 'value1',
                 'value2',
-            ),
-        );
+            ],
+        ];
         $expected = 'attribute';
         $this->setExpectedException(
-            'SimpleSAML_Error_Exception',
+            '\SimpleSAML\Error\Exception',
             'More than one value found for the attribute, multiple values not allowed.'
         );
         Attributes::getExpectedAttribute($attributes, $expected);
@@ -127,17 +127,17 @@ class AttributesTest extends TestCase
     {
         // check one value
         $value = 'value';
-        $attributes = array(
-            'attribute' => array($value),
-        );
+        $attributes = [
+            'attribute' => [$value],
+        ];
         $expected = 'attribute';
         $this->assertEquals($value, Attributes::getExpectedAttribute($attributes, $expected));
 
         // check multiple (allowed) values
         $value = 'value';
-        $attributes = array(
-            'attribute' => array($value, 'value2', 'value3'),
-        );
+        $attributes = [
+            'attribute' => [$value, 'value2', 'value3'],
+        ];
         $expected = 'attribute';
         $this->assertEquals($value, Attributes::getExpectedAttribute($attributes, $expected, true));
     }
@@ -160,7 +160,7 @@ class AttributesTest extends TestCase
      */
     public function testNormalizeAttributesArrayBadKeys()
     {
-        Attributes::normalizeAttributesArray(array('attr1' => 'value1', 1 => 'value2'));
+        Attributes::normalizeAttributesArray(['attr1' => 'value1', 1 => 'value2']);
     }
 
     /**
@@ -170,7 +170,7 @@ class AttributesTest extends TestCase
      */
     public function testNormalizeAttributesArrayBadValues()
     {
-        Attributes::normalizeAttributesArray(array('attr1' => 'value1', 'attr2' => 0));
+        Attributes::normalizeAttributesArray(['attr1' => 'value1', 'attr2' => 0]);
     }
 
     /**
@@ -178,16 +178,16 @@ class AttributesTest extends TestCase
      */
     public function testNormalizeAttributesArray()
     {
-        $attributes = array(
+        $attributes = [
             'key1' => 'value1',
-            'key2' => array('value2', 'value3'),
+            'key2' => ['value2', 'value3'],
             'key3' => 'value1'
-        );
-        $expected = array(
-            'key1' => array('value1'),
-            'key2' => array('value2', 'value3'),
-            'key3' => array('value1')
-        );
+        ];
+        $expected = [
+            'key1' => ['value1'],
+            'key2' => ['value2', 'value3'],
+            'key3' => ['value1']
+        ];
         $this->assertEquals(
             $expected,
             Attributes::normalizeAttributesArray($attributes),
@@ -203,13 +203,13 @@ class AttributesTest extends TestCase
     {
         // test for only the name
         $this->assertEquals(
-            array('default', 'name'),
+            ['default', 'name'],
             Attributes::getAttributeNamespace('name', 'default')
         );
 
         // test for a given namespace and multiple '/'
         $this->assertEquals(
-            array('some/namespace', 'name'),
+            ['some/namespace', 'name'],
             Attributes::getAttributeNamespace('some/namespace/name', 'default')
         );
     }
diff --git a/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php b/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php
index afcbb611e65b24fadd7e5a19a126ee718bf140e7..70edeb6fc73dcace42c5b60bd8fea106e08b079e 100644
--- a/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php
+++ b/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php
@@ -24,9 +24,9 @@ class MetadataTest extends TestCase
         }
 
         // test missing type
-        $contact = array(
+        $contact = [
             'name' => 'John Doe'
-        );
+        ];
         try {
             Metadata::getContact($contact);
         } catch (\InvalidArgumentException $e) {
@@ -34,9 +34,9 @@ class MetadataTest extends TestCase
         }
 
         // test invalid type
-        $contact = array(
+        $contact = [
             'contactType' => 'invalid'
-        );
+        ];
         try {
             Metadata::getContact($contact);
         } catch (\InvalidArgumentException $e) {
@@ -45,9 +45,9 @@ class MetadataTest extends TestCase
 
         // test all valid contact types
         foreach (Metadata::$VALID_CONTACT_TYPES as $type) {
-            $contact = array(
+            $contact = [
                 'contactType' => $type
-            );
+            ];
             $parsed = Metadata::getContact($contact);
             $this->assertArrayHasKey('contactType', $parsed);
             $this->assertArrayNotHasKey('givenName', $parsed);
@@ -55,10 +55,10 @@ class MetadataTest extends TestCase
         }
 
         // test basic name parsing
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
             'name'        => 'John Doe'
-        );
+        ];
         $parsed = Metadata::getContact($contact);
         $this->assertArrayNotHasKey('name', $parsed);
         $this->assertArrayHasKey('givenName', $parsed);
@@ -67,10 +67,10 @@ class MetadataTest extends TestCase
         $this->assertEquals('Doe', $parsed['surName']);
 
         // test comma-separated names
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
             'name'        => 'Doe, John'
-        );
+        ];
         $parsed = Metadata::getContact($contact);
         $this->assertArrayHasKey('givenName', $parsed);
         $this->assertArrayHasKey('surName', $parsed);
@@ -78,10 +78,10 @@ class MetadataTest extends TestCase
         $this->assertEquals('Doe', $parsed['surName']);
 
         // test long names
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
             'name'        => 'John Fitzgerald Doe Smith'
-        );
+        ];
         $parsed = Metadata::getContact($contact);
         $this->assertArrayNotHasKey('name', $parsed);
         $this->assertArrayHasKey('givenName', $parsed);
@@ -89,10 +89,10 @@ class MetadataTest extends TestCase
         $this->assertEquals('John Fitzgerald Doe Smith', $parsed['givenName']);
 
         // test comma-separated long names
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
             'name'        => 'Doe Smith, John Fitzgerald'
-        );
+        ];
         $parsed = Metadata::getContact($contact);
         $this->assertArrayNotHasKey('name', $parsed);
         $this->assertArrayHasKey('givenName', $parsed);
@@ -101,10 +101,10 @@ class MetadataTest extends TestCase
         $this->assertEquals('Doe Smith', $parsed['surName']);
 
         // test givenName
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
-        );
-        $invalid_types = array(0, array(0), 0.1, true, false);
+        ];
+        $invalid_types = [0, [0], 0.1, true, false];
         foreach ($invalid_types as $type) {
             $contact['givenName'] = $type;
             try {
@@ -115,10 +115,10 @@ class MetadataTest extends TestCase
         }
 
         // test surName
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
-        );
-        $invalid_types = array(0, array(0), 0.1, true, false);
+        ];
+        $invalid_types = [0, [0], 0.1, true, false];
         foreach ($invalid_types as $type) {
             $contact['surName'] = $type;
             try {
@@ -129,10 +129,10 @@ class MetadataTest extends TestCase
         }
 
         // test company
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
-        );
-        $invalid_types = array(0, array(0), 0.1, true, false);
+        ];
+        $invalid_types = [0, [0], 0.1, true, false];
         foreach ($invalid_types as $type) {
             $contact['company'] = $type;
             try {
@@ -143,10 +143,10 @@ class MetadataTest extends TestCase
         }
 
         // test emailAddress
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
-        );
-        $invalid_types = array(0, 0.1, true, false, array());
+        ];
+        $invalid_types = [0, 0.1, true, false, []];
         foreach ($invalid_types as $type) {
             $contact['emailAddress'] = $type;
             try {
@@ -158,7 +158,7 @@ class MetadataTest extends TestCase
                 );
             }
         }
-        $invalid_types = array(array("string", true), array("string", 0));
+        $invalid_types = [["string", true], ["string", 0]];
         foreach ($invalid_types as $type) {
             $contact['emailAddress'] = $type;
             try {
@@ -170,7 +170,7 @@ class MetadataTest extends TestCase
                 );
             }
         }
-        $valid_types = array('email@example.com', array('email1@example.com', 'email2@example.com'));
+        $valid_types = ['email@example.com', ['email1@example.com', 'email2@example.com']];
         foreach ($valid_types as $type) {
             $contact['emailAddress'] = $type;
             $parsed = Metadata::getContact($contact);
@@ -178,10 +178,10 @@ class MetadataTest extends TestCase
         }
 
         // test telephoneNumber
-        $contact = array(
+        $contact = [
             'contactType' => 'technical',
-        );
-        $invalid_types = array(0, 0.1, true, false, array());
+        ];
+        $invalid_types = [0, 0.1, true, false, []];
         foreach ($invalid_types as $type) {
             $contact['telephoneNumber'] = $type;
             try {
@@ -193,7 +193,7 @@ class MetadataTest extends TestCase
                 );
             }
         }
-        $invalid_types = array(array("string", true), array("string", 0));
+        $invalid_types = [["string", true], ["string", 0]];
         foreach ($invalid_types as $type) {
             $contact['telephoneNumber'] = $type;
             try {
@@ -202,7 +202,7 @@ class MetadataTest extends TestCase
                 $this->assertEquals('Telephone numbers must be a string and cannot be empty.', $e->getMessage());
             }
         }
-        $valid_types = array('1234', array('1234', '5678'));
+        $valid_types = ['1234', ['1234', '5678']];
         foreach ($valid_types as $type) {
             $contact['telephoneNumber'] = $type;
             $parsed = Metadata::getContact($contact);
@@ -210,13 +210,13 @@ class MetadataTest extends TestCase
         }
 
         // test completeness
-        $contact = array();
+        $contact = [];
         foreach (Metadata::$VALID_CONTACT_OPTIONS as $option) {
             $contact[$option] = 'string';
         }
         $contact['contactType'] = 'technical';
         $contact['name'] = 'to_be_removed';
-        $contact['attributes'] = array('test' => 'testval');
+        $contact['attributes'] = ['test' => 'testval'];
         $parsed = Metadata::getContact($contact);
         foreach (array_keys($parsed) as $key) {
             $this->assertEquals($parsed[$key], $contact[$key]);
@@ -231,33 +231,33 @@ class MetadataTest extends TestCase
     public function testIsHiddenFromDiscovery()
     {
         // test for success
-        $metadata = array(
-            'EntityAttributes' => array(
-                Metadata::$ENTITY_CATEGORY => array(
+        $metadata = [
+            'EntityAttributes' => [
+                Metadata::$ENTITY_CATEGORY => [
                     Metadata::$HIDE_FROM_DISCOVERY,
-                ),
-            ),
-        );
+                ],
+            ],
+        ];
         $this->assertTrue(Metadata::isHiddenFromDiscovery($metadata));
 
         // test for failures
-        $this->assertFalse(Metadata::isHiddenFromDiscovery(array('foo')));
-        $this->assertFalse(Metadata::isHiddenFromDiscovery(array(
+        $this->assertFalse(Metadata::isHiddenFromDiscovery(['foo']));
+        $this->assertFalse(Metadata::isHiddenFromDiscovery([
             'EntityAttributes' => 'bar',
-        )));
-        $this->assertFalse(Metadata::isHiddenFromDiscovery(array(
-            'EntityAttributes' => array(),
-        )));
-        $this->assertFalse(Metadata::isHiddenFromDiscovery(array(
-            'EntityAttributes' => array(
+        ]));
+        $this->assertFalse(Metadata::isHiddenFromDiscovery([
+            'EntityAttributes' => [],
+        ]));
+        $this->assertFalse(Metadata::isHiddenFromDiscovery([
+            'EntityAttributes' => [
                 Metadata::$ENTITY_CATEGORY => '',
-            ),
-        )));
-        $this->assertFalse(Metadata::isHiddenFromDiscovery(array(
-            'EntityAttributes' => array(
-                Metadata::$ENTITY_CATEGORY => array(),
-            ),
-        )));
+            ],
+        ]));
+        $this->assertFalse(Metadata::isHiddenFromDiscovery([
+            'EntityAttributes' => [
+                Metadata::$ENTITY_CATEGORY => [],
+            ],
+        ]));
     }
 
     
diff --git a/tests/lib/SimpleSAML/Utils/ConfigTest.php b/tests/lib/SimpleSAML/Utils/ConfigTest.php
index 262fbfd801837ef611fb738c69424fa5caaa41ea..6077a6301c45627eb860ac672343b29217ad21f0 100644
--- a/tests/lib/SimpleSAML/Utils/ConfigTest.php
+++ b/tests/lib/SimpleSAML/Utils/ConfigTest.php
@@ -20,7 +20,7 @@ class ConfigTest extends TestCase
         putenv('SIMPLESAMLPHP_CONFIG_DIR');
         $configDir = Config::getConfigDir();
 
-        $this->assertEquals($configDir, dirname(dirname(dirname(dirname(__DIR__)))) . '/config');
+        $this->assertEquals($configDir, dirname(dirname(dirname(dirname(__DIR__)))).'/config');
     }
 
 
@@ -29,12 +29,35 @@ class ConfigTest extends TestCase
      */
     public function testEnvVariableConfigDir()
     {
-        putenv('SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__);
+        putenv('SIMPLESAMLPHP_CONFIG_DIR='.__DIR__);
         $configDir = Config::getConfigDir();
 
         $this->assertEquals($configDir, __DIR__);
     }
 
+    /**
+     * Test valid dir specified by env redirect var overrides default config dir
+     */
+    public function testEnvRedirectVariableConfigDir()
+    {
+        putenv('REDIRECT_SIMPLESAMLPHP_CONFIG_DIR='.__DIR__);
+        $configDir = Config::getConfigDir();
+
+        $this->assertEquals($configDir, __DIR__);
+    }
+
+    /**
+     * Test which directory takes precedence
+     */
+    public function testEnvRedirectPriorityVariableConfigDir()
+    {
+        putenv('SIMPLESAMLPHP_CONFIG_DIR='.dirname(__DIR__));
+        putenv('REDIRECT_SIMPLESAMLPHP_CONFIG_DIR='.__DIR__);
+        $configDir = Config::getConfigDir();
+
+        $this->assertEquals($configDir, dirname(__DIR__));
+    }
+
 
     /**
      * Test invalid dir specified by env var results in a thrown exception
@@ -42,13 +65,13 @@ class ConfigTest extends TestCase
     public function testInvalidEnvVariableConfigDirThrowsException()
     {
         // I used a random hash to ensure this test directory is always invalid
-        $invalidDir = __DIR__ . '/e9826ad19cbc4f5bf20c0913ffcd2ce6';
-        putenv('SIMPLESAMLPHP_CONFIG_DIR=' . $invalidDir);
+        $invalidDir = __DIR__.'/e9826ad19cbc4f5bf20c0913ffcd2ce6';
+        putenv('SIMPLESAMLPHP_CONFIG_DIR='.$invalidDir);
 
         $this->setExpectedException(
             'InvalidArgumentException',
-            'Config directory specified by environment variable SIMPLESAMLPHP_CONFIG_DIR is not a directory.  ' .
-            'Given: "' . $invalidDir . '"'
+            'Config directory specified by environment variable SIMPLESAMLPHP_CONFIG_DIR is not a directory.  '.
+            'Given: "'.$invalidDir.'"'
         );
 
         Config::getConfigDir();
diff --git a/tests/lib/SimpleSAML/Utils/CryptoTest.php b/tests/lib/SimpleSAML/Utils/CryptoTest.php
index a47d0d432c938fe3001a6a0c2a4fb059937d77a0..23194596991d1cde678606bcb22061b0d012a0dd 100644
--- a/tests/lib/SimpleSAML/Utils/CryptoTest.php
+++ b/tests/lib/SimpleSAML/Utils/CryptoTest.php
@@ -4,7 +4,7 @@ namespace SimpleSAML\Test\Utils;
 
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Utils\Crypto;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 
 use \org\bovigo\vfs\vfsStream;
 
@@ -21,9 +21,9 @@ class CryptoTest extends TestCase
         $this->root = vfsStream::setup(
             self::ROOTDIRNAME,
             null,
-            array(
-                self::DEFAULTCERTDIR => array(),
-            )
+            [
+                self::DEFAULTCERTDIR => [],
+            ]
         );
         $this->root_directory = vfsStream::url(self::ROOTDIRNAME);
         $this->certdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTCERTDIR;
@@ -34,14 +34,14 @@ class CryptoTest extends TestCase
      *
      * @expectedException \InvalidArgumentException
      *
-     * @covers \SimpleSAML\Utils\Crypto::_aesDecrypt
+     * @covers \SimpleSAML\Utils\Crypto::aesDecrypt
      */
     public function testAesDecryptBadInput()
     {
         $m = new \ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesDecrypt');
         $m->setAccessible(true);
 
-        $m->invokeArgs(null, array(array(), 'SECRET'));
+        $m->invokeArgs(null, [[], 'SECRET']);
     }
 
 
@@ -50,14 +50,14 @@ class CryptoTest extends TestCase
      *
      * @expectedException \InvalidArgumentException
      *
-     * @covers \SimpleSAML\Utils\Crypto::_aesEncrypt
+     * @covers \SimpleSAML\Utils\Crypto::aesEncrypt
      */
     public function testAesEncryptBadInput()
     {
         $m = new \ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesEncrypt');
         $m->setAccessible(true);
 
-        $m->invokeArgs(null, array(array(), 'SECRET'));
+        $m->invokeArgs(null, [[], 'SECRET']);
     }
 
 
@@ -65,12 +65,12 @@ class CryptoTest extends TestCase
      * Test that aesDecrypt() works properly, being able to decrypt some previously known (and correct)
      * ciphertext.
      *
-     * @covers \SimpleSAML\Utils\Crypto::_aesDecrypt
+     * @covers \SimpleSAML\Utils\Crypto::aesDecrypt
      */
     public function testAesDecrypt()
     {
         if (!extension_loaded('openssl')) {
-            $this->setExpectedException('\SimpleSAML_Error_Exception');
+            $this->setExpectedException('\SimpleSAML\Error\Exception');
         }
 
         $secret = 'SUPER_SECRET_SALT';
@@ -79,20 +79,20 @@ class CryptoTest extends TestCase
 
         $plaintext = 'SUPER_SECRET_TEXT';
         $ciphertext = 'uR2Yu0r4itInKx91D/l9y/08L5CIQyev9nAr27fh3Sshous4vbXRRcMcjqHDOrquD+2vqLyw7ygnbA9jA9TpB4hLZocvAWcTN8tyO82hiSY=';
-        $this->assertEquals($plaintext, $m->invokeArgs(null, array(base64_decode($ciphertext), $secret)));
+        $this->assertEquals($plaintext, $m->invokeArgs(null, [base64_decode($ciphertext), $secret]));
     }
 
 
     /**
      * Test that aesEncrypt() produces ciphertexts that aesDecrypt() can decrypt.
      *
-     * @covers \SimpleSAML\Utils\Crypto::_aesDecrypt
-     * @covers \SimpleSAML\Utils\Crypto::_aesEncrypt
+     * @covers \SimpleSAML\Utils\Crypto::aesDecrypt
+     * @covers \SimpleSAML\Utils\Crypto::aesEncrypt
      */
     public function testAesEncrypt()
     {
         if (!extension_loaded('openssl')) {
-            $this->setExpectedException('\SimpleSAML_Error_Exception');
+            $this->setExpectedException('\SimpleSAML\Error\Exception');
         }
 
         $secret = 'SUPER_SECRET_SALT';
@@ -102,8 +102,8 @@ class CryptoTest extends TestCase
         $d->setAccessible(true);
 
         $original_plaintext = 'SUPER_SECRET_TEXT';
-        $ciphertext = $e->invokeArgs(null, array($original_plaintext, $secret));
-        $decrypted_plaintext = $d->invokeArgs(null, array($ciphertext, $secret));
+        $ciphertext = $e->invokeArgs(null, [$original_plaintext, $secret]);
+        $decrypted_plaintext = $d->invokeArgs(null, [$ciphertext, $secret]);
         $this->assertEquals($original_plaintext, $decrypted_plaintext);
     }
 
@@ -195,7 +195,7 @@ PHP;
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\Crypto::pwHash
      */
@@ -237,13 +237,12 @@ PHP;
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\Crypto::pwValid
      */
     public function testBadHashAlgorithmValid()
     {
-        $pw = "password";
         $algorithm = "wtf";
         $hash = "{".$algorithm."}B64STRING";
 
@@ -271,13 +270,13 @@ PHP;
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\Crypto::loadPrivateKey
      */
     public function testLoadPrivateKeyRequiredMetadataMissing()
     {
-        $config = new Configuration(array(), 'test');
+        $config = new Configuration([], 'test');
         $required = true;
 
         Crypto::loadPrivateKey($config, $required);
@@ -288,7 +287,7 @@ PHP;
      */
     public function testLoadPrivateKeyNotRequiredMetadataMissing()
     {
-        $config = new Configuration(array(), 'test');
+        $config = new Configuration([], 'test');
         $required = false;
 
         $res = Crypto::loadPrivateKey($config, $required);
@@ -297,13 +296,13 @@ PHP;
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\Crypto::loadPrivateKey
      */
     public function testLoadPrivateKeyMissingFile()
     {
-        $config = new Configuration(array('privatekey' => 'nonexistant'), 'test');
+        $config = new Configuration(['privatekey' => 'nonexistant'], 'test');
 
         Crypto::loadPrivateKey($config, false, '', true);
     }
@@ -315,13 +314,13 @@ PHP;
     {
         $filename = $this->certdir.DIRECTORY_SEPARATOR.'key';
         $data = 'data';
-        $config = new Configuration(array('privatekey' => $filename), 'test');
+        $config = new Configuration(['privatekey' => $filename], 'test');
         $full_path = true;
 
         file_put_contents($filename, $data);
 
         $res = Crypto::loadPrivateKey($config, false, '', $full_path);
-        $expected = array('PEM' => $data);
+        $expected = ['PEM' => $data];
 
         $this->assertEquals($expected, $res);
     }
@@ -335,10 +334,10 @@ PHP;
         $filename = $this->certdir.DIRECTORY_SEPARATOR.'key';
         $data = 'data';
         $config = new Configuration(
-            array(
+            [
                 'privatekey' => $filename,
                 'privatekey_pass' => $password,
-            ),
+            ],
             'test'
         );
         $full_path = true;
@@ -346,7 +345,7 @@ PHP;
         file_put_contents($filename, $data);
 
         $res = Crypto::loadPrivateKey($config, false, '', $full_path);
-        $expected = array('PEM' => $data, 'password' => $password);
+        $expected = ['PEM' => $data, 'password' => $password];
 
         $this->assertEquals($expected, $res);
     }
@@ -361,10 +360,10 @@ PHP;
         $filename = $this->certdir.DIRECTORY_SEPARATOR.'key';
         $data = 'data';
         $config = new Configuration(
-            array(
+            [
                 $prefix.'privatekey' => $filename,
                 $prefix.'privatekey_pass' => $password,
-            ),
+            ],
             'test'
         );
         $full_path = true;
@@ -372,19 +371,19 @@ PHP;
         file_put_contents($filename, $data);
 
         $res = Crypto::loadPrivateKey($config, false, $prefix, $full_path);
-        $expected = array('PEM' => $data, 'password' => $password);
+        $expected = ['PEM' => $data, 'password' => $password];
 
         $this->assertEquals($expected, $res);
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\Crypto::loadPublicKey
      */
     public function testLoadPublicKeyRequiredMetadataMissing()
     {
-        $config = new Configuration(array(), 'test');
+        $config = new Configuration([], 'test');
         $required = true;
 
         Crypto::loadPublicKey($config, $required);
@@ -395,7 +394,7 @@ PHP;
      */
     public function testLoadPublicKeyNotRequiredMetadataMissing()
     {
-        $config = new Configuration(array(), 'test');
+        $config = new Configuration([], 'test');
         $required = false;
 
         $res = Crypto::loadPublicKey($config, $required);
@@ -409,10 +408,10 @@ PHP;
     public function testLoadPublicKeyFingerprintBasicString()
     {
         $fingerprint = 'fingerprint';
-        $config = new Configuration(array('certFingerprint' => $fingerprint), 'test');
+        $config = new Configuration(['certFingerprint' => $fingerprint], 'test');
 
         $res = Crypto::loadPublicKey($config);
-        $expected = array('certFingerprint' => array($fingerprint));
+        $expected = ['certFingerprint' => [$fingerprint]];
 
         $this->assertEquals($expected, $res);
     }
@@ -425,17 +424,17 @@ PHP;
         $fingerprint1 = 'fingerprint1';
         $fingerprint2 = 'fingerprint2';
         $config = new Configuration(
-            array(
-                'certFingerprint' => array(
+            [
+                'certFingerprint' => [
                     $fingerprint1,
                     $fingerprint2
-                ),
-            ),
+                ],
+            ],
             'test'
         );
 
         $res = Crypto::loadPublicKey($config);
-        $expected = array('certFingerprint' => array($fingerprint1, $fingerprint2));
+        $expected = ['certFingerprint' => [$fingerprint1, $fingerprint2]];
 
         $this->assertEquals($expected, $res);
     }
@@ -446,10 +445,10 @@ PHP;
     public function testLoadPublicKeyFingerprintLowercase()
     {
         $fingerprint = 'FINGERPRINT';
-        $config = new Configuration(array('certFingerprint' => $fingerprint), 'test');
+        $config = new Configuration(['certFingerprint' => $fingerprint], 'test');
 
         $res = Crypto::loadPublicKey($config);
-        $expected = array('certFingerprint' => array(strtolower($fingerprint)));
+        $expected = ['certFingerprint' => [strtolower($fingerprint)]];
 
         $this->assertEquals($expected, $res);
     }
@@ -460,10 +459,10 @@ PHP;
     public function testLoadPublicKeyFingerprintRemoveColons()
     {
         $fingerprint = 'f:i:n:g:e:r:p:r:i:n:t';
-        $config = new Configuration(array('certFingerprint' => $fingerprint), 'test');
+        $config = new Configuration(['certFingerprint' => $fingerprint], 'test');
 
         $res = Crypto::loadPublicKey($config);
-        $expected = array('certFingerprint' => array(str_replace(':', '', $fingerprint)));
+        $expected = ['certFingerprint' => [str_replace(':', '', $fingerprint)]];
 
         $this->assertEquals($expected, $res);
     }
@@ -474,15 +473,15 @@ PHP;
     public function testLoadPublicKeyNotX509Certificate()
     {
         $config = new Configuration(
-            array(
-                'keys' => array(
-                    array(
+            [
+                'keys' => [
+                    [
                         'X509Certificate' => '',
                         'type' => 'NotX509Certificate',
                         'signing' => true
-                    ),
-                ),
-            ),
+                    ],
+                ],
+            ],
             'test'
         );
 
@@ -497,15 +496,15 @@ PHP;
     public function testLoadPublicKeyNotSigning()
     {
         $config = new Configuration(
-            array(
-                'keys' => array(
-                    array(
+            [
+                'keys' => [
+                    [
                         'X509Certificate' => '',
                         'type' => 'X509Certificate',
                         'signing' => false
-                    ),
-                ),
-            ),
+                    ],
+                ],
+            ],
             'test'
         );
 
@@ -521,15 +520,15 @@ PHP;
     {
         $x509certificate = 'x509certificate';
         $config = new Configuration(
-            array(
-                'keys' => array(
-                    array(
+            [
+                'keys' => [
+                    [
                         'X509Certificate' => $x509certificate,
                         'type' => 'X509Certificate',
                         'signing' => true
-                    ),
-                ),
-            ),
+                    ],
+                ],
+            ],
             'test'
         );
 
diff --git a/tests/lib/SimpleSAML/Utils/HTTPTest.php b/tests/lib/SimpleSAML/Utils/HTTPTest.php
index 2abf7e9d406c22e758d2c0eeebac2fd9ad9b88ea..07184088482e75bfbc1871aadbd7625b3ca715b7 100644
--- a/tests/lib/SimpleSAML/Utils/HTTPTest.php
+++ b/tests/lib/SimpleSAML/Utils/HTTPTest.php
@@ -1,8 +1,10 @@
 <?php
+
 namespace SimpleSAML\Test\Utils;
 
 use PHPUnit\Framework\TestCase;
 use SimpleSAML\Utils\HTTP;
+use SimpleSAML\Configuration;
 
 class HTTPTest extends TestCase
 {
@@ -37,7 +39,7 @@ class HTTPTest extends TestCase
      */
     public function testAddURLParametersInvalidURL()
     {
-        HTTP::addURLParameters(array(), array());
+        HTTP::addURLParameters([], []);
     }
 
     /**
@@ -56,23 +58,23 @@ class HTTPTest extends TestCase
     public function testAddURLParameters()
     {
         $url = 'http://example.com/';
-        $params = array(
+        $params = [
             'foo' => 'bar',
             'bar' => 'foo',
-        );
+        ];
         $this->assertEquals($url.'?foo=bar&bar=foo', HTTP::addURLParameters($url, $params));
 
         $url = 'http://example.com/?';
-        $params = array(
+        $params = [
             'foo' => 'bar',
             'bar' => 'foo',
-        );
+        ];
         $this->assertEquals($url.'foo=bar&bar=foo', HTTP::addURLParameters($url, $params));
 
         $url = 'http://example.com/?foo=bar';
-        $params = array(
+        $params = [
             'bar' => 'foo',
-        );
+        ];
         $this->assertEquals($url.'&bar=foo', HTTP::addURLParameters($url, $params));
     }
 
@@ -125,9 +127,9 @@ class HTTPTest extends TestCase
     {
         $original = $_SERVER;
 
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => '',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $_SERVER['SERVER_PORT'] = '80';
         $this->assertEquals('localhost', HTTP::getSelfHost());
         $_SERVER['SERVER_PORT'] = '3030';
@@ -143,9 +145,9 @@ class HTTPTest extends TestCase
     {
         $original = $_SERVER;
 
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => '',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         // standard port for HTTP
         $_SERVER['SERVER_PORT'] = '80';
@@ -174,9 +176,9 @@ class HTTPTest extends TestCase
          * Test a URL pointing to a script that's not part of the public interface. This allows us to test calls to
          * getSelfURL() from scripts outside of SimpleSAMLphp
          */
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => 'http://example.com/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $url = 'https://example.com/app/script.php/some/path?foo=bar';
         $this->setupEnvFromURL($url);
         $_SERVER['SCRIPT_FILENAME'] = '/var/www/app/script.php';
@@ -187,9 +189,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a request URI that doesn't match the current script
-        $cfg = \SimpleSAML_Configuration::loadFromArray(array(
+        $cfg = Configuration::loadFromArray([
             'baseurlpath' => 'https://example.org/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $baseDir = $cfg->getBaseDir();
         $_SERVER['SCRIPT_FILENAME'] = $baseDir.'www/module.php';
         $this->setupEnvFromURL('http://www.example.com/protected/resource.asp?foo=bar');
@@ -201,9 +203,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('http://www.example.com', HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a full URL in the configuration
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => 'https://example.com/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->setupEnvFromURL('http://www.example.org/module.php/module/file.php?foo=bar');
         $this->assertEquals(
             'https://example.com/simplesaml/module.php/module/file.php?foo=bar',
@@ -215,9 +217,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a full URL *without* a trailing slash in the configuration
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => 'https://example.com/simplesaml',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->assertEquals(
             'https://example.com/simplesaml/module.php/module/file.php?foo=bar',
             HTTP::getSelfURL()
@@ -228,9 +230,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a full URL *without* a path in the configuration
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => 'https://example.com',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->assertEquals(
             'https://example.com/module.php/module/file.php?foo=bar',
             HTTP::getSelfURL()
@@ -241,9 +243,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('https://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a relative path in the configuration
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => '/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->setupEnvFromURL('http://www.example.org/simplesaml/module.php/module/file.php?foo=bar');
         $this->assertEquals(
             'http://www.example.org/simplesaml/module.php/module/file.php?foo=bar',
@@ -255,9 +257,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('http://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a relative path in the configuration and a non standard port
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => '/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->setupEnvFromURL('http://example.org:8080/simplesaml/module.php/module/file.php?foo=bar');
         $this->assertEquals(
             'http://example.org:8080/simplesaml/module.php/module/file.php?foo=bar',
@@ -269,9 +271,9 @@ class HTTPTest extends TestCase
         $this->assertEquals('http://'.HTTP::getSelfHostWithNonStandardPort(), HTTP::getSelfURLHost());
 
         // test a valid, full URL, based on a relative path in the configuration, a non standard port and HTTPS
-        \SimpleSAML_Configuration::loadFromArray(array(
+        Configuration::loadFromArray([
             'baseurlpath' => '/simplesaml/',
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
         $this->setupEnvFromURL('https://example.org:8080/simplesaml/module.php/module/file.php?foo=bar');
         $this->assertEquals(
             'https://example.org:8080/simplesaml/module.php/module/file.php?foo=bar',
@@ -295,24 +297,24 @@ class HTTPTest extends TestCase
     {
         $original = $_SERVER;
 
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'trusted.url.domains' => array('sp.example.com', 'app.example.com'),
+        Configuration::loadFromArray([
+            'trusted.url.domains' => ['sp.example.com', 'app.example.com'],
             'trusted.url.regex' => false,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $_SERVER['REQUEST_URI'] = '/module.php';
 
-        $allowed = array(
+        $allowed = [
             'https://sp.example.com/',
             'http://sp.example.com/',
             'https://app.example.com/',
             'http://app.example.com/',
-        );
+        ];
         foreach ($allowed as $url) {
             $this->assertEquals(HTTP::checkURLAllowed($url), $url);
         }
 
-        $this->setExpectedException('SimpleSAML_Error_Exception');
+        $this->setExpectedException('\SimpleSAML\Error\Exception');
         HTTP::checkURLAllowed('https://evil.com');
 
         $_SERVER = $original;
@@ -325,26 +327,26 @@ class HTTPTest extends TestCase
     {
         $original = $_SERVER;
 
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'trusted.url.domains' => array('.*\.example\.com'),
+        Configuration::loadFromArray([
+            'trusted.url.domains' => ['.*\.example\.com'],
             'trusted.url.regex' => true,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $_SERVER['REQUEST_URI'] = '/module.php';
 
-        $allowed = array(
+        $allowed = [
             'https://sp.example.com/',
             'http://sp.example.com/',
             'https://app1.example.com/',
             'http://app1.example.com/',
             'https://app2.example.com/',
             'http://app2.example.com/',
-        );
+        ];
         foreach ($allowed as $url) {
             $this->assertEquals(HTTP::checkURLAllowed($url), $url);
         }
 
-        $this->setExpectedException('SimpleSAML_Error_Exception');
+        $this->setExpectedException('\SimpleSAML\Error\Exception');
         HTTP::checkURLAllowed('https://evil.com');
 
         $_SERVER = $original;
@@ -366,6 +368,10 @@ class HTTPTest extends TestCase
         $_SERVER['SERVER_PORT'] = '80';
         $this->assertEquals(HTTP::getServerPort(), '');
 
+        // Test HTTP + standard integer port
+        $_SERVER['SERVER_PORT'] = 80;
+        $this->assertEquals(HTTP::getServerPort(), '');
+
         // Test HTTP + without port
         unset($_SERVER['SERVER_PORT']);
         $this->assertEquals(HTTP::getServerPort(), '');
@@ -375,6 +381,10 @@ class HTTPTest extends TestCase
         $_SERVER['SERVER_PORT'] = '3030';
         $this->assertEquals(HTTP::getServerPort(), ':3030');
 
+        // Test HTTPS + non-standard integer port
+        $_SERVER['SERVER_PORT'] = 3030;
+        $this->assertEquals(HTTP::getServerPort(), ':3030');
+
         // Test HTTPS + standard port
         $_SERVER['SERVER_PORT'] = '443';
         $this->assertEquals(HTTP::getServerPort(), '');
@@ -394,16 +404,28 @@ class HTTPTest extends TestCase
     {
         $original = $_SERVER;
 
-        \SimpleSAML_Configuration::loadFromArray(array(
-            'trusted.url.domains' => array('app\.example\.com'),
+        Configuration::loadFromArray([
+            'trusted.url.domains' => ['app\.example\.com'],
             'trusted.url.regex' => true,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         $_SERVER['REQUEST_URI'] = '/module.php';
 
-        $this->setExpectedException('SimpleSAML_Error_Exception');
+        $this->setExpectedException('\SimpleSAML\Error\Exception');
         HTTP::checkURLAllowed('https://app.example.com.evil.com');
 
         $_SERVER = $original;
     }
+
+    /**
+     * @covers SimpleSAML\Utils\HTTP::getFirstPathElement()
+     */
+    public function testGetFirstPathElement()
+    {
+        $original = $_SERVER;
+        $_SERVER['SCRIPT_NAME'] = '/test/tmp.php';
+        $this->assertEquals(HTTP::getFirstPathElement(), '/test');
+        $this->assertEquals(HTTP::getFirstPathElement(false), 'test');
+        $_SERVER = $original;
+    }
 }
diff --git a/tests/lib/SimpleSAML/Utils/NetTest.php b/tests/lib/SimpleSAML/Utils/NetTest.php
index 8e7e29e5453794f34bce483ee921279dd37b845e..8b23bb44aaf709e7993195bffadc8aeb40d17fa3 100644
--- a/tests/lib/SimpleSAML/Utils/NetTest.php
+++ b/tests/lib/SimpleSAML/Utils/NetTest.php
@@ -10,8 +10,6 @@ use SimpleSAML\Utils\Net;
  */
 class NetTest extends TestCase
 {
-
-
     /**
      * Test the function that checks for IPs belonging to a CIDR.
      *
diff --git a/tests/lib/SimpleSAML/Utils/RandomTest.php b/tests/lib/SimpleSAML/Utils/RandomTest.php
index ff05ed0243f2ceb09104ee59b2b3deb6f529e401..6067faf070830ba24ac26745cb08d278ba07b134 100644
--- a/tests/lib/SimpleSAML/Utils/RandomTest.php
+++ b/tests/lib/SimpleSAML/Utils/RandomTest.php
@@ -10,7 +10,6 @@ use SimpleSAML\Utils\Random;
  */
 class RandomTest extends TestCase
 {
-
     /**
      * Test for SimpleSAML\Utils\Random::generateID().
      *
diff --git a/tests/lib/SimpleSAML/Utils/SystemTest.php b/tests/lib/SimpleSAML/Utils/SystemTest.php
index 897f8a3d9d68b6c7f011c3f0fddb1f06464e4572..99a77ebe08a0890f345b26583cbac427e79fb182 100644
--- a/tests/lib/SimpleSAML/Utils/SystemTest.php
+++ b/tests/lib/SimpleSAML/Utils/SystemTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\Utils;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Utils\System;
 
 use \org\bovigo\vfs\vfsStream;
@@ -21,9 +21,9 @@ class SystemTest extends TestCase
         $this->root = vfsStream::setup(
             self::ROOTDIRNAME,
             null,
-            array(
-                self::DEFAULTTEMPDIR => array(),
-            )
+            [
+                self::DEFAULTTEMPDIR => [],
+            ]
         );
         $this->root_directory = vfsStream::url(self::ROOTDIRNAME);
     }
@@ -115,16 +115,16 @@ class SystemTest extends TestCase
      */
     public function testWriteFileBasic()
     {
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTTEMPDIR;
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTTEMPDIR;
         $config = $this->setConfigurationTempDir($tempdir);
 
-        $filename = $this->root_directory . DIRECTORY_SEPARATOR . 'test';
+        $filename = $this->root_directory.DIRECTORY_SEPARATOR.'test';
 
         System::writeFile($filename, '');
 
         $this->assertFileExists($filename);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     /**
@@ -133,10 +133,10 @@ class SystemTest extends TestCase
      */
     public function testWriteFileContents()
     {
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTTEMPDIR;
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTTEMPDIR;
         $config = $this->setConfigurationTempDir($tempdir);
 
-        $filename = $this->root_directory . DIRECTORY_SEPARATOR . 'test';
+        $filename = $this->root_directory.DIRECTORY_SEPARATOR.'test';
         $contents = 'TEST';
 
         System::writeFile($filename, $contents);
@@ -146,7 +146,7 @@ class SystemTest extends TestCase
 
         $this->assertEquals($expected, $res);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     /**
@@ -155,10 +155,10 @@ class SystemTest extends TestCase
      */
     public function testWriteFileMode()
     {
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTTEMPDIR;
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTTEMPDIR;
         $config = $this->setConfigurationTempDir($tempdir);
 
-        $filename = $this->root_directory . DIRECTORY_SEPARATOR . 'test';
+        $filename = $this->root_directory.DIRECTORY_SEPARATOR.'test';
         $mode = 0666;
 
         System::writeFile($filename, '', $mode);
@@ -168,7 +168,7 @@ class SystemTest extends TestCase
 
         $this->assertEquals($expected, $res);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     /**
@@ -177,7 +177,7 @@ class SystemTest extends TestCase
      */
     public function testGetTempDirBasic()
     {
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTTEMPDIR;
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTTEMPDIR;
         $config = $this->setConfigurationTempDir($tempdir);
 
         $res = System::getTempDir();
@@ -186,7 +186,7 @@ class SystemTest extends TestCase
         $this->assertEquals($expected, $res);
         $this->assertFileExists($res);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     /**
@@ -195,7 +195,7 @@ class SystemTest extends TestCase
      */
     public function testGetTempDirNonExistant()
     {
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . 'nonexistant';
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.'nonexistant';
         $config = $this->setConfigurationTempDir($tempdir);
 
         $res = System::getTempDir();
@@ -204,7 +204,7 @@ class SystemTest extends TestCase
         $this->assertEquals($expected, $res);
         $this->assertFileExists($res);
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     /**
@@ -214,24 +214,28 @@ class SystemTest extends TestCase
      */
     public function testGetTempDirBadOwner()
     {
+        if (!function_exists('posix_getuid')) {
+            static::markTestSkipped('POSIX-functions not available;  skipping!');
+        }
+
         $bad_uid = posix_getuid() + 1;
 
-        $tempdir = $this->root_directory . DIRECTORY_SEPARATOR . self::DEFAULTTEMPDIR;
+        $tempdir = $this->root_directory.DIRECTORY_SEPARATOR.self::DEFAULTTEMPDIR;
         $config = $this->setConfigurationTempDir($tempdir);
 
         chown($tempdir, $bad_uid);
 
-        $this->setExpectedException('\SimpleSAML_Error_Exception');
-        $res = System::getTempDir();
+        $this->setExpectedException('\SimpleSAML\Error\Exception');
+        System::getTempDir();
 
-        $this->clearInstance($config, '\SimpleSAML_Configuration');
+        $this->clearInstance($config, '\SimpleSAML\Configuration');
     }
 
     private function setConfigurationTempDir($directory)
     {
-        $config = Configuration::loadFromArray(array(
+        $config = Configuration::loadFromArray([
             'tempdir' => $directory,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
 
         return $config;
     }
diff --git a/tests/lib/SimpleSAML/Utils/TimeTest.php b/tests/lib/SimpleSAML/Utils/TimeTest.php
index 043aefbe52d4bec5519bda67216e5086fb4e79ff..6973a2180871c933fc92aecdff9ee8ea746f5002 100644
--- a/tests/lib/SimpleSAML/Utils/TimeTest.php
+++ b/tests/lib/SimpleSAML/Utils/TimeTest.php
@@ -7,7 +7,6 @@ use SimpleSAML\Utils\Time;
 
 class TimeTest extends TestCase
 {
-
     /**
      * Test the SimpleSAML\Utils\Time::generateTimestamp() method.
      *
@@ -37,7 +36,7 @@ class TimeTest extends TestCase
         }
 
         // test guessing timezone from the OS
-        \SimpleSAML_Configuration::loadFromArray(array('timezone' => null), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['timezone' => null], '[ARRAY]', 'simplesaml');
         @Time::initTimezone();
         $this->assertEquals($os, @date_default_timezone_get());
 
@@ -47,21 +46,21 @@ class TimeTest extends TestCase
         $c->setValue(false);
 
         // test unknown timezone
-        \SimpleSAML_Configuration::loadFromArray(array('timezone' => 'INVALID'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['timezone' => 'INVALID'], '[ARRAY]', 'simplesaml');
         try {
             @Time::initTimezone();
             $this->fail('Failed to recognize an invalid timezone.');
-        } catch (\SimpleSAML_Error_Exception $e) {
+        } catch (\SimpleSAML\Error\Exception $e) {
             $this->assertEquals('Invalid timezone set in the "timezone" option in config.php.', $e->getMessage());
         }
 
         // test a valid timezone
-        \SimpleSAML_Configuration::loadFromArray(array('timezone' => $tz), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['timezone' => $tz], '[ARRAY]', 'simplesaml');
         @Time::initTimezone();
         $this->assertEquals($tz, @date_default_timezone_get());
 
         // make sure initialization happens only once
-        \SimpleSAML_Configuration::loadFromArray(array('timezone' => 'Europe/Madrid'), '[ARRAY]', 'simplesaml');
+        \SimpleSAML\Configuration::loadFromArray(['timezone' => 'Europe/Madrid'], '[ARRAY]', 'simplesaml');
         @Time::initTimezone();
         $this->assertEquals($tz, @date_default_timezone_get());
     }
@@ -144,7 +143,7 @@ class TimeTest extends TestCase
         }
         try {
             // invalid timestamp
-            Time::parseDuration('', array());
+            Time::parseDuration('', []);
             $this->fail("Did not fail with invalid timestamp parameter.");
         } catch (\InvalidArgumentException $e) {
             $this->assertEquals('Invalid input parameters', $e->getMessage());
diff --git a/tests/lib/SimpleSAML/Utils/XMLTest.php b/tests/lib/SimpleSAML/Utils/XMLTest.php
index 7660487956ba79e9449342b26380896d7641041f..1e9bacb8b986cada2225e18e2635877914df4891 100644
--- a/tests/lib/SimpleSAML/Utils/XMLTest.php
+++ b/tests/lib/SimpleSAML/Utils/XMLTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\Utils;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\Utils\XML;
 
 /**
@@ -135,13 +135,13 @@ class XMLTest extends TestCase
         $element->appendChild(new \DOMText($data2));
 
         $res = XML::getDOMText($element);
-        $expected = $data1 . $data2 . $data1 . $data2;
+        $expected = $data1.$data2.$data1.$data2;
 
         $this->assertEquals($expected, $res);
     }
 
     /**
-     * @expectedException \SimpleSAML_Error_Exception
+     * @expectedException \SimpleSAML\Error\Exception
      *
      * @covers \SimpleSAML\Utils\XML::getDOMText
      * @test
@@ -150,7 +150,7 @@ class XMLTest extends TestCase
     {
         $dom = new \DOMDocument();
         $element = $dom->appendChild(new \DOMElement('root'));
-        $comment = $element->appendChild(new \DOMComment(''));
+        $element->appendChild(new \DOMComment(''));
 
         XML::getDOMText($element);
     }
@@ -168,7 +168,7 @@ class XMLTest extends TestCase
         $dom->appendChild($element);
 
         $res = XML::getDOMChildren($dom, $name, $namespace_uri);
-        $expected = array($element);
+        $expected = [$element];
 
         $this->assertEquals($expected, $res);
     }
@@ -357,12 +357,12 @@ NOWDOC;
      */
     public function testIsValidMetadata()
     {
-        \SimpleSAML_Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
+        Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
 
         $schema = 'saml-schema-metadata-2.0.xsd';
 
         $dom = $this->getMockBuilder('\DOMDocument')
-            ->setMethods(array('schemaValidate'))
+            ->setMethods(['schemaValidate'])
             ->disableOriginalConstructor()
             ->getMock();
 
@@ -379,4 +379,13 @@ NOWDOC;
 
         $this->assertTrue($res);
     }
+
+    /**
+     * @covers \SimpleSAML\Utils\XML::checkSAMLMessage()
+     */
+    public function testCheckSAMLMessageInvalidType()
+    {
+        $this->setExpectedException('\InvalidArgumentException');
+        XML::checkSAMLMessage('<test></test>', 'blub');
+    }
 }
diff --git a/tests/lib/SimpleSAML/XML/ErrorsTest.php b/tests/lib/SimpleSAML/XML/ErrorsTest.php
index a6a46f19da67564f78e765bb4865bb1821a6068d..4c0f929139c4b7ee1d467eb1d43e171f3f74723f 100644
--- a/tests/lib/SimpleSAML/XML/ErrorsTest.php
+++ b/tests/lib/SimpleSAML/XML/ErrorsTest.php
@@ -9,7 +9,6 @@
  * @package simplesamlphp/simplesamlphp
  */
 
-
 namespace SimpleSAML\Test\XML;
 
 use PHPUnit\Framework\TestCase;
@@ -51,7 +50,7 @@ class ErrorsTest extends TestCase
         $error->column = 'col';
         $error->message = ' msg ';
 
-        $errors = Errors::formatErrors(array($error, $error));
+        $errors = Errors::formatErrors([$error, $error]);
 
         $this->assertEquals(
             "level=level,code=code,line=line,col=col,msg=msg\nlevel=level,code=code,line=line,col=col,msg=msg\n",
diff --git a/tests/lib/SimpleSAML/XML/ParserTest.php b/tests/lib/SimpleSAML/XML/ParserTest.php
index 336ae86f12357fff99e3870873d19bc171807c90..2e4e1891e1479496fc778c5ad9ceb49a21897dfc 100644
--- a/tests/lib/SimpleSAML/XML/ParserTest.php
+++ b/tests/lib/SimpleSAML/XML/ParserTest.php
@@ -8,7 +8,6 @@
  * file that was distributed with this source code.
  */
 
-
 namespace SimpleSAML\Test\XML;
 
 use PHPUnit\Framework\TestCase;
@@ -96,10 +95,10 @@ XML;
     {
         $result = $this
             ->xml
-            ->getValueAlternatives(array(
+            ->getValueAlternatives([
                 '/Root/Other',
                 '/Root/Value'
-            ), true)
+            ], true)
         ;
 
         $this->assertEquals(
@@ -117,10 +116,10 @@ XML;
     {
         $result = $this
             ->xml
-            ->getValueAlternatives(array(
+            ->getValueAlternatives([
                 '/Root/Foo',
                 '/Root/Bar'
-            ), false)
+            ], false)
         ;
 
         $this->assertEquals(
@@ -139,10 +138,10 @@ XML;
     {
         $this
             ->xml
-            ->getValueAlternatives(array(
+            ->getValueAlternatives([
                 '/Root/Foo',
                 '/Root/Bar'
-            ), true)
+            ], true)
         ;
     }
 }
diff --git a/tests/lib/SimpleSAML/XML/Shib13/AuthnResponseTest.php b/tests/lib/SimpleSAML/XML/Shib13/AuthnResponseTest.php
index b492337f6780387f9125ddac3cea9a9885997fa7..c2e266929c2a254117be5a3fec30f9323944f306 100644
--- a/tests/lib/SimpleSAML/XML/Shib13/AuthnResponseTest.php
+++ b/tests/lib/SimpleSAML/XML/Shib13/AuthnResponseTest.php
@@ -112,10 +112,10 @@ XML;
         $result = $this->xml->getNameID();
 
         $this->assertEquals(
-            array(
+            [
                 'Value' => 'NameIdentifier',
                 'Format' => 'urn:mace:shibboleth:1.0:nameIdentifier',
-            ),
+            ],
             $result
         );
     }
diff --git a/tests/lib/SimpleSAML/XML/SignerTest.php b/tests/lib/SimpleSAML/XML/SignerTest.php
index 77edff09d1d1291fef61af531b5988d5b41ac04a..f14ef5111b3fff4d1239583676a2b432c5900ad9 100644
--- a/tests/lib/SimpleSAML/XML/SignerTest.php
+++ b/tests/lib/SimpleSAML/XML/SignerTest.php
@@ -1,9 +1,9 @@
 <?php
 
-namespace SimpleSAML\Test\Utils;
+namespace SimpleSAML\Test\XML;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\XML\Signer;
 
 use \org\bovigo\vfs\vfsStream;
@@ -105,13 +105,13 @@ NOWDOC;
         $this->root = vfsStream::setup(
             self::ROOTDIRNAME,
             null,
-            array(
-                self::DEFAULTCERTDIR => array(
+            [
+                self::DEFAULTCERTDIR => [
                     self::PRIVATEKEY => $this->private_key,
                     self::CERTIFICATE1 => $this->certificate1,
                     self::CERTIFICATE2 => $this->certificate2,
-                ),
-            )
+                ],
+            ]
         );
         $this->root_directory = vfsStream::url(self::ROOTDIRNAME);
 
@@ -120,19 +120,19 @@ NOWDOC;
         $this->certificate_file1 = $this->certdir.DIRECTORY_SEPARATOR.self::CERTIFICATE1;
         $this->certificate_file2 = $this->certdir.DIRECTORY_SEPARATOR.self::CERTIFICATE2;
 
-        $this->config = Configuration::loadFromArray(array(
+        $this->config = Configuration::loadFromArray([
             'certdir' => $this->certdir,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
     }
 
     public function tearDown()
     {
-        $this->clearInstance($this->config, '\SimpleSAML_Configuration', array());
+        $this->clearInstance($this->config, '\SimpleSAML\Configuration', []);
     }
 
     public function testSignerBasic()
     {
-        $res = new Signer(array());
+        $res = new Signer([]);
 
         $this->assertNotNull($res);
     }
@@ -146,7 +146,7 @@ NOWDOC;
         $doc = new \DOMDocument();
         $insertInto = $doc->appendChild(new \DOMElement('insert'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->privatekey_file, null, true);
         $signer->sign($element, $insertInto);
 
@@ -158,11 +158,11 @@ NOWDOC;
 
     private static function getCertificateValue($certificate)
     {
-        $replacements = array(
+        $replacements = [
             "-----BEGIN CERTIFICATE-----",
             "-----END CERTIFICATE-----",
             "\n",
-        );
+        ];
 
         return str_replace($replacements, "", $certificate);
     }
@@ -176,7 +176,7 @@ NOWDOC;
         $doc = new \DOMDocument();
         $insertInto = $doc->appendChild(new \DOMElement('insert'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->privatekey_file, null, true);
         $signer->loadCertificate($this->certificate_file1, true);
         $signer->sign($element, $insertInto);
@@ -198,7 +198,7 @@ NOWDOC;
         $doc = new \DOMDocument();
         $insertInto = $doc->appendChild(new \DOMElement('insert'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->privatekey_file, null, true);
         $signer->loadCertificate($this->certificate_file1, true);
         $signer->addCertificate($this->certificate_file2, true);
@@ -223,7 +223,7 @@ NOWDOC;
         $doc = new \DOMDocument();
         $insertInto = $doc->appendChild(new \DOMElement('insert'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
 
         $this->setExpectedException('\Exception');
         $signer->sign($element, $insertInto);
diff --git a/tests/lib/SimpleSAML/XML/ValidatorTest.php b/tests/lib/SimpleSAML/XML/ValidatorTest.php
index 8dc2179f45986bfc4c287dc1a54c7c31f252e721..b274ad9a89a7d3b9612228188ae397236052afbf 100644
--- a/tests/lib/SimpleSAML/XML/ValidatorTest.php
+++ b/tests/lib/SimpleSAML/XML/ValidatorTest.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\XML;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 use \SimpleSAML\XML\Signer;
 use \SimpleSAML\XML\Validator;
 
@@ -147,14 +147,14 @@ NOWDOC;
         $this->root = vfsStream::setup(
             self::ROOTDIRNAME,
             null,
-            array(
-                self::DEFAULTCERTDIR => array(
+            [
+                self::DEFAULTCERTDIR => [
                     self::CA_PRIVATE_KEY => $this->ca_private_key,
                     self::CA_CERTIFICATE => $this->ca_certificate,
                     self::GOOD_PRIVATE_KEY => $this->good_private_key,
                     self::GOOD_CERTIFICATE => $this->good_certificate,
-                ),
-            )
+                ],
+            ]
         );
         $this->root_directory = vfsStream::url(self::ROOTDIRNAME);
 
@@ -164,14 +164,14 @@ NOWDOC;
         $this->good_private_key_file = $this->certdir.DIRECTORY_SEPARATOR.self::GOOD_PRIVATE_KEY;
         $this->good_certificate_file = $this->certdir.DIRECTORY_SEPARATOR.self::GOOD_CERTIFICATE;
 
-        $this->config = Configuration::loadFromArray(array(
+        $this->config = Configuration::loadFromArray([
             'certdir' => $this->certdir,
-        ), '[ARRAY]', 'simplesaml');
+        ], '[ARRAY]', 'simplesaml');
     }
 
     public function tearDown()
     {
-        $this->clearInstance($this->config, '\SimpleSAML_Configuration', array());
+        $this->clearInstance($this->config, '\SimpleSAML\Configuration', []);
     }
 
     public function testValidatorMissingSignature()
@@ -192,7 +192,7 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->loadCertificate($this->good_certificate_file, true);
         $signer->sign($node, $signature_parent);
@@ -202,7 +202,7 @@ NOWDOC;
         $result = $validator->getX509Certificate();
 
         // getX509Certificate returns a certificate with a newline
-        $expected = $this->good_certificate . "\n";
+        $expected = $this->good_certificate."\n";
 
         $this->assertEquals($result, $expected);
     }
@@ -216,7 +216,7 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->loadCertificate($this->good_certificate_file, true);
         $signer->sign($node, $signature_parent);
@@ -228,7 +228,7 @@ NOWDOC;
         $validator = new Validator(
             $doc,
             'node',
-            array('certFingerprint' => array($fingerprint))
+            ['certFingerprint' => [$fingerprint]]
         );
 
         // Avoiding Validator::class because it's >= PHP 5.5 only
@@ -244,13 +244,13 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->loadCertificate($this->good_certificate_file, true);
         $signer->sign($node, $signature_parent);
 
         $this->setExpectedException('\Exception');
-        new Validator($doc, 'node', array('certFingerprint' => array()));
+        new Validator($doc, 'node', ['certFingerprint' => []]);
     }
 
     public function testValidateFingerprintSuccess()
@@ -262,7 +262,7 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->loadCertificate($this->good_certificate_file, true);
         $signer->sign($node, $signature_parent);
@@ -287,7 +287,7 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->loadCertificate($this->good_certificate_file, true);
         $signer->sign($node, $signature_parent);
@@ -309,14 +309,14 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->sign($node, $signature_parent);
 
         $validator = new Validator(
             $doc,
             'node',
-            array('PEM' => $this->good_certificate)
+            ['PEM' => $this->good_certificate]
         );
 
         $result = $validator->isNodeValidated($node);
@@ -334,14 +334,14 @@ NOWDOC;
 
         $signature_parent = $doc->appendChild(new \DOMElement('signature_parent'));
 
-        $signer = new Signer(array());
+        $signer = new Signer([]);
         $signer->loadPrivateKey($this->good_private_key_file, null, true);
         $signer->sign($node1, $signature_parent);
 
         $validator = new Validator(
             $doc,
             'node1',
-            array('PEM' => $this->good_certificate)
+            ['PEM' => $this->good_certificate]
         );
 
         $result = $validator->isNodeValidated($node2);
diff --git a/tests/modules/consent/lib/Auth/Process/ConsentTest.php b/tests/modules/consent/lib/Auth/Process/ConsentTest.php
index 887e11b433e8daffa88fdef506339124d9622685..1e162314720ab0cdeda95d15f02456c15b9c8a94 100644
--- a/tests/modules/consent/lib/Auth/Process/ConsentTest.php
+++ b/tests/modules/consent/lib/Auth/Process/ConsentTest.php
@@ -9,13 +9,14 @@
 namespace SimpleSAML\Test\Module\consent\Auth\Process;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 
 class ConsentTest extends TestCase
 {
     public function setUp()
     {
-        $this->config = Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
+        $this->config = Configuration::loadFromArray(['module.enable' => ['consent' => true]], '[ARRAY]', 'simplesaml');
+        \SimpleSAML_Configuration::setPreLoadedConfig($this->config, 'config.php');
     }
 
     /**
@@ -27,7 +28,7 @@ class ConsentTest extends TestCase
      */
     private function processFilter(array $config, array $request)
     {
-        $filter = new \sspmod_consent_Auth_Process_Consent($config, null);
+        $filter = new \SimpleSAML\Module\consent\Auth\Process\Consent($config, null);
         $filter->process($request);
         return $request;
     }
@@ -39,85 +40,187 @@ class ConsentTest extends TestCase
     public function testCheckDisable()
     {
         // test consent disable regex with match
-        $config = array();
+        $config = [];
 
         // test consent disable with match on specific SP entityid
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => 'https://idp.example.org',
                 'metadata-set' => 'saml20-idp-local',
-                'consent.disable' => array(
+                'consent.disable' => [
                     'https://valid.flatstring.example.that.does.not.match',
-                ),
-                'SingleSignOnService' => array(
-                    array(
+                ],
+                'SingleSignOnService' => [
+                    [
                         'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                         'Location' => 'https://idp.example.org/saml2/idp/SSOService.php',
-                    ),
-                ),
-            ),
-            'Destination' => array(
+                    ],
+                ],
+            ],
+            'Destination' => [
                 // valid entityid equal to the last one in the consent.disable array
                 'entityid' => 'https://sp.example.org/my-sp',
                 'metadata-set' => 'saml20-sp-remote',
-                'consent.disable' => array(
-                    array('type' => 'regex', 'pattern' => '/invalid/i'),
+                'consent.disable' => [
+                    ['type' => 'regex', 'pattern' => '/invalid/i'],
                     'https://sp.example.org/my-sp', // accept the SP that has this specific entityid
                     'https://idp.example.org',
-                ),
-            ),
+                ],
+            ],
             'UserID' => 'jdoe',
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-            ),
-        );
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+            ],
+        ];
         $result = $this->processFilter($config, $request);
         // the state should NOT have changed because NO consent should be necessary (match)
         $this->assertEquals($request, $result);
 
         // test consent disable with match on SP through regular expression
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => 'https://idp.example.org',
                 'metadata-set' => 'saml20-idp-local',
-                'consent.disable' => array(
-                    array(), // invalid consent option array should be ignored
+                'consent.disable' => [
+                    [], // invalid consent option array should be ignored
                     1234, // bad option
-                    array(''), // no type
-                    array('type'=>'invalid'), // invalid consent option type should be ignored
-                    array('type'=>'regex'), // regex consent option without pattern should be ignored
-                    array('type'=>'regex', 'pattern'=>'/.*\.valid.regex\.that\.does\.not\.match.*/i'),
+                    [''], // no type
+                    ['type'=>'invalid'], // invalid consent option type should be ignored
+                    ['type'=>'regex'], // regex consent option without pattern should be ignored
+                    ['type'=>'regex', 'pattern'=>'/.*\.valid.regex\.that\.does\.not\.match.*/i'],
                     // accept any SP that has an entityid that contains the string ".example.org"
-                    array('type'=>'regex', 'pattern'=>'/.*\.example\.org\/.*/i'),
-                ),
-                'SingleSignOnService' => array(
-                    array(
+                    ['type'=>'regex', 'pattern'=>'/.*\.example\.org\/.*/i'],
+                ],
+                'SingleSignOnService' => [
+                    [
                         'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                         'Location' => 'https://idp.example.org/saml2/idp/SSOService.php',
-                    ),
-                ),
-            ),
-            'Destination' => array(
+                    ],
+                ],
+            ],
+            'Destination' => [
                 'entityid' => 'https://sp.example.org/my-sp', // sp contains the string ".example.org"
                 'metadata-set' => 'saml20-sp-remote',
-            ),
+            ],
             'UserID' => 'jdoe',
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-            ),
-        );
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+            ],
+        ];
         $result = $this->processFilter($config, $request);
         // the state should NOT have changed because NO consent should be necessary (match)
         $this->assertEquals($request, $result);
 
         // test corner cases
-        $request['Source']['consent.disable'] = array(
+        $request['Source']['consent.disable'] = [
             'https://valid.flatstring.example.that.does.not.match',
-            array('foo' => 'bar'),
-        );
+            ['foo' => 'bar'],
+        ];
         $request['Destination']['consent.disable'] = 1;
         $result = $this->processFilter($config, $request);
         // the state should NOT have changed because NO consent should be necessary (match)
         $this->assertEquals($request, $result);
     }
+
+    public function testAttributeHashIsConsistentWhenOrderOfValuesChange()
+    {
+        $attributes1 = [
+            'attribute1' => ['val1', 'val2'],
+            'attribute2' => ['val1', 'val2']
+        ];
+        $attributeHash1 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes1, true);
+
+        $attributes2 = [
+            'attribute1' => ['val1', 'val2'],
+            'attribute2' => ['val2', 'val1']
+        ];
+        $attributeHash2 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes2, true);
+
+        $this->assertEquals($attributeHash1, $attributeHash2, "Hash is not the same when the order of values changes");
+    }
+
+    public function testAttributeHashIsConsistentWhenOrderOfAttributesChange()
+    {
+        $attributes1 = [
+            'attribute2' => ['val1', 'val2'],
+            'attribute1' => ['val1', 'val2']
+        ];
+        $attributeHash1 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes1, true);
+
+        $attributes2 = [
+            'attribute1' => ['val1', 'val2'],
+            'attribute2' => ['val1', 'val2']
+        ];
+        $attributeHash2 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes2, true);
+
+        $this->assertEquals(
+            $attributeHash1,
+            $attributeHash2,
+            "Hash is not the same when the order of the attributs changes"
+        );
+    }
+
+    public function testAttributeHashIsConsistentWithoutValuesWhenOrderOfAttributesChange()
+    {
+        $attributes1 = [
+            'attribute2' => ['val1', 'val2'],
+            'attribute1' => ['val1', 'val2']
+        ];
+        $attributeHash1 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes1);
+
+        $attributes2 = [
+            'attribute1' => ['val1', 'val2'],
+            'attribute2' => ['val1', 'val2']
+        ];
+        $attributeHash2 = \SimpleSAML\Module\consent\Auth\Process\Consent::getAttributeHash($attributes2);
+
+        $this->assertEquals(
+            $attributeHash1,
+            $attributeHash2,
+            "Hash is not the same when the order of the attributs changes and the values are not included"
+        );
+    }
+
+    public function testConstructorSetsInstancePrivateVars()
+    {
+        $reflection = new \ReflectionClass('\SimpleSAML\Module\consent\Auth\Process\Consent');
+
+        $values = [
+            'includeValues',
+            'checked',
+            'focus',
+            'hiddenAttributes',
+            'noconsentattributes',
+            'showNoConsentAboutService'
+        ];
+        foreach ($values as $v) {
+            $instanceVars[$v] = $reflection->getProperty($v);
+            $instanceVars[$v]->setAccessible(true);
+        }
+
+        /* these just need to be different to the default values */
+        $config = [
+            'includeValues' => true,
+            'checked' => true,
+            'focus' => 'yes',
+            'hiddenAttributes' => ['attribute1', 'attribute2'],
+            'attributes.exclude' => ['attribute1', 'attribute2'],
+            'showNoConsentAboutService' => false,
+        ];
+
+        $testcase = $reflection->newInstance($config, null);
+
+        $this->assertEquals($instanceVars['includeValues']->getValue($testcase), $config['includeValues']);
+        $this->assertEquals($instanceVars['checked']->getValue($testcase), $config['checked']);
+        $this->assertEquals($instanceVars['focus']->getValue($testcase), $config['focus']);
+        $this->assertEquals($instanceVars['hiddenAttributes']->getValue($testcase), $config['hiddenAttributes']);
+        $this->assertEquals($instanceVars['noconsentattributes']->getValue($testcase), $config['attributes.exclude']);
+        $this->assertEquals(
+            $instanceVars['showNoConsentAboutService']->getValue($testcase),
+            $config['showNoConsentAboutService']
+        );
+
+        $deprecated = $reflection->newInstance(['noconsentattributes' => $config['attributes.exclude']], null);
+        $this->assertEquals($instanceVars['noconsentattributes']->getValue($deprecated), $config['attributes.exclude']);
+    }
 }
diff --git a/tests/modules/core/lib/Auth/Process/AttributeAddTest.php b/tests/modules/core/lib/Auth/Process/AttributeAddTest.php
index e6f763b3fc70f013bb5f4f69be0f7c381339718c..50cf5b3d19186357255dce4c649cd817524ab005 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeAddTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeAddTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeAdd filter.
  */
-class Test_Core_Auth_Process_AttributeAdd extends TestCase
+class AttributeAddTest extends TestCase
 {
 
     /**
@@ -17,7 +19,7 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeAdd($config, null);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeAdd($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,16 +29,16 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
-            'test' => array('value1', 'value2'),
-        );
-        $request = array(
-            'Attributes' => array(),
-        );
+        $config = [
+            'test' => ['value1', 'value2'],
+        ];
+        $request = [
+            'Attributes' => [],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
-        $this->assertEquals($attributes['test'], array('value1', 'value2'));
+        $this->assertEquals($attributes['test'], ['value1', 'value2']);
     }
 
     /**
@@ -44,23 +46,23 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testExistingNotModified()
     {
-        $config = array(
-            'test' => array('value1', 'value2'),
-        );
-        $request = array(
-            'Attributes' => array(
-                'original1' => array('original_value1'),
-                'original2' => array('original_value2'),
-            ),
-        );
+        $config = [
+            'test' => ['value1', 'value2'],
+        ];
+        $request = [
+            'Attributes' => [
+                'original1' => ['original_value1'],
+                'original2' => ['original_value2'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
-        $this->assertEquals($attributes['test'], array('value1', 'value2'));
+        $this->assertEquals($attributes['test'], ['value1', 'value2']);
         $this->assertArrayHasKey('original1', $attributes);
-        $this->assertEquals($attributes['original1'], array('original_value1'));
+        $this->assertEquals($attributes['original1'], ['original_value1']);
         $this->assertArrayHasKey('original2', $attributes);
-        $this->assertEquals($attributes['original2'], array('original_value2'));
+        $this->assertEquals($attributes['original2'], ['original_value2']);
     }
 
     /**
@@ -68,16 +70,16 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testStringValue()
     {
-        $config = array(
+        $config = [
             'test' => 'value',
-        );
-        $request = array(
-            'Attributes' => array(),
-        );
+        ];
+        $request = [
+            'Attributes' => [],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
-        $this->assertEquals($attributes['test'], array('value'));
+        $this->assertEquals($attributes['test'], ['value']);
     }
 
     /**
@@ -85,19 +87,19 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testAddMultiple()
     {
-        $config = array(
-            'test1' => array('value1'),
-            'test2' => array('value2'),
-        );
-        $request = array(
-            'Attributes' => array(),
-        );
+        $config = [
+            'test1' => ['value1'],
+            'test2' => ['value2'],
+        ];
+        $request = [
+            'Attributes' => [],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test1', $attributes);
-        $this->assertEquals($attributes['test1'], array('value1'));
+        $this->assertEquals($attributes['test1'], ['value1']);
         $this->assertArrayHasKey('test2', $attributes);
-        $this->assertEquals($attributes['test2'], array('value2'));
+        $this->assertEquals($attributes['test2'], ['value2']);
     }
 
     /**
@@ -105,17 +107,17 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testAppend()
     {
-        $config = array(
-            'test' => array('value2'),
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
+        $config = [
+            'test' => ['value2'],
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['test'], array('value1', 'value2'));
+        $this->assertEquals($attributes['test'], ['value1', 'value2']);
     }
 
     /**
@@ -123,18 +125,18 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testReplace()
     {
-        $config = array(
+        $config = [
             '%replace',
-            'test' => array('value2'),
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
+            'test' => ['value2'],
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['test'], array('value2'));
+        $this->assertEquals($attributes['test'], ['value2']);
     }
 
     /**
@@ -144,16 +146,16 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testWrongFlag()
     {
-        $config = array(
+        $config = [
             '%nonsense',
-            'test' => array('value2'),
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+            'test' => ['value2'],
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -163,15 +165,15 @@ class Test_Core_Auth_Process_AttributeAdd extends TestCase
      */
     public function testWrongAttributeValue()
     {
-        $config = array(
+        $config = [
             '%replace',
-            'test' => array(true),
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+            'test' => [true],
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 }
diff --git a/tests/modules/core/lib/Auth/Process/AttributeAlterTest.php b/tests/modules/core/lib/Auth/Process/AttributeAlterTest.php
index c13bcbd1080911441b49751d88ae786d38c89fb4..b8f9c7bb9b2649f041ea15c3b61797c6b6e39521 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeAlterTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeAlterTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeAlter filter.
  */
-class Test_Core_Auth_Process_AttributeAlter extends TestCase
+class AttributeAlterTest extends TestCase
 {
 
     /**
@@ -17,7 +19,7 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeAlter($config, null);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeAlter($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,22 +29,22 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
             'replacement' => 'right',
-        );
+        ];
 
-        $request = array(
-            'Attributes' => array(
-                 'test' => array('somethingiswrong'),
-             ),
-        );
+        $request = [
+            'Attributes' => [
+                 'test' => ['somethingiswrong'],
+             ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
-        $this->assertEquals($attributes['test'], array('somethingisright'));
+        $this->assertEquals($attributes['test'], ['somethingisright']);
     }
 
     /**
@@ -50,25 +52,25 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testWithTarget()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'target' => 'test2',
             'pattern' => '/wrong/',
             'replacement' => 'right',
-        );
+        ];
 
-        $request = array(
-            'Attributes' => array(
-                 'something' => array('somethingelse'),
-                 'test' => array('wrong'),
-             ),
-        );
+        $request = [
+            'Attributes' => [
+                 'something' => ['somethingelse'],
+                 'test' => ['wrong'],
+             ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test2', $attributes);
-        $this->assertEquals($attributes['test'], array('wrong'));
-        $this->assertEquals($attributes['test2'], array('right'));
+        $this->assertEquals($attributes['test'], ['wrong']);
+        $this->assertEquals($attributes['test2'], ['right']);
     }
 
     /**
@@ -76,24 +78,26 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testNomatch()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
             'replacement' => 'right',
-        );
+        ];
 
-        $request = array(
-            'Attributes' => array(
-                 'something' => array('somevalue'),
-                 'somethingelse' => array('someothervalue'),
-             ),
-        );
+        $request = [
+            'Attributes' => [
+                 'something' => ['somevalue'],
+                 'somethingelse' => ['someothervalue'],
+             ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes,
-            array('something' => array('somevalue'),
-            'somethingelse' => array('someothervalue')));
+        $this->assertEquals(
+            $attributes,
+            ['something' => ['somevalue'],
+            'somethingelse' => ['someothervalue']]
+        );
     }
 
     /**
@@ -101,20 +105,20 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testReplaceMatch()
     {
-        $config = array(
+        $config = [
             'subject' => 'source',
             'pattern' => '/wrong/',
             'replacement' => 'right',
             '%replace',
-        );
-        $request = array(
-            'Attributes' => array(
-                'source' => array('wrongthing'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'source' => ['wrongthing'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['source'], array('right'));
+        $this->assertEquals($attributes['source'], ['right']);
     }
 
     /**
@@ -122,22 +126,22 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testReplaceMatchWithTarget()
     {
-        $config = array(
+        $config = [
             'subject' => 'source',
             'pattern' => '/wrong/',
             'replacement' => 'right',
             'target' => 'test',
             '%replace',
-        );
-        $request = array(
-            'Attributes' => array(
-                'source' => array('wrong'),
-                'test'   => array('wrong'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'source' => ['wrong'],
+                'test'   => ['wrong'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['test'], array('right'));
+        $this->assertEquals($attributes['test'], ['right']);
     }
 
     /**
@@ -145,22 +149,22 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testReplaceNoMatch()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/doink/',
             'replacement' => 'wrong',
             'target' => 'test',
             '%replace',
-        );
-        $request = array(
-            'Attributes' => array(
-                'source' => array('wrong'),
-                'test'   => array('right'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'source' => ['wrong'],
+                'test'   => ['right'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['test'], array('right'));
+        $this->assertEquals($attributes['test'], ['right']);
     }
 
     /**
@@ -170,21 +174,21 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testRemoveMatch()
     {
-        $config = array(
+        $config = [
             'subject' => 'eduPersonAffiliation',
             'pattern' => '/^emper/',
             '%remove',
-        );
-        $request = array(
-            'Attributes' => array(
-                'displayName' => array('emperor kuzco'),
-                'eduPersonAffiliation' => array('member', 'emperor', 'staff'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'displayName' => ['emperor kuzco'],
+                'eduPersonAffiliation' => ['member', 'emperor', 'staff'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['displayName'], array('emperor kuzco'));
-        $this->assertEquals($attributes['eduPersonAffiliation'], array(0 => 'member', 2 => 'staff'));
+        $this->assertEquals($attributes['displayName'], ['emperor kuzco']);
+        $this->assertEquals($attributes['eduPersonAffiliation'], [0 => 'member', 2 => 'staff']);
     }
 
     /**
@@ -192,17 +196,17 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testRemoveMatchAll()
     {
-        $config = array(
+        $config = [
             'subject' => 'eduPersonAffiliation',
             'pattern' => '/^emper/',
             '%remove',
-        );
-        $request = array(
-            'Attributes' => array(
-                'displayName' => array('emperor kuzco'),
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'displayName' => ['emperor kuzco'],
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
@@ -215,17 +219,17 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testWrongConfig()
     {
-        $config = array(
+        $config = [
             'subject' => 'eduPersonAffiliation',
             'pattern' => '/^emper/',
             '%dwiw',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -235,15 +239,15 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testIncompleteConfig()
     {
-        $config = array(
+        $config = [
             'subject' => 'eduPersonAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -253,23 +257,17 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testIncompleteConfig2()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'test' => array('somethingiswrong'),
-             ),
-        );
-
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -279,25 +277,19 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testIncompleteConfig3()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
             '%replace',
             '%remove',
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'test' => array('somethingiswrong'),
-             ),
-        );
-
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -307,25 +299,19 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testIncompleteConfig4()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
             'target' => 'test2',
             '%remove',
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'test' => array('somethingiswrong'),
-             ),
-        );
-
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
 
@@ -336,23 +322,17 @@ class Test_Core_Auth_Process_AttributeAlter extends TestCase
      */
     public function testIncompleteConfig5()
     {
-        $config = array(
+        $config = [
             'subject' => 'test',
             'pattern' => '/wrong/',
             'replacement' => null,
-        );
+        ];
 
-        $request = array(
-            'Attributes' => array(
-                 'test' => array('somethingiswrong'),
-             ),
-        );
-
-        $request = array(
-            'Attributes' => array(
-                'eduPersonAffiliation' => array('emperess', 'emperor'),
-            ),
-        );
+        $request = [
+            'Attributes' => [
+                'eduPersonAffiliation' => ['emperess', 'emperor'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
     }
 }
diff --git a/tests/modules/core/lib/Auth/Process/AttributeCopyTest.php b/tests/modules/core/lib/Auth/Process/AttributeCopyTest.php
index d960c379f764e9b0db635a8f8aa44253daaa52c5..538bd10e09464b607fa351ba0e2e2770485cf2e6 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeCopyTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeCopyTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeCopy filter.
  */
-class Test_Core_Auth_Process_AttributeCopy extends TestCase
+class AttributeCopyTest extends TestCase
 {
 
     /**
@@ -17,7 +19,7 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeCopy($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeCopy($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,17 +29,17 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'test' => 'testnew',
-        );
-        $request = array(
-            'Attributes' => array('test' => array('AAP')),
-        );
+        ];
+        $request = [
+            'Attributes' => ['test' => ['AAP']],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
         $this->assertArrayHasKey('testnew', $attributes);
-        $this->assertEquals($attributes['testnew'], array('AAP'));
+        $this->assertEquals($attributes['testnew'], ['AAP']);
     }
 
     /**
@@ -45,19 +47,19 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testArray()
     {
-        $config = array(
-            'test' => array('new1','new2'),
-        );
-        $request = array(
-            'Attributes' => array('test' => array('AAP')),
-        );
+        $config = [
+            'test' => ['new1', 'new2'],
+        ];
+        $request = [
+            'Attributes' => ['test' => ['AAP']],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('test', $attributes);
         $this->assertArrayHasKey('new1', $attributes);
         $this->assertArrayHasKey('new2', $attributes);
-        $this->assertEquals($attributes['new1'], array('AAP'));
-        $this->assertEquals($attributes['new2'], array('AAP'));
+        $this->assertEquals($attributes['new1'], ['AAP']);
+        $this->assertEquals($attributes['new2'], ['AAP']);
     }
 
     /**
@@ -65,24 +67,24 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testExistingNotModified()
     {
-        $config = array(
+        $config = [
             'test' => 'testnew',
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('AAP'),
-                'original1' => array('original_value1'),
-                'original2' => array('original_value2'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['AAP'],
+                'original1' => ['original_value1'],
+                'original2' => ['original_value2'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('testnew', $attributes);
-        $this->assertEquals($attributes['test'], array('AAP'));
+        $this->assertEquals($attributes['test'], ['AAP']);
         $this->assertArrayHasKey('original1', $attributes);
-        $this->assertEquals($attributes['original1'], array('original_value1'));
+        $this->assertEquals($attributes['original1'], ['original_value1']);
         $this->assertArrayHasKey('original2', $attributes);
-        $this->assertEquals($attributes['original2'], array('original_value2'));
+        $this->assertEquals($attributes['original2'], ['original_value2']);
     }
 
     /**
@@ -90,19 +92,19 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testCopyMultiple()
     {
-        $config = array(
+        $config = [
             'test1' => 'new1',
             'test2' => 'new2',
-        );
-        $request = array(
-            'Attributes' => array('test1' => array('val1'), 'test2' => array('val2.1','val2.2')),
-        );
+        ];
+        $request = [
+            'Attributes' => ['test1' => ['val1'], 'test2' => ['val2.1', 'val2.2']],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('new1', $attributes);
-        $this->assertEquals($attributes['new1'], array('val1'));
+        $this->assertEquals($attributes['new1'], ['val1']);
         $this->assertArrayHasKey('new2', $attributes);
-        $this->assertEquals($attributes['new2'], array('val2.1','val2.2'));
+        $this->assertEquals($attributes['new2'], ['val2.1', 'val2.2']);
     }
 
     /**
@@ -110,18 +112,18 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testCopyClash()
     {
-        $config = array(
+        $config = [
             'test' => 'new1',
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('testvalue1'),
-                'new1' => array('newvalue1'),
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['testvalue1'],
+                'new1' => ['newvalue1'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['new1'], array('testvalue1'));
+        $this->assertEquals($attributes['new1'], ['testvalue1']);
     }
 
     /**
@@ -131,15 +133,15 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testWrongAttributeName()
     {
-        $config = array(
-            array('value2'),
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        $config = [
+            ['value2'],
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -149,14 +151,14 @@ class Test_Core_Auth_Process_AttributeCopy extends TestCase
      */
     public function testWrongAttributeValue()
     {
-        $config = array(
+        $config = [
             'test' => 100,
-        );
-        $request = array(
-            'Attributes' => array(
-                'test' => array('value1'),
-            ),
-        );
-        $result = self::processFilter($config, $request);
+        ];
+        $request = [
+            'Attributes' => [
+                'test' => ['value1'],
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 }
diff --git a/tests/modules/core/lib/Auth/Process/AttributeLimitTest.php b/tests/modules/core/lib/Auth/Process/AttributeLimitTest.php
index 57e912e88cdf993f143e9240e79acd455b8738a3..01e2a6bee53060c72a1c9a3aae39e8a1b82b1267 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeLimitTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeLimitTest.php
@@ -1,13 +1,14 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeLimit filter.
  */
-class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
+class AttributeLimitTest extends TestCase
 {
-
     /**
      * Helper function to run the filter with a given configuration.
      *
@@ -17,7 +18,7 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeLimit($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeLimit($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,23 +28,23 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testIdPAttrs()
     {
-        $config = array(
+        $config = [
             'cn', 'mail'
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'eduPersonTargetedID' => array('eptid@example.org'),
-                 'eduPersonAffiliation' => array('member'),
-                 'cn' => array('user name'),
-                 'mail' => array('user@example.org'),
-             ),
-            'Destination' => array(
-             ),
-            'Source' => array(
-                'attributes' => array('cn','mail'),
-             ),
-        );
+        ];
+
+        $request = [
+            'Attributes' => [
+                 'eduPersonTargetedID' => ['eptid@example.org'],
+                 'eduPersonAffiliation' => ['member'],
+                 'cn' => ['user name'],
+                 'mail' => ['user@example.org'],
+            ],
+            'Destination' => [
+            ],
+            'Source' => [
+                'attributes' => ['cn', 'mail'],
+            ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
@@ -53,10 +54,10 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
         $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
         $this->assertCount(2, $attributes);
 
-        $config = array(
+        $config = [
             'cn',
-            'default' => TRUE,
-        );
+            'default' => true,
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
@@ -65,8 +66,6 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
         $this->assertArrayNotHasKey('eduPersonTargetedID', $attributes);
         $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
         $this->assertCount(2, $attributes);
-
-
     }
 
     /**
@@ -74,22 +73,22 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testNULLMetadataAttrs()
     {
-        $config = array(
+        $config = [
             'cn', 'mail'
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'eduPersonTargetedID' => array('eptid@example.org'),
-                 'eduPersonAffiliation' => array('member'),
-                 'cn' => array('user name'),
-                 'mail' => array('user@example.org'),
-             ),
-            'Destination' => array(
-             ),
-            'Source' => array(
-             ),
-        );
+        ];
+
+        $request = [
+            'Attributes' => [
+                 'eduPersonTargetedID' => ['eptid@example.org'],
+                 'eduPersonAffiliation' => ['member'],
+                 'cn' => ['user name'],
+                 'mail' => ['user@example.org'],
+            ],
+            'Destination' => [
+            ],
+            'Source' => [
+            ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
@@ -99,10 +98,10 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
         $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
         $this->assertCount(2, $attributes);
 
-        $config = array(
+        $config = [
             'cn',
-            'default' => TRUE,
-        );
+            'default' => true,
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
@@ -112,8 +111,8 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
         $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes);
         $this->assertCount(1, $attributes);
 
-        $config = array(
-        );
+        $config = [
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
@@ -132,19 +131,19 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
 
     public static function setUpBeforeClass()
     {
-        self::$request = array(
-            'Attributes' => array(
-                 'eduPersonTargetedID' => array('eptid@example.org'),
-                 'eduPersonAffiliation' => array('member'),
-                 'cn' => array('common name'),
-                 'mail' => array('user@example.org'),
-             ),
-            'Destination' => array(
-		'attributes' => array('cn','mail'),
-             ),
-            'Source' => array(
-             ),
-        );
+        self::$request = [
+            'Attributes' => [
+                 'eduPersonTargetedID' => ['eptid@example.org'],
+                 'eduPersonAffiliation' => ['member'],
+                 'cn' => ['common name'],
+                 'mail' => ['user@example.org'],
+            ],
+            'Destination' => [
+                'attributes' => ['cn', 'mail'],
+            ],
+            'Source' => [
+            ],
+        ];
     }
 
     /**
@@ -152,9 +151,9 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'cn', 'mail'
-        );
+        ];
 
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
@@ -168,9 +167,9 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testDefaultWithMetadata()
     {
-        $config = array(
-            'default' => TRUE,
-        );
+        $config = [
+            'default' => true,
+        ];
 
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
@@ -184,10 +183,10 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testDefaultWithAttrs()
     {
-        $config = array(
-            'default' => TRUE,
+        $config = [
+            'default' => true,
             'eduPersonTargetedID', 'eduPersonAffiliation',
-        );
+        ];
 
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
@@ -205,11 +204,11 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testInvalidConfig()
     {
-        $config = array(
-            'invalidArg' => TRUE,
-        );
+        $config = [
+            'invalidArg' => true,
+        ];
 
-        $result = self::processFilter($config, self::$request);
+        self::processFilter($config, self::$request);
     }
 
     /**
@@ -219,11 +218,11 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testInvalidAttributeName()
     {
-        $config = array(
-		null
-        );
+        $config = [
+            null
+        ];
 
-        $result = self::processFilter($config, self::$request);
+        self::processFilter($config, self::$request);
     }
 
 
@@ -232,39 +231,209 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testMatchAttributeValues()
     {
-        $config = array(
-		'eduPersonAffiliation' => array('member')
-        );
+        $config = [
+            'eduPersonAffiliation' => ['member']
+        ];
 
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
         $this->assertCount(1, $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
 
-        $config = array(
-		'eduPersonAffiliation' => array('member','staff')
-        );
+        $config = [
+            'eduPersonAffiliation' => ['member', 'staff']
+        ];
 
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
         $this->assertCount(1, $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
 
-        $config = array(
-		'eduPersonAffiliation' => array('student')
-        );
+        $config = [
+            'eduPersonAffiliation' => ['student']
+        ];
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
         $this->assertCount(0, $attributes);
 
-        $config = array(
-		'eduPersonAffiliation' => array('student','staff')
-        );
+        $config = [
+            'eduPersonAffiliation' => ['student', 'staff']
+        ];
+        $result = self::processFilter($config, self::$request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(0, $attributes);
+    }
+
+    public function testBadOptionsNotTreatedAsValidValues()
+    {
+        // Ensure really misconfigured ignoreCase and regex options are not interpretted as valid valus
+        $config = [
+            'eduPersonAffiliation' => ['ignoreCase' => 'member', 'nomatch'],
+            'mail' => ['regex' => 'user@example.org', 'nomatch']
+        ];
+        $result = self::processFilter($config, self::$request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(0, $attributes);
+    }
+
+    /**
+     * Verify that the true value for ignoreCase doesn't get converted into a string ('1') by
+     * php and matched against an attribute value of '1'
+     */
+    public function testThatIgnoreCaseOptionNotMatchBooleanAsStringValue()
+    {
+        $config = [
+            'someAttribute' => ['ignoreCase' => true, 'someValue']
+        ];
+
+        $request = [
+            'Attributes' => [
+                'someAttribute' => ['1'], //boolean true as a string
+
+            ],
+        ];
+        $result = self::processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(0, $attributes);
+    }
+
+    /**
+     * Test for attribute value matching ignore case
+     */
+    public function testMatchAttributeValuesIgnoreCase()
+    {
+        $config = [
+            'eduPersonAffiliation' => ['ignoreCase' => true, 'meMber']
+        ];
+
         $result = self::processFilter($config, self::$request);
         $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
+
+        $config = [
+            'eduPersonAffiliation' => ['ignoreCase' => true, 'membeR', 'sTaff']
+        ];
+
+        $result = self::processFilter($config, self::$request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
+
+        $config = [
+            'eduPersonAffiliation' => ['ignoreCase' => true, 'Student']
+        ];
+        $result = self::processFilter($config, self::$request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(0, $attributes);
+
+        $config = [
+            'eduPersonAffiliation' => ['ignoreCase' => true, 'studeNt', 'sTaff']
+        ];
+        $result = self::processFilter($config, self::$request);
+        $attributes = $result['Attributes'];
+        $this->assertCount(0, $attributes);
+    }
+
+    /**
+     * Test for attribute value matching
+     */
+    public function testMatchAttributeValuesRegex()
+    {
+        // SSP Logger requires a configuration to be set.
+        \SimpleSAML\Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
+        $state = self::$request;
+        $state['Attributes']['eduPersonEntitlement'] = [
+            'urn:mace:example.terena.org:tcs:personal-user',
+            'urn:x-surfnet:surfdomeinen.nl:role:dnsadmin',
+            'urn:x-surfnet:surf.nl:surfdrive:quota:100',
+            '1' //boolean true as a string
+        ];
+
+        $config = [
+            'eduPersonEntitlement' => [
+                'regex' => true,
+                '/^urn:x-surfnet:surf/'
+            ]
+        ];
+
+        $result = self::processFilter($config, $state);
+        $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonEntitlement', $attributes);
+        $this->assertEquals(
+            ['urn:x-surfnet:surfdomeinen.nl:role:dnsadmin', 'urn:x-surfnet:surf.nl:surfdrive:quota:100'],
+            $attributes['eduPersonEntitlement']
+        );
+
+        // Matching multiple lines shouldn't duplicate the attribute
+        $config = [
+            'eduPersonEntitlement' => [
+                'regex' => true,
+                '/urn:x-surfnet:surf/',
+                '/urn:x-surfnet/'
+
+            ]
+        ];
+
+        $result = self::processFilter($config, $state);
+        $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonEntitlement', $attributes);
+        $this->assertEquals(
+            ['urn:x-surfnet:surfdomeinen.nl:role:dnsadmin', 'urn:x-surfnet:surf.nl:surfdrive:quota:100'],
+            $attributes['eduPersonEntitlement']
+        );
+
+        // Invalid and no-match regex expressions should not stop a valid regex from matching
+        $config = [
+            'eduPersonEntitlement' => [
+                'regex' => true,
+                '/urn:mace:example.terena.org:tcs:no-match/',
+                '$invalidRegex[',
+                '/^URN:x-surf.*SURF.*n$/i'
+            ]
+        ];
+
+        $result = self::processFilter($config, $state);
+        $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonEntitlement', $attributes);
+        $this->assertEquals(
+            ['urn:x-surfnet:surfdomeinen.nl:role:dnsadmin'],
+            $attributes['eduPersonEntitlement']
+        );
+
+        // No matches should remove attribute
+        $config = [
+            'eduPersonEntitlement' => [
+                'regex' => true,
+                '/urn:x-no-match/'
+            ]
+        ];
+        $result = self::processFilter($config, $state);
+        $attributes = $result['Attributes'];
         $this->assertCount(0, $attributes);
+
+        // A regex that matches an input value multiple times should work.
+        $config = [
+            'eduPersonEntitlement' => [
+                'regex' => true,
+                '/surf/'
+            ]
+        ];
+        $result = self::processFilter($config, $state);
+        $attributes = $result['Attributes'];
+        $this->assertCount(1, $attributes);
+        $this->assertArrayHasKey('eduPersonEntitlement', $attributes);
+        $this->assertEquals(
+            ['urn:x-surfnet:surfdomeinen.nl:role:dnsadmin', 'urn:x-surfnet:surf.nl:surfdrive:quota:100'],
+            $attributes['eduPersonEntitlement']
+        );
     }
 
     /**
@@ -277,26 +446,26 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testMatchAttributeValuesNotArray()
     {
-        $config = array(
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'eduPersonTargetedID' => array('eptid@example.org'),
-                 'eduPersonAffiliation' => array('member'),
-                 'cn' => array('user name'),
-                 'mail' => array('user@example.org'),
-                 'discardme' => array('somethingiswrong'),
-             ),
-            'Destination' => array(
-                'attributes' => array('eduPersonAffiliation' => 'student'),
-             ),
-            'Source' => array(
-             ),
-        );
-
-
-        $result = self::processFilter($config, $request);
+        $config = [
+        ];
+
+        $request = [
+            'Attributes' => [
+                 'eduPersonTargetedID' => ['eptid@example.org'],
+                 'eduPersonAffiliation' => ['member'],
+                 'cn' => ['user name'],
+                 'mail' => ['user@example.org'],
+                 'discardme' => ['somethingiswrong'],
+            ],
+            'Destination' => [
+                'attributes' => ['eduPersonAffiliation' => 'student'],
+            ],
+            'Source' => [
+            ],
+        ];
+
+
+        self::processFilter($config, $request);
     }
 
     /**
@@ -304,24 +473,24 @@ class Test_Core_Auth_Process_AttributeLimitTest extends TestCase
      */
     public function testNoIntersection()
     {
-        $config = array(
-            'default' => TRUE,
-        );
-
-        $request = array(
-            'Attributes' => array(
-                 'eduPersonTargetedID' => array('eptid@example.org'),
-                 'eduPersonAffiliation' => array('member'),
-                 'cn' => array('user name'),
-                 'mail' => array('user@example.org'),
-                 'discardme' => array('somethingiswrong'),
-             ),
-            'Destination' => array(
-                'attributes' => array('urn:oid:1.2.840.113549.1.9.1'),
-             ),
-            'Source' => array(
-             ),
-        );
+        $config = [
+            'default' => true,
+        ];
+
+        $request = [
+            'Attributes' => [
+                 'eduPersonTargetedID' => ['eptid@example.org'],
+                 'eduPersonAffiliation' => ['member'],
+                 'cn' => ['user name'],
+                 'mail' => ['user@example.org'],
+                 'discardme' => ['somethingiswrong'],
+            ],
+            'Destination' => [
+                'attributes' => ['urn:oid:1.2.840.113549.1.9.1'],
+            ],
+            'Source' => [
+            ],
+        ];
 
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
diff --git a/tests/modules/core/lib/Auth/Process/AttributeMapTest.php b/tests/modules/core/lib/Auth/Process/AttributeMapTest.php
index 719ad54cf222f10215dad485d6fb5c2b010ed5ce..7a14dc76c4a944c7dac0db8033431a998c9d87e4 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeMapTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeMapTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeMap filter.
  */
-class Test_Core_Auth_Process_AttributeMap extends TestCase
+class AttributeMapTest extends TestCase
 {
     /**
      * Helper function to run the filter with a given configuration.
@@ -16,7 +18,7 @@ class Test_Core_Auth_Process_AttributeMap extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeMap($config, null);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeMap($config, null);
         $filter->process($request);
         return $request;
     }
@@ -108,6 +110,51 @@ class Test_Core_Auth_Process_AttributeMap extends TestCase
         $this->assertEquals($expected, $result);
     }
 
+    public function testCircular()
+    {
+        $config = [
+            'attribute1' => 'attribute1',
+            'attribute2' => 'attribute2',
+        ];
+        $request = [
+            'Attributes' => [
+                'attribute1' => ['value'],
+                'attribute2' => ['value'],
+            ],
+        ];
+
+        $processed = self::processFilter($config, $request);
+        $result = $processed['Attributes'];
+        $expected = [
+            'attribute1' => ['value'],
+            'attribute2' => ['value'],
+        ];
+
+        $this->assertEquals($expected, $result);
+    }
+
+    public function testMissingMap()
+    {
+        $config = [
+            'attribute1' => 'attribute3',
+        ];
+        $request = [
+            'Attributes' => [
+                'attribute1' => ['value'],
+                'attribute2' => ['value'],
+            ],
+        ];
+
+        $processed = self::processFilter($config, $request);
+        $result = $processed['Attributes'];
+        $expected = [
+            'attribute2' => ['value'],
+            'attribute3' => ['value'],
+        ];
+
+        $this->assertEquals($expected, $result);
+    }
+
     public function testInvalidOriginalAttributeType()
     {
         $config = [
diff --git a/tests/modules/core/lib/Auth/Process/AttributeRealmTest.php b/tests/modules/core/lib/Auth/Process/AttributeRealmTest.php
index 915475d17d559b7eb163eff0dd6242e38f034978..f7d0ef60637720f0041bd85d1e4d0b9e8bfcf9ac 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeRealmTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeRealmTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:AttributeRealm filter.
  */
-class Test_Core_Auth_Process_AttributeRealm extends TestCase
+class AttributeRealmTest extends TestCase
 {
 
     /**
@@ -17,7 +19,7 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_AttributeRealm($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\AttributeRealm($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,16 +29,16 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
-        );
-        $request = array(
-            'Attributes' => array(),
+        $config = [
+        ];
+        $request = [
+            'Attributes' => [],
             'UserID' => 'user2@example.org',
-        );
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('realm', $attributes);
-        $this->assertEquals($attributes['realm'], array('example.org'));
+        $this->assertEquals($attributes['realm'], ['example.org']);
     }
 
     /**
@@ -46,12 +48,12 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testNoUserID()
     {
-        $config = array(
-        );
-        $request = array(
-            'Attributes' => array(),
-        );
-        $result = self::processFilter($config, $request);
+        $config = [
+        ];
+        $request = [
+            'Attributes' => [],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -59,21 +61,21 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testAttributeNameConfig()
     {
-        $config = array(
+        $config = [
             'attributename' => 'schacHomeOrganization',
-        );
-        $request = array(
-            'Attributes' => array(
+        ];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Joe User',
                 'schacGender' => 9,
-            ),
+            ],
             'UserID' => 'user2@example.org',
-        );
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('schacHomeOrganization', $attributes);
         $this->assertArrayHasKey('displayName', $attributes);
-        $this->assertEquals($attributes['schacHomeOrganization'], array('example.org'));
+        $this->assertEquals($attributes['schacHomeOrganization'], ['example.org']);
     }
 
     /**
@@ -81,21 +83,21 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testTargetAttributeOverwritten()
     {
-        $config = array(
+        $config = [
             'attributename' => 'schacHomeOrganization',
-        );
-        $request = array(
-            'Attributes' => array(
+        ];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Joe User',
                 'schacGender' => 9,
                 'schacHomeOrganization' => 'example.com',
-            ),
+            ],
             'UserID' => 'user2@example.org',
-        );
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('schacHomeOrganization', $attributes);
-        $this->assertEquals($attributes['schacHomeOrganization'], array('example.org'));
+        $this->assertEquals($attributes['schacHomeOrganization'], ['example.org']);
     }
 
     /**
@@ -103,13 +105,13 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testNoAtisNoOp()
     {
-        $config = array();
-        $request = array(
-            'Attributes' => array(
+        $config = [];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Joe User',
-            ),
+            ],
             'UserID' => 'user2',
-        );
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('realm', $attributes);
@@ -120,13 +122,13 @@ class Test_Core_Auth_Process_AttributeRealm extends TestCase
      */
     public function testMultiAtisNoOp()
     {
-        $config = array();
-        $request = array(
-            'Attributes' => array(
+        $config = [];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Joe User',
-            ),
+            ],
             'UserID' => 'user2@home@example.org',
-        );
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('realm', $attributes);
diff --git a/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php b/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php
index a6d601f06bfa821ab68f514fd471d1f37a8a4a47..ddf07427342248d0bd30e86c8374cfbe9c44b359 100644
--- a/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php
+++ b/tests/modules/core/lib/Auth/Process/AttributeValueMapTest.php
@@ -34,26 +34,26 @@ class AttributeValueMapTest extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'sourceattribute' => 'memberOf',
             'targetattribute' => 'eduPersonAffiliation',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
                     'otherGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('memberOf', $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
     }
 
 
@@ -65,27 +65,27 @@ class AttributeValueMapTest extends TestCase
      */
     public function testNoDuplicates()
     {
-        $config = array(
+        $config = [
             'sourceattribute' => 'memberOf',
             'targetattribute' => 'eduPersonAffiliation',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
                     'otherGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup', 'otherGroup'),
-                'eduPersonAffiliation' => array('member', 'someValue'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup', 'otherGroup'],
+                'eduPersonAffiliation' => ['member', 'someValue'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('memberOf', $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('member', 'someValue'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member', 'someValue']);
     }
 
 
@@ -97,28 +97,28 @@ class AttributeValueMapTest extends TestCase
      */
     public function testReplace()
     {
-        $config = array(
+        $config = [
             'sourceattribute' => 'memberOf',
             'targetattribute' => 'eduPersonAffiliation',
             '%replace',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
                     'otherGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-                'eduPersonAffiliation' => array('someValue'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+                'eduPersonAffiliation' => ['someValue'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayNotHasKey('memberOf', $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('member'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['member']);
     }
 
 
@@ -130,28 +130,28 @@ class AttributeValueMapTest extends TestCase
      */
     public function testKeep()
     {
-        $config = array(
+        $config = [
             'sourceattribute' => 'memberOf',
             'targetattribute' => 'eduPersonAffiliation',
             '%keep',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
                     'otherGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-                'eduPersonAffiliation' => array('someValue'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+                'eduPersonAffiliation' => ['someValue'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('memberOf', $attributes);
         $this->assertArrayHasKey('eduPersonAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonAffiliation'], array('someValue','member'));
+        $this->assertEquals($attributes['eduPersonAffiliation'], ['someValue', 'member']);
     }
 
 
@@ -163,21 +163,21 @@ class AttributeValueMapTest extends TestCase
      */
     public function testUnknownFlag()
     {
-        $config = array(
+        $config = [
             '%test',
             'targetattribute' => 'affiliation',
             'sourceattribute' => 'memberOf',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+            ],
+        ];
         $result = self::processFilter($config, $request);
         $this->assertArrayHasKey('affiliation', $result['Attributes']);
         $this->assertArrayNotHasKey('memberOf', $result['Attributes']);
@@ -195,19 +195,19 @@ class AttributeValueMapTest extends TestCase
      */
     public function testMissingSourceAttribute()
     {
-        $config = array(
+        $config = [
             'targetattribute' => 'affiliation',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+            ],
+        ];
         self::processFilter($config, $request);
     }
 
@@ -222,19 +222,19 @@ class AttributeValueMapTest extends TestCase
      */
     public function testMissingTargetAttribute()
     {
-        $config = array(
+        $config = [
             'sourceattribute' => 'memberOf',
-            'values' => array(
-                'member' => array(
+            'values' => [
+                'member' => [
                     'theGroup',
-                ),
-            ),
-        );
-        $request = array(
-            'Attributes' => array(
-                'memberOf' => array('theGroup'),
-            ),
-        );
+                ],
+            ],
+        ];
+        $request = [
+            'Attributes' => [
+                'memberOf' => ['theGroup'],
+            ],
+        ];
         self::processFilter($config, $request);
     }
 }
diff --git a/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php b/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..533bb9f1187e1e52646e847376598416cf65d48e
--- /dev/null
+++ b/tests/modules/core/lib/Auth/Process/CardinalitySingleTest.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
+// Alias the PHPUnit 6.0 ancestor if available, else fall back to legacy ancestor
+if (class_exists('\PHPUnit\Framework\TestCase', true) and !class_exists('\PHPUnit_Framework_TestCase', true)) {
+    class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase', true);
+}
+
+/**
+ * Test for the core:CardinalitySingle filter.
+ */
+class CardinalitySingleTest extends \PHPUnit_Framework_TestCase
+{
+    private $http;
+
+    /**
+     * Helper function to run the filter with a given configuration.
+     *
+     * @param  array $config The filter configuration.
+     * @param  array $request The request state.
+     * @return array  The state array after processing.
+     */
+    private function processFilter(array $config, array $request)
+    {
+        $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
+        $_SERVER['REQUEST_METHOD'] = 'GET';
+        $filter = new \SimpleSAML\Module\core\Auth\Process\CardinalitySingle($config, null, $this->http);
+        $filter->process($request);
+        return $request;
+    }
+
+    protected function setUp()
+    {
+        \SimpleSAML\Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
+        $this->http = $this->getMockBuilder('SimpleSAML\Utils\HTTPAdapter')
+                           ->setMethods(['redirectTrustedURL'])
+                           ->getMock();
+    }
+
+    /**
+     * Test singleValued
+     */
+    public function testSingleValuedUnchanged()
+    {
+        $config = [
+            'singleValued' => ['eduPersonPrincipalName']
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['eduPersonPrincipalName' => ['joe@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /**
+     * Test first value extraction
+     */
+    public function testFirstValue()
+    {
+        $config = [
+            'firstValue' => ['eduPersonPrincipalName']
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com', 'bob@example.net'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['eduPersonPrincipalName' => ['joe@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Only first value should be returned");
+    }
+
+    public function testFirstValueUnchanged()
+    {
+        $config = [
+            'firstValue' => ['eduPersonPrincipalName']
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['eduPersonPrincipalName' => ['joe@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /**
+     * Test flattening
+     */
+    public function testFlatten()
+    {
+        $config = [
+            'flatten' => ['eduPersonPrincipalName'],
+            'flattenWith' => '|',
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com', 'bob@example.net'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['eduPersonPrincipalName' => ['joe@example.com|bob@example.net']];
+        $this->assertEquals($expectedData, $attributes, "Flattened string should be returned");
+    }
+
+    public function testFlattenUnchanged()
+    {
+        $config = [
+            'flatten' => ['eduPersonPrincipalName'],
+            'flattenWith' => '|',
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['eduPersonPrincipalName' => ['joe@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /**
+     * Test abort
+     */
+    public function testAbort()
+    {
+        $config = [
+            'singleValued' => ['eduPersonPrincipalName'],
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['joe@example.com', 'bob@example.net'],
+            ],
+        ];
+
+        $this->http->expects($this->once())
+                   ->method('redirectTrustedURL');
+
+        $this->processFilter($config, $request);
+    }
+}
diff --git a/tests/modules/core/lib/Auth/Process/CardinalityTest.php b/tests/modules/core/lib/Auth/Process/CardinalityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1dec455bb82065eac4257f6d461fb9f2587aea38
--- /dev/null
+++ b/tests/modules/core/lib/Auth/Process/CardinalityTest.php
@@ -0,0 +1,249 @@
+<?php
+
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
+// Alias the PHPUnit 6.0 ancestor if available, else fall back to legacy ancestor
+if (class_exists('\PHPUnit\Framework\TestCase', true) and !class_exists('\PHPUnit_Framework_TestCase', true)) {
+    class_alias('\PHPUnit\Framework\TestCase', '\PHPUnit_Framework_TestCase', true);
+}
+
+/**
+ * Test for the core:Cardinality filter.
+ */
+class CardinalityTest extends \PHPUnit_Framework_TestCase
+{
+    private $http;
+
+    /**
+     * Helper function to run the filter with a given configuration.
+     *
+     * @param  array $config The filter configuration.
+     * @param  array $request The request state.
+     * @return array  The state array after processing.
+     */
+    private function processFilter(array $config, array $request)
+    {
+        $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
+        $_SERVER['REQUEST_METHOD'] = 'GET';
+        $filter = new \SimpleSAML\Module\core\Auth\Process\Cardinality($config, null, $this->http);
+        $filter->process($request);
+        return $request;
+    }
+
+    protected function setUp()
+    {
+        \SimpleSAML\Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
+        $this->http = $this->getMockBuilder('SimpleSAML\Utils\HTTPAdapter')
+                           ->setMethods(['redirectTrustedURL'])
+                           ->getMock();
+    }
+
+    /*
+     * Test where a minimum is set but no maximum
+     */
+    public function testMinNoMax()
+    {
+        $config = [
+            'mail' => ['min' => 1],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['mail' => ['joe@example.com', 'bob@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /*
+     * Test where a maximum is set but no minimum
+     */
+    public function testMaxNoMin()
+    {
+        $config = [
+            'mail' => ['max' => 2],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['mail' => ['joe@example.com', 'bob@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /*
+     * Test in bounds within a maximum an minimum
+     */
+    public function testMaxMin()
+    {
+        $config = [
+            'mail' => ['min' => 1, 'max' => 2],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $result = $this->processFilter($config, $request);
+        $attributes = $result['Attributes'];
+        $expectedData = ['mail' => ['joe@example.com', 'bob@example.com']];
+        $this->assertEquals($expectedData, $attributes, "Assertion values should not have changed");
+    }
+
+    /**
+     * Test maximum is out of bounds results in redirect
+     */
+    public function testMaxOutOfBounds()
+    {
+        $config = [
+            'mail' => ['max' => 2],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com', 'fred@example.com'],
+            ],
+        ];
+
+        $this->http->expects($this->once())
+                   ->method('redirectTrustedURL');
+
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test minimum is out of bounds results in redirect
+     */
+    public function testMinOutOfBounds()
+    {
+        $config = [
+            'mail' => ['min' => 3],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+
+        $this->http->expects($this->once())
+                   ->method('redirectTrustedURL');
+
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test missing attribute results in redirect
+     */
+    public function testMissingAttribute()
+    {
+        $config = [
+            'mail' => ['min' => 1],
+        ];
+        $request = [
+            'Attributes' => [],
+        ];
+
+        $this->http->expects($this->once())
+                   ->method('redirectTrustedURL');
+
+        $this->processFilter($config, $request);
+    }
+
+    /*
+     * Configuration errors
+     */
+
+    /**
+     * Test invalid minimum values
+     * @expectedException \SimpleSAML\Error\Exception
+     * @expectedExceptionMessageRegExp /Minimum/
+     */
+    public function testMinInvalid()
+    {
+        $config = [
+            'mail' => ['min' => false],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test invalid minimum values
+     * @expectedException \SimpleSAML\Error\Exception
+     * @expectedExceptionMessageRegExp /Minimum/
+     */
+    public function testMinNegative()
+    {
+        $config = [
+            'mail' => ['min' => -1],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test invalid maximum values
+     * @expectedException \SimpleSAML\Error\Exception
+     * @expectedExceptionMessageRegExp /Maximum/
+     */
+    public function testMaxInvalid()
+    {
+        $config = [
+            'mail' => ['max' => false],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test maximum < minimum
+     * @expectedException \SimpleSAML\Error\Exception
+     * @expectedExceptionMessageRegExp /less than/
+     */
+    public function testMinGreaterThanMax()
+    {
+        $config = [
+            'mail' => ['min' => 2, 'max' => 1],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $this->processFilter($config, $request);
+    }
+
+    /**
+     * Test invalid attribute name
+     * @expectedException \SimpleSAML\Error\Exception
+     * @expectedExceptionMessageRegExp /Invalid attribute/
+     */
+    public function testInvalidAttributeName()
+    {
+        $config = [
+            ['min' => 2, 'max' => 1],
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['joe@example.com', 'bob@example.com'],
+            ],
+        ];
+        $this->processFilter($config, $request);
+    }
+}
diff --git a/tests/modules/core/lib/Auth/Process/PHPTest.php b/tests/modules/core/lib/Auth/Process/PHPTest.php
index f4b0342e36319245d93d2e73d394a341ff0a6712..e37bee1adb2bd60098c1c04ed4ef789e55526a7e 100644
--- a/tests/modules/core/lib/Auth/Process/PHPTest.php
+++ b/tests/modules/core/lib/Auth/Process/PHPTest.php
@@ -1,13 +1,14 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:PHP filter.
  */
-class Test_Core_Auth_Process_PHP extends TestCase
+class PHPTest extends TestCase
 {
-
     /**
      * Helper function to run the filter with a given configuration.
      *
@@ -18,7 +19,7 @@ class Test_Core_Auth_Process_PHP extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_PHP($config, null);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\PHP($config, null);
         @$filter->process($request);
         return $request;
     }
@@ -29,12 +30,12 @@ class Test_Core_Auth_Process_PHP extends TestCase
      */
     public function testInvalidConfiguration()
     {
-        $config = array();
+        $config = [];
         $this->setExpectedException(
-            "SimpleSAML_Error_Exception",
+            "\SimpleSAML\Error\Exception",
             "core:PHP: missing mandatory configuration option 'code'."
         );
-        new sspmod_core_Auth_Process_PHP($config, null);
+        new \SimpleSAML\Module\core\Auth\Process\PHP($config, null);
     }
 
 
@@ -43,17 +44,17 @@ class Test_Core_Auth_Process_PHP extends TestCase
      */
     public function testCodeDefined()
     {
-        $config = array(
+        $config = [
             'code' => '
                 $attributes["key"] = array("value");
             ',
-        );
-        $request = array('Attributes' => array());
-        $expected = array(
-            'Attributes' => array(
-                'key' => array('value'),
-            ),
-        );
+        ];
+        $request = ['Attributes' => []];
+        $expected = [
+            'Attributes' => [
+                'key' => ['value'],
+            ],
+        ];
 
         $this->assertEquals($expected, $this->processFilter($config, $request));
     }
@@ -63,25 +64,25 @@ class Test_Core_Auth_Process_PHP extends TestCase
      */
     public function testPreserveIncomingAttributes()
     {
-        $config = array(
+        $config = [
             'code' => '
                 $attributes["orig2"] = array("value0");
             ',
-        );
-        $request = array(
-            'Attributes' => array(
-                'orig1' => array('value1', 'value2'),
-                'orig2' => array('value3'),
-                'orig3' => array('value4')
-            )
-        );
-        $expected = array(
-            'Attributes' => array(
-                'orig1' => array('value1', 'value2'),
-                'orig2' => array('value0'),
-                'orig3' => array('value4')
-            ),
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'orig1' => ['value1', 'value2'],
+                'orig2' => ['value3'],
+                'orig3' => ['value4']
+            ]
+        ];
+        $expected = [
+            'Attributes' => [
+                'orig1' => ['value1', 'value2'],
+                'orig2' => ['value0'],
+                'orig3' => ['value4']
+            ],
+        ];
 
         $this->assertEquals($expected, $this->processFilter($config, $request));
     }
@@ -92,19 +93,19 @@ class Test_Core_Auth_Process_PHP extends TestCase
      */
     public function testThrowExceptionFromFilter()
     {
-        $config = array(
+        $config = [
             'code' => '
                  if (empty($attributes["uid"])) {
                      throw new Exception("Missing uid attribute.");
                  }
                  $attributes["uid"][0] = strtoupper($attributes["uid"][0]);
             ',
-        );
-        $request = array(
-            'Attributes' => array(
-                'orig1' => array('value1', 'value2'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'orig1' => ['value1', 'value2'],
+            ]
+        ];
 
         $this->setExpectedException(
             "Exception",
@@ -112,4 +113,42 @@ class Test_Core_Auth_Process_PHP extends TestCase
         );
         $this->processFilter($config, $request);
     }
+
+    /**
+     * Check that the entire state can be adjusted.
+     */
+    public function testStateCanBeModified()
+    {
+
+        $config = array(
+            'code' => '
+                $attributes["orig2"] = array("value0");
+                $state["newKey"] = ["newValue"];
+                $state["Destination"]["attributes"][] = "givenName";
+            ',
+        );
+        $request = array(
+            'Attributes' => array(
+                'orig1' => array('value1', 'value2'),
+                'orig2' => array('value3'),
+                'orig3' => array('value4')
+            ),
+            'Destination' => [
+                'attributes' => ['eduPersonPrincipalName']
+            ],
+        );
+        $expected = array(
+            'Attributes' => array(
+                'orig1' => array('value1', 'value2'),
+                'orig2' => array('value0'),
+                'orig3' => array('value4')
+            ),
+            'Destination' => [
+                'attributes' => ['eduPersonPrincipalName', 'givenName']
+            ],
+            'newKey' => ['newValue']
+        );
+
+        $this->assertEquals($expected, $this->processFilter($config, $request));
+    }
 }
diff --git a/tests/modules/core/lib/Auth/Process/ScopeAttributeTest.php b/tests/modules/core/lib/Auth/Process/ScopeAttributeTest.php
index 866fc1a641a60db42eaffa27365e8664957b6197..52b29234c3029dcafda913c7673a8c6217395731 100644
--- a/tests/modules/core/lib/Auth/Process/ScopeAttributeTest.php
+++ b/tests/modules/core/lib/Auth/Process/ScopeAttributeTest.php
@@ -1,13 +1,14 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:ScopeAttribute filter.
  */
-class Test_Core_Auth_Process_ScopeAttribute extends TestCase
+class ScopeAttributeTest extends TestCase
 {
-
     /*
      * Helper function to run the filter with a given configuration.
      *
@@ -17,7 +18,7 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_ScopeAttribute($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\ScopeAttribute($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,21 +28,21 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-                'eduPersonAffiliation' => array('member'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+                'eduPersonAffiliation' => ['member'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('eduPersonScopedAffiliation', $attributes);
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com'));
+        $this->assertEquals($attributes['eduPersonScopedAffiliation'], ['member@example.com']);
     }
 
     /*
@@ -49,21 +50,24 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testNoOverwrite()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-                'eduPersonAffiliation' => array('member'),
-                'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+                'eduPersonAffiliation' => ['member'],
+                'eduPersonScopedAffiliation' => ['library-walk-in@example.edu'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('library-walk-in@example.edu', 'member@example.com'));
+        $this->assertEquals(
+            $attributes['eduPersonScopedAffiliation'],
+            ['library-walk-in@example.edu', 'member@example.com']
+        );
     }
 
     /*
@@ -71,21 +75,21 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testNoDuplication()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-                'eduPersonAffiliation' => array('member'),
-                'eduPersonScopedAffiliation' => array('member@example.com'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+                'eduPersonAffiliation' => ['member'],
+                'eduPersonScopedAffiliation' => ['member@example.com'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com'));
+        $this->assertEquals($attributes['eduPersonScopedAffiliation'], ['member@example.com']);
     }
 
 
@@ -94,18 +98,18 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testNoSourceAttribute()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'mail' => array('j.doe@example.edu', 'john@example.org'),
-                'eduPersonAffiliation' => array('member'),
-                'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['j.doe@example.edu', 'john@example.org'],
+                'eduPersonAffiliation' => ['member'],
+                'eduPersonScopedAffiliation' => ['library-walk-in@example.edu'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
     }
@@ -115,18 +119,18 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testNoScopeAttribute()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'mail' => array('j.doe@example.edu', 'john@example.org'),
-                'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'),
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['j.doe@example.edu', 'john@example.org'],
+                'eduPersonScopedAffiliation' => ['library-walk-in@example.edu'],
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
     }
@@ -136,20 +140,20 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testMultiAt()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('john@doe@example.com'),
-                'eduPersonAffiliation' => array('member'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['john@doe@example.com'],
+                'eduPersonAffiliation' => ['member'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@doe@example.com'));
+        $this->assertEquals($attributes['eduPersonScopedAffiliation'], ['member@doe@example.com']);
     }
 
     /*
@@ -157,20 +161,23 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testMultivaluedSource()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'eduPersonPrincipalName',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-                'eduPersonAffiliation' => array('member','staff','faculty'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+                'eduPersonAffiliation' => ['member', 'staff', 'faculty'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com','staff@example.com','faculty@example.com'));
+        $this->assertEquals(
+            $attributes['eduPersonScopedAffiliation'],
+            ['member@example.com', 'staff@example.com', 'faculty@example.com']
+        );
     }
 
     /*
@@ -178,42 +185,42 @@ class Test_Core_Auth_Process_ScopeAttribute extends TestCase
      */
     public function testNoAt()
     {
-        $config = array(
+        $config = [
             'scopeAttribute' => 'schacHomeOrganization',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-        );
-        $request = array(
-            'Attributes' => array(
-                'schacHomeOrganization' => array('example.org'),
-                'eduPersonAffiliation' => array('student'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'schacHomeOrganization' => ['example.org'],
+                'eduPersonAffiliation' => ['student'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('student@example.org'));
+        $this->assertEquals($attributes['eduPersonScopedAffiliation'], ['student@example.org']);
     }
 
-	/*
-	 * When the target attribute exists and onlyIfEmpty is set
-	 */
-	public function testOnlyIfEmpty()
-	{
-       $config = array(
+    /*
+     * When the target attribute exists and onlyIfEmpty is set
+     */
+    public function testOnlyIfEmpty()
+    {
+        $config = [
             'scopeAttribute' => 'schacHomeOrganization',
             'sourceAttribute' => 'eduPersonAffiliation',
             'targetAttribute' => 'eduPersonScopedAffiliation',
-			'onlyIfEmpty' => true,
-        );
-        $request = array(
-            'Attributes' => array(
-                'schacHomeOrganization' => array('example.org'),
-                'eduPersonAffiliation' => array('student'),
-				'eduPersonScopedAffiliation' => array('staff@example.org', 'member@example.org'),
-            )
-        );
+            'onlyIfEmpty' => true,
+        ];
+        $request = [
+            'Attributes' => [
+                'schacHomeOrganization' => ['example.org'],
+                'eduPersonAffiliation' => ['student'],
+                'eduPersonScopedAffiliation' => ['staff@example.org', 'member@example.org'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('staff@example.org', 'member@example.org'));
-	}
+        $this->assertEquals($attributes['eduPersonScopedAffiliation'], ['staff@example.org', 'member@example.org']);
+    }
 }
diff --git a/tests/modules/core/lib/Auth/Process/ScopeFromAttributeTest.php b/tests/modules/core/lib/Auth/Process/ScopeFromAttributeTest.php
index 545093124dbe74709ed2b8fec9fd98eb90d212e1..a0abea39a7c0e1ae02383eb78cff579050cb6e77 100644
--- a/tests/modules/core/lib/Auth/Process/ScopeFromAttributeTest.php
+++ b/tests/modules/core/lib/Auth/Process/ScopeFromAttributeTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:ScopeFromAttribute filter.
  */
-class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
+class ScopeFromAttributeTest extends TestCase
 {
 
     /*
@@ -17,7 +19,7 @@ class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_ScopeFromAttribute($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\ScopeFromAttribute($config, null);
         $filter->process($request);
         return $request;
     }
@@ -27,19 +29,19 @@ class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
      */
     public function testBasic()
     {
-        $config = array(
+        $config = [
             'sourceAttribute' => 'eduPersonPrincipalName',
             'targetAttribute' => 'scope',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
         $this->assertArrayHasKey('scope', $attributes);
-        $this->assertEquals($attributes['scope'], array('example.com'));
+        $this->assertEquals($attributes['scope'], ['example.com']);
     }
 
     /*
@@ -47,19 +49,19 @@ class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
      */
     public function testNoOverwrite()
     {
-        $config = array(
+        $config = [
             'sourceAttribute' => 'eduPersonPrincipalName',
             'targetAttribute' => 'scope',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-                'scope' => array('example.edu')
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+                'scope' => ['example.edu']
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['scope'], array('example.edu'));
+        $this->assertEquals($attributes['scope'], ['example.edu']);
     }
 
     /*
@@ -67,16 +69,16 @@ class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
      */
     public function testNoSourceAttribute()
     {
-        $config = array(
+        $config = [
             'sourceAttribute' => 'eduPersonPrincipalName',
             'targetAttribute' => 'scope',
-        );
-        $request = array(
-            'Attributes' => array(
-                'mail' => array('j.doe@example.edu', 'john@example.org'),
-                'scope' => array('example.edu')
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'mail' => ['j.doe@example.edu', 'john@example.org'],
+                'scope' => ['example.edu']
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
     }
@@ -86,36 +88,34 @@ class Test_Core_Auth_Process_ScopeFromAttribute extends TestCase
      */
     public function testMultiAt()
     {
-        $config = array(
+        $config = [
             'sourceAttribute' => 'eduPersonPrincipalName',
             'targetAttribute' => 'scope',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('john@doe@example.com'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['john@doe@example.com'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
-        $this->assertEquals($attributes['scope'], array('example.com'));
+        $this->assertEquals($attributes['scope'], ['example.com']);
     }
 
     /*
      * When the source attribute doesn't have a scope, a warning is emitted
-     * NOTE: currently disabled: this triggers a warning and a warning
-     * wants to start a session which we cannot do in phpunit. How to fix?
      */
     public function testNoAt()
     {
-        $config = array(
+        $config = [
             'sourceAttribute' => 'eduPersonPrincipalName',
             'targetAttribute' => 'scope',
-        );
-        $request = array(
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('johndoe'),
-            )
-        );
+        ];
+        $request = [
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['johndoe'],
+            ]
+        ];
         $result = self::processFilter($config, $request);
         $attributes = $result['Attributes'];
 
diff --git a/tests/modules/core/lib/Auth/Process/TargetedIDTest.php b/tests/modules/core/lib/Auth/Process/TargetedIDTest.php
index 7cfc1abe3e222bf193a8514e1a10f3179914db66..b4ef4ee4b0b11fbe32da02223e64cca8bbdc94d6 100644
--- a/tests/modules/core/lib/Auth/Process/TargetedIDTest.php
+++ b/tests/modules/core/lib/Auth/Process/TargetedIDTest.php
@@ -1,11 +1,13 @@
 <?php
 
+namespace SimpleSAML\Test\Module\core\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
 /**
  * Test for the core:TargetedID filter.
  */
-class Test_Core_Auth_Process_TargetedID extends TestCase
+class TargetedIDTest extends TestCase
 {
     /**
      * Helper function to run the filter with a given configuration.
@@ -16,7 +18,7 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
      */
     private static function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_core_Auth_Process_TargetedID($config, NULL);
+        $filter = new \SimpleSAML\Module\core\Auth\Process\TargetedID($config, null);
         $filter->process($request);
         return $request;
     }
@@ -26,12 +28,11 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
 //     */
 //    public function testBasic()
 //    {
-//        $config = array(
-//        );
-//        $request = array(
-//            'Attributes' => array(),
+//        $config = [];
+//        $request = [
+//            'Attributes' => [],
 //            'UserID' => 'user2@example.org',
-//        );
+//        ];
 //        $result = self::processFilter($config, $request);
 //        $attributes = $result['Attributes'];
 //        $this->assertArrayHasKey('eduPersonTargetedID', $attributes);
@@ -44,22 +45,21 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
 //     */
 //    public function testWithSrcDst()
 //    {
-//        $config = array(
-//        );
-//        $request = array(
-//            'Attributes' => array(
+//        $config = [];
+//        $request = [
+//            'Attributes' => [
 //                'eduPersonTargetedID' => 'dummy',
-//            ),
+//            ],
 //            'UserID' => 'user2@example.org',
-//            'Source' => array(
+//            'Source' => [
 //                'metadata-set' => 'saml20-idp-hosted',
 //                'entityid' => 'urn:example:src:id',
-//            ),
-//            'Destination' => array(
+//            ],
+//            'Destination' => [
 //                'metadata-set' => 'saml20-sp-remote',
 //                'entityid' => 'joe',
-//            ),
-//        );
+//            ],
+//        ];
 //        $result = self::processFilter($config, $request);
 //        $attributes = $result['Attributes'];
 //        $this->assertArrayHasKey('eduPersonTargetedID', $attributes);
@@ -71,26 +71,28 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
 //     */
 //    public function testNameIdGeneration()
 //    {
-//        $config = array(
+//        $config = [
 //            'nameId' => true,
-//        );
+//        ];
 //        $request = array(
-//            'Attributes' => array(
-//            ),
+//            'Attributes' => [],
 //            'UserID' => 'user2@example.org',
-//            'Source' => array(
+//            'Source' => [
 //                'metadata-set' => 'saml20-idp-hosted',
 //                'entityid' => 'urn:example:src:id',
-//            ),
-//            'Destination' => array(
+//            ],
+//            'Destination' => [
 //                'metadata-set' => 'saml20-sp-remote',
 //                'entityid' => 'joe',
-//            ),
+//            ],
 //        );
 //        $result = self::processFilter($config, $request);
 //        $attributes = $result['Attributes'];
 //        $this->assertArrayHasKey('eduPersonTargetedID', $attributes);
-//        $this->assertRegExp('#^<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2\.0:assertion" NameQualifier="urn:example:src:id" SPNameQualifier="joe" Format="urn:oasis:names:tc:SAML:2\.0:nameid-format:persistent">[0-9a-f]{40}</saml:NameID>$#', $attributes['eduPersonTargetedID'][0]);
+//        $this->assertRegExp(
+//            '#^<saml:NameID xmlns:saml="urn:oasis:names:tc:SAML:2\.0:assertion" NameQualifier="urn:example:src:id" SPNameQualifier="joe" Format="urn:oasis:names:tc:SAML:2\.0:nameid-format:persistent">[0-9a-f]{40}</saml:NameID>$#',
+//            $attributes['eduPersonTargetedID'][0]
+//        );
 //    }
 //
 //    /**
@@ -98,30 +100,29 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
 //     */
 //    public function testIdIsPersistent()
 //    {
-//        $config = array(
-//        );
-//        $request = array(
-//            'Attributes' => array(
+//        $config = [];
+//        $request = [
+//            'Attributes' => [
 //                'eduPersonTargetedID' => 'dummy',
-//            ),
+//            ],
 //            'UserID' => 'user2@example.org',
-//            'Source' => array(
+//            'Source' => [
 //                'metadata-set' => 'saml20-idp-hosted',
 //                'entityid' => 'urn:example:src:id',
-//            ),
-//            'Destination' => array(
+//            ],
+//            'Destination' => [
 //                'metadata-set' => 'saml20-sp-remote',
 //                'entityid' => 'joe',
-//            ),
-//        );
+//            ],
+//        ];
 //        for ($i = 0; $i < 10; ++$i) {
-//		$result = self::processFilter($config, $request);
-//		$attributes = $result['Attributes'];
-//                $tid = $attributes['eduPersonTargetedID'][0];
-//                if (isset($prevtid)) {
-//                    $this->assertEquals($prevtid, $tid);
-//                    $prevtid = $tid;
-//                }
+//            $result = self::processFilter($config, $request);
+//            $attributes = $result['Attributes'];
+//            $tid = $attributes['eduPersonTargetedID'][0];
+//            if (isset($prevtid)) {
+//                $this->assertEquals($prevtid, $tid);
+//                $prevtid = $tid;
+//            }
 //        }
 //    }
 //
@@ -130,33 +131,31 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
 //     */
 //    public function testIdIsUnique()
 //    {
-//        $config = array(
-//        );
-//        $request = array(
-//            'Attributes' => array(
-//            ),
+//        $config = [];
+//        $request = [
+//            'Attributes' => [],
 //            'UserID' => 'user2@example.org',
-//            'Source' => array(
+//            'Source' => [
 //                'metadata-set' => 'saml20-idp-hosted',
 //                'entityid' => 'urn:example:src:id',
-//            ),
-//            'Destination' => array(
+//            ],
+//            'Destination' => [
 //                'metadata-set' => 'saml20-sp-remote',
 //                'entityid' => 'joe',
-//            ),
-//        );
-//	$result = self::processFilter($config, $request);
-//	$tid1 = $result['Attributes']['eduPersonTargetedID'][0];
+//            ],
+//        ];
+//        $result = self::processFilter($config, $request);
+//        $tid1 = $result['Attributes']['eduPersonTargetedID'][0];
 //
 //        $request['UserID'] = 'user3@example.org';
-//	$result = self::processFilter($config, $request);
-//	$tid2 = $result['Attributes']['eduPersonTargetedID'][0];
+//        $result = self::processFilter($config, $request);
+//        $tid2 = $result['Attributes']['eduPersonTargetedID'][0];
 //
 //        $this->assertNotEquals($tid1, $tid2);
 //
 //        $request['Destination']['entityid'] = 'urn:example.org:another-sp';
-//	$result = self::processFilter($config, $request);
-//	$tid3 = $result['Attributes']['eduPersonTargetedID'][0];
+//        $result = self::processFilter($config, $request);
+//        $tid3 = $result['Attributes']['eduPersonTargetedID'][0];
 //
 //        $this->assertNotEquals($tid2, $tid3);
 //    }
@@ -168,12 +167,11 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
      */
     public function testNoUserID()
     {
-        $config = array(
-        );
-        $request = array(
-            'Attributes' => array(),
-        );
-        $result = self::processFilter($config, $request);
+        $config = [];
+        $request = [
+            'Attributes' => [],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -183,15 +181,15 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
      */
     public function testAttributeNotExists()
     {
-        $config = array(
+        $config = [
             'attributename' => 'uid',
-        );
-        $request = array(
-            'Attributes' => array(
+        ];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Jack Student',
-            ),
-        );
-        $result = self::processFilter($config, $request);
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -201,15 +199,15 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
      */
     public function testConfigInvalidAttributeName()
     {
-        $config = array(
+        $config = [
             'attributename' => 5,
-        );
-        $request = array(
-            'Attributes' => array(
+        ];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Jack Student',
-            ),
-        );
-        $result = self::processFilter($config, $request);
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 
     /**
@@ -219,14 +217,14 @@ class Test_Core_Auth_Process_TargetedID extends TestCase
      */
     public function testConfigInvalidNameId()
     {
-        $config = array(
+        $config = [
             'nameId' => 'persistent',
-        );
-        $request = array(
-            'Attributes' => array(
+        ];
+        $request = [
+            'Attributes' => [
                 'displayName' => 'Jack Student',
-            ),
-        );
-        $result = self::processFilter($config, $request);
+            ],
+        ];
+        self::processFilter($config, $request);
     }
 }
diff --git a/tests/modules/core/lib/Auth/UserPassBaseTest.php b/tests/modules/core/lib/Auth/UserPassBaseTest.php
index ff248bdc5459814ed92f3881fe4319ef4dc7c873..cd5a328acad88345e76d28676b4ab543697743cb 100644
--- a/tests/modules/core/lib/Auth/UserPassBaseTest.php
+++ b/tests/modules/core/lib/Auth/UserPassBaseTest.php
@@ -1,18 +1,20 @@
 <?php
 
-class sspmod_core_Auth_UserPassBaseTest extends \PHPUnit_Framework_TestCase
+namespace SimpleSAML\Test\Module\core\Auth;
+
+class UserPassBaseTest extends \PHPUnit_Framework_TestCase
 {
     public function testAuthenticateECPCallsLoginAndSetsAttributes()
     {
-        $state = array();
-        $attributes = array('attrib' => 'val');
+        $state = [];
+        $attributes = ['attrib' => 'val'];
 
         $username = $state['core:auth:username'] = 'username';
         $password = $state['core:auth:password'] = 'password';
 
-        $stub = $this->getMockBuilder('sspmod_core_Auth_UserPassBase')
+        $stub = $this->getMockBuilder('\SimpleSAML\Module\core\Auth\UserPassBase')
             ->disableOriginalConstructor()
-            ->setMethods(array('login'))
+            ->setMethods(['login'])
             ->getMockForAbstractClass();
 
         $stub->expects($this->once())
@@ -27,17 +29,17 @@ class sspmod_core_Auth_UserPassBaseTest extends \PHPUnit_Framework_TestCase
 
     public function testAuthenticateECPCallsLoginWithForcedUsername()
     {
-        $state = array();
-        $attributes = array();
+        $state = [];
+        $attributes = [];
 
         $forcedUsername = 'forcedUsername';
 
         $state['core:auth:username'] = 'username';
         $password = $state['core:auth:password'] = 'password';
 
-        $stub = $this->getMockBuilder('sspmod_core_Auth_UserPassBase')
+        $stub = $this->getMockBuilder('\SimpleSAML\Module\core\Auth\UserPassBase')
             ->disableOriginalConstructor()
-            ->setMethods(array('login'))
+            ->setMethods(['login'])
             ->getMockForAbstractClass();
 
         $stub->expects($this->once())
diff --git a/tests/modules/core/lib/Auth/UserPassOrgBaseTest.php b/tests/modules/core/lib/Auth/UserPassOrgBaseTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7db0605b0679f534d9ea46d0a1c38db81d663e14
--- /dev/null
+++ b/tests/modules/core/lib/Auth/UserPassOrgBaseTest.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace SimpleSAML\Test\Module\core\Auth;
+
+use SimpleSAML\Module\core\Auth\UserPassOrgBase;
+
+class UserPassOrgBaseTest extends \PHPUnit_Framework_TestCase
+{
+    public function testRememberOrganizationEnabled()
+    {
+        $config = [
+            'ldap:LDAPMulti',
+
+            'remember.organization.enabled' => true,
+            'remember.organization.checked' => false,
+
+            'my-org' => [
+                'description' => 'My organization',
+                // The rest of the options are the same as those available for
+                // the LDAP authentication source.
+                'hostname' => 'ldap://ldap.myorg.com',
+                'dnpattern' => 'uid=%username%,ou=employees,dc=example,dc=org',
+                // Whether SSL/TLS should be used when contacting the LDAP server.
+                'enable_tls' => false,
+            ]
+        ];
+
+        $mockUserPassOrgBase = $this->getMockBuilder(\SimpleSAML\Module\core\Auth\UserPassOrgBase::class)
+            ->setConstructorArgs([['AuthId' => 'my-org'], &$config])
+            ->setMethods([])
+            ->getMockForAbstractClass();
+        $this->assertTrue($mockUserPassOrgBase->getRememberOrganizationEnabled());
+    }
+}
diff --git a/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php b/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d8f4d700006abf1c780d938902aae6cea14a498
--- /dev/null
+++ b/tests/modules/core/lib/Storage/SQLPermanentStorageTest.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace SimpleSAML\Test\Module\core\Storage;
+
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Test for the SQLPermanentStorage class.
+ */
+class SQLPermanentStorageTest extends TestCase
+{
+    private static $sql;
+
+    public static function setUpBeforeClass()
+    {
+        // Create instance
+        $config = \SimpleSAML\Configuration::loadFromArray([
+            'datadir' => sys_get_temp_dir(),
+        ]);
+        self::$sql = new \SimpleSAML\Module\core\Storage\SQLPermanentStorage('test', $config);
+    }
+
+    public static function tearDownAfterClass()
+    {
+        self::$sql = null;
+        unlink(sys_get_temp_dir().'/sqllite/test.sqlite');
+    }
+
+    public function testSet()
+    {
+        // Set a new value
+        self::$sql->set('testtype', 'testkey1', 'testkey2', 'testvalue', 2);
+
+        // Test getCondition
+        $result = self::$sql->get();
+        $this->assertEquals('testvalue', $result['value']);
+    }
+
+    public function testSetOverwrite()
+    {
+        // Overwrite existing value
+        self::$sql->set('testtype', 'testkey1', 'testkey2', 'testvaluemodified', 2);
+
+        // Test that the value was actually overwriten
+        $result = self::$sql->getValue('testtype', 'testkey1', 'testkey2');
+        $this->assertEquals('testvaluemodified', $result);
+
+        $result = self::$sql->getList('testtype', 'testkey1', 'testkey2');
+        $this->assertEquals('testvaluemodified', $result[0]['value']);
+    }
+
+    public function testNonexistentKey()
+    {
+        // Test that getting some non-existing key will return null
+        $result = self::$sql->getValue('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+        $result = self::$sql->getList('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+        $result = self::$sql->get('testtype_nonexistent', 'testkey1_nonexistent', 'testkey2_nonexistent');
+        $this->assertNull($result);
+    }
+
+    public function testExpiration()
+    {
+        // Make sure the earlier created entry has expired now
+        sleep(3);
+
+        // Make sure we can't get the expired entry anymore
+        $result = self::$sql->getValue('testtype', 'testkey1', 'testkey2');
+        $this->assertNull($result);
+
+        // Now add a second entry that never expires
+        self::$sql->set('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring', 'testvalue_nonexpiring', null);
+
+        // Expire entries and verify that only the second one is still there
+        self::$sql->removeExpired();
+        $result = self::$sql->getValue('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $this->assertEquals('testvalue_nonexpiring', $result);
+    }
+
+    public function testRemove()
+    {
+        // Now remove the nonexpiring entry and make sure it's gone
+        self::$sql->remove('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $result = self::$sql->getValue('testtype', 'testkey1_nonexpiring', 'testkey2_nonexpiring');
+        $this->assertNull($result);
+    }
+}
diff --git a/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php b/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php
index 08dd8ea52a8b59bd177f9a8997e03fe2f7fff563..05f808ee55512182656552cd23be9ac50b09c890 100644
--- a/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php
+++ b/tests/modules/ldap/lib/Auth/Process/BaseFilterTest.php
@@ -1,12 +1,14 @@
 <?php
 
+namespace SimpleSAML\Test\Module\ldap\Auth\Process;
+
 use PHPUnit\Framework\TestCase;
 
-class sspmod_ldap_Auth_Process_BaseFilter_Test extends TestCase
+class BaseFilterTest extends TestCase
 {
     public function testVarExportHidesLdapPassword()
     {
-        $stub = $this->getMockBuilder('sspmod_ldap_Auth_Process_BaseFilter')
+        $stub = $this->getMockBuilder('\SimpleSAML\Module\ldap\Auth\Process\BaseFilter')
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
         $class = new \ReflectionClass($stub);
@@ -15,11 +17,11 @@ class sspmod_ldap_Auth_Process_BaseFilter_Test extends TestCase
 
         $this->assertEquals(
             "array ( 'ldap.hostname' => 'ldap://172.17.101.32', 'ldap.port' => 389, 'ldap.password' => '********', )",
-            $method->invokeArgs($stub, array(array(
+            $method->invokeArgs($stub, [[
                 'ldap.hostname' => 'ldap://172.17.101.32',
                 'ldap.port' => 389,
                 'ldap.password' => 'password',
-            )))
+            ]])
         );
     }
 }
diff --git a/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php b/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php
index 1915c9c0e77316a4a7236e309ce6777ccb891cc9..20e9400b6dd685c233181a8da2f3fd8352e70192 100644
--- a/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php
+++ b/tests/modules/saml/lib/Auth/Process/FilterScopesTest.php
@@ -34,51 +34,51 @@ class FilterScopesTest extends TestCase
     public function testValidScopes()
     {
         // test declared scopes
-        $config = array();
-        $request = array(
-            'Source'     => array(
-                'SingleSignOnService' => array(
-                    array(
+        $config = [];
+        $request = [
+            'Source'     => [
+                'SingleSignOnService' => [
+                    [
                         'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                         'Location' => 'https://example.org/saml2/idp/SSOService.php',
-                    ),
-                ),
-                'scope' => array(
+                    ],
+                ],
+                'scope' => [
                     'example.com',
                     'example.net',
-                ),
-            ),
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.com'),
-            ),
-        );
+                ],
+            ],
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.com'],
+            ],
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
 
         // test multiple values
-        $request['Attributes'] = array(
-            'eduPersonPrincipalName' => array(
+        $request['Attributes'] = [
+            'eduPersonPrincipalName' => [
                 'jdoe@example.com',
                 'jdoe@example.net',
-            ),
-        );
+            ],
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
 
         // test implicit scope
-        $request['Attributes'] = array(
-            'eduPersonPrincipalName' => array('jdoe@example.org'),
-        );
+        $request['Attributes'] = [
+            'eduPersonPrincipalName' => ['jdoe@example.org'],
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
 
         // test alternative attributes
-        $config['attributes'] = array(
+        $config['attributes'] = [
             'mail',
-        );
-        $request['Attributes'] = array(
-            'mail' => array('john.doe@example.org'),
-        );
+        ];
+        $request['Attributes'] = [
+            'mail' => ['john.doe@example.org'],
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
 
@@ -95,43 +95,43 @@ class FilterScopesTest extends TestCase
     public function testInvalidScopes()
     {
         // test scope not matching anything, empty attribute
-        $config = array();
-        $request = array(
-            'Source'     => array(
-                'SingleSignOnService' => array(
-                    array(
+        $config = [];
+        $request = [
+            'Source'     => [
+                'SingleSignOnService' => [
+                    [
                         'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                         'Location' => 'https://example.org/saml2/idp/SSOService.php',
-                    ),
-                ),
-                'scope' => array(
+                    ],
+                ],
+                'scope' => [
                     'example.com',
                     'example.net',
-                ),
-            ),
-            'Attributes' => array(
-                'eduPersonPrincipalName' => array('jdoe@example.edu'),
-            ),
-        );
+                ],
+            ],
+            'Attributes' => [
+                'eduPersonPrincipalName' => ['jdoe@example.edu'],
+            ],
+        ];
         $result = $this->processFilter($config, $request);
-        $this->assertEquals(array(), $result['Attributes']);
+        $this->assertEquals([], $result['Attributes']);
 
         // test some scopes allowed and some others not
         $request['Attributes']['eduPersonPrincipalName'][] = 'jdoe@example.com';
         $result = $this->processFilter($config, $request);
         $this->assertEquals(
-            array(
-                'eduPersonPrincipalName' => array(
+            [
+                'eduPersonPrincipalName' => [
                     'jdoe@example.com',
-                ),
-            ),
+                ],
+            ],
             $result['Attributes']
         );
 
         // test attribute missing scope
-        $request['Attributes'] = array(
-            'eduPersonPrincipalName' => array('jdoe'),
-        );
+        $request['Attributes'] = [
+            'eduPersonPrincipalName' => ['jdoe'],
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals($request['Attributes'], $result['Attributes']);
     }
diff --git a/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php b/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php
index 56f02d540b6ebaab5f7bab518fcbf1ef926489ee..f20ee5b377935f3d9e204be8fd949d5f1b84a41f 100644
--- a/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php
+++ b/tests/modules/saml/lib/Auth/Process/NameIDAttributeTest.php
@@ -1,4 +1,7 @@
 <?php
+
+namespace SimpleSAML\Test\Module\saml\Auth\Process;
+
 /**
  * Test for the saml:NameIDAttribute filter.
  *
@@ -20,7 +23,7 @@ class NameIDAttributeTest extends TestCase
      */
     private function processFilter(array $config, array $request)
     {
-        $filter = new sspmod_saml_Auth_Process_NameIDAttribute($config, null);
+        $filter = new \SimpleSAML\Module\saml\Auth\Process\NameIDAttribute($config, null);
         $filter->process($request);
         return $request;
     }
@@ -31,7 +34,7 @@ class NameIDAttributeTest extends TestCase
      */
     public function testMinimalConfig()
     {
-        $config = array();
+        $config = [];
 
         $nameId = new \SAML2\XML\saml\NameID();
         $nameId->value = 'eugene@oombaas';
@@ -40,15 +43,15 @@ class NameIDAttributeTest extends TestCase
         $spId = 'eugeneSP';
         $idpId = 'eugeneIdP';
 
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => $spId,
-            ),
-            'Destination' => array(
+            ],
+            'Destination' => [
                 'entityid' => $idpId,
-            ),
+            ],
             'saml:sp:NameID' => $nameId,
-        );
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals("{$spId}!{$idpId}!{$nameId->value}", $result['Attributes']['nameid'][0]);
     }
@@ -59,7 +62,7 @@ class NameIDAttributeTest extends TestCase
     public function testCustomAttributeName()
     {
         $attributeName = 'eugeneNameIDAttribute';
-        $config = array('attribute' => $attributeName);
+        $config = ['attribute' => $attributeName];
 
         $nameId = new \SAML2\XML\saml\NameID();
         $nameId->value = 'eugene@oombaas';
@@ -68,15 +71,15 @@ class NameIDAttributeTest extends TestCase
         $spId = 'eugeneSP';
         $idpId = 'eugeneIdP';
 
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => $spId,
-            ),
-            'Destination' => array(
+            ],
+            'Destination' => [
                 'entityid' => $idpId,
-            ),
+            ],
             'saml:sp:NameID' => $nameId,
-        );
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertTrue(isset($result['Attributes'][$attributeName]));
         $this->assertEquals("{$spId}!{$idpId}!{$nameId->value}", $result['Attributes'][$attributeName][0]);
@@ -87,7 +90,7 @@ class NameIDAttributeTest extends TestCase
      */
     public function testFormat()
     {
-        $config = array('format' => '%V');
+        $config = ['format' => '%V'];
 
         $nameId = new \SAML2\XML\saml\NameID();
         $nameId->value = 'eugene@oombaas';
@@ -96,15 +99,15 @@ class NameIDAttributeTest extends TestCase
         $spId = 'eugeneSP';
         $idpId = 'eugeneIdP';
 
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => $spId,
-            ),
-            'Destination' => array(
+            ],
+            'Destination' => [
                 'entityid' => $idpId,
-            ),
+            ],
             'saml:sp:NameID' => $nameId,
-        );
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertEquals("{$nameId->value}", $result['Attributes']['nameid'][0]);
     }
@@ -116,7 +119,7 @@ class NameIDAttributeTest extends TestCase
     public function testCustomAttributeNameAndFormat()
     {
         $attributeName = 'eugeneNameIDAttribute';
-        $config = array('attribute' => $attributeName, 'format' => '%V');
+        $config = ['attribute' => $attributeName, 'format' => '%V'];
 
         $nameId = new \SAML2\XML\saml\NameID();
         $nameId->value = 'eugene@oombaas';
@@ -125,15 +128,15 @@ class NameIDAttributeTest extends TestCase
         $spId = 'eugeneSP';
         $idpId = 'eugeneIdP';
 
-        $request = array(
-            'Source'     => array(
+        $request = [
+            'Source'     => [
                 'entityid' => $spId,
-            ),
-            'Destination' => array(
+            ],
+            'Destination' => [
                 'entityid' => $idpId,
-            ),
+            ],
             'saml:sp:NameID' => $nameId,
-        );
+        ];
         $result = $this->processFilter($config, $request);
         $this->assertTrue(isset($result['Attributes'][$attributeName]));
         $this->assertEquals("{$nameId->value}", $result['Attributes'][$attributeName][0]);
diff --git a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
index 57baff5ff06b30480f5742dc97dde3f657e614f5..c1310986c847bbca8c195bfdd4fab7e6e2de8367 100644
--- a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
+++ b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php
@@ -3,7 +3,7 @@
 namespace SimpleSAML\Test\Module\saml\Auth\Source;
 
 use PHPUnit\Framework\TestCase;
-use \SimpleSAML_Configuration as Configuration;
+use \SimpleSAML\Configuration;
 
 /**
  * Custom Exception to throw to terminate a TestCase.
@@ -28,11 +28,11 @@ class ExitTestException extends \Exception
 
 
 /**
- * Wrap the SSP sspmod_saml_Auth_Source_SP class
+ * Wrap the SSP \SimpleSAML\Module\saml\Auth\Source\SP class
  * - Use introspection to make startSSO2Test available
  * - Override sendSAML2AuthnRequest() to catch the AuthnRequest being sent
  */
-class SP_Tester extends \sspmod_saml_Auth_Source_SP
+class SPTester extends \SimpleSAML\Module\saml\Auth\Source\SP
 {
 
     public function __construct($info, $config)
@@ -41,7 +41,7 @@ class SP_Tester extends \sspmod_saml_Auth_Source_SP
     }
 
 
-    public function startSSO2Test(\SimpleSAML_Configuration $idpMetadata, array $state)
+    public function startSSO2Test(Configuration $idpMetadata, array $state)
     {
         $reflector = new \ReflectionObject($this);
         $method = $reflector->getMethod('startSSO2');
@@ -55,20 +55,20 @@ class SP_Tester extends \sspmod_saml_Auth_Source_SP
     {
         // Exit test. Continuing would mean running into a assert(FALSE)
         throw new ExitTestException(
-            array(
+            [
                 'state'   => $state,
                 'binding' => $binding,
                 'ar'      => $ar,
-            )
+            ]
         );
     }
 }
 
 
 /**
- * Set of test cases for sspmod_saml_Auth_Source_SP.
+ * Set of test cases for \SimpleSAML\Module\saml\Auth\Source\SP.
  */
-class SP_Test extends TestCase
+class SPTest extends TestCase
 {
 
     private $idpMetadata = null;
@@ -79,7 +79,7 @@ class SP_Test extends TestCase
     private function getIdpMetadata()
     {
         if (!$this->idpMetadata) {
-            $this->idpMetadata = new \SimpleSAML_Configuration(
+            $this->idpMetadata = new Configuration(
                 $this->idpConfigArray,
                 'Auth_Source_SP_Test::getIdpMetadata()'
             );
@@ -91,17 +91,17 @@ class SP_Test extends TestCase
 
     protected function setUp()
     {
-        $this->idpConfigArray = array(
+        $this->idpConfigArray = [
             'metadata-set'        => 'saml20-idp-remote',
             'entityid'            => 'https://engine.surfconext.nl/authentication/idp/metadata',
-            'SingleSignOnService' => array(
-                array(
+            'SingleSignOnService' => [
+                [
                     'Binding'  => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
                     'Location' => 'https://engine.surfconext.nl/authentication/idp/single-sign-on',
-                ),
-            ),
-            'keys'                => array(
-                array(
+                ],
+            ],
+            'keys'                => [
+                [
                     'encryption'      => false,
                     'signing'         => true,
                     'type'            => 'X509Certificate',
@@ -121,27 +121,27 @@ class SP_Test extends TestCase
                         'ZkQO8EsscJPPy/Zp4uHAnADWACkOUHiCbcKiUUFu66dX0Wr/v53Gekz487GgVRs8HEeT9MU1reBKRgdENR8PNg4rbQfLc'.
                         '3YQKLWK7yWnn/RenjDpuCiePj8N8/80tGgrNgK/6fzM3zI18sSywnXLswxqDb/J+jgVxnQ6MrsTf1urM8MnfcxG/82oHI'.
                         'wfMh/sXPCZpo+DTLkhQxctJ3M=',
-                ),
-            ),
-        );
+                ],
+            ],
+        ];
 
-        $this->config = Configuration::loadFromArray(array(), '[ARRAY]', 'simplesaml');
+        $this->config = Configuration::loadFromArray([], '[ARRAY]', 'simplesaml');
     }
 
 
     /**
-     * Create a SAML AuthnRequest using sspmod_saml_Auth_Source_SP
+     * Create a SAML AuthnRequest using \SimpleSAML\Module\saml\Auth\Source\SP
      *
      * @param array $state The state array to use in the test. This is an array of the parameters described in section
      * 2 of https://simplesamlphp.org/docs/development/saml:sp
      *
      * @return \SAML2\AuthnRequest The AuthnRequest generated.
      */
-    private function createAuthnRequest($state = array())
+    private function createAuthnRequest($state = [])
     {
-        $info = array('AuthId' => 'default-sp');
-        $config = array();
-        $as = new SP_Tester($info, $config);
+        $info = ['AuthId' => 'default-sp'];
+        $config = [];
+        $as = new SPTester($info, $config);
 
         /** @var \SAML2\AuthnRequest $ar */
         $ar = null;
@@ -187,9 +187,9 @@ class SP_Test extends TestCase
      */
     public function testNameID()
     {
-        $state = array(
-            'saml:NameID' => array('Value' => 'user@example.org', 'Format' => \SAML2\Constants::NAMEID_UNSPECIFIED)
-        );
+        $state = [
+            'saml:NameID' => ['Value' => 'user@example.org', 'Format' => \SAML2\Constants::NAMEID_UNSPECIFIED]
+        ];
 
         /** @var \SAML2\AuthnRequest $ar */
         $ar = $this->createAuthnRequest($state);
@@ -219,9 +219,9 @@ class SP_Test extends TestCase
      */
     public function testAuthnContextClassRef()
     {
-        $state = array(
+        $state = [
             'saml:AuthnContextClassRef' => 'http://example.com/myAuthnContextClassRef'
-        );
+        ];
 
         /** @var \SAML2\AuthnRequest $ar */
         $ar = $this->createAuthnRequest($state);
@@ -248,9 +248,9 @@ class SP_Test extends TestCase
      */
     public function testForcedAuthn()
     {
-        $state = array(
+        $state = [
             'ForceAuthn' => true
-        );
+        ];
 
         /** @var \SAML2\AuthnRequest $ar */
         $ar = $this->createAuthnRequest($state);
diff --git a/tests/modules/saml/lib/IdP/SAML2Test.php b/tests/modules/saml/lib/IdP/SAML2Test.php
index 4ca2095920eeef09f42f75d7507d94e264462dd7..ef94baf9a28b7bf2510cfba38ba5d95d1820dcce 100644
--- a/tests/modules/saml/lib/IdP/SAML2Test.php
+++ b/tests/modules/saml/lib/IdP/SAML2Test.php
@@ -1,14 +1,21 @@
 <?php
 
-class sspmod_saml_IdP_SAML2Test extends \PHPUnit_Framework_TestCase
+namespace SimpleSAML\Test\Module\saml\IdP;
+
+use SimpleSAML\Configuration;
+use SimpleSAML\IdP;
+use SimpleSAML\Module\saml\IdP\SAML2;
+use SimpleSAML\Test\Utils\ClearStateTestCase;
+
+class SAML2Test extends ClearStateTestCase
 {
     public function testProcessSOAPAuthnRequest()
     {
         $username = $_SERVER['PHP_AUTH_USER'] = 'username';
         $password = $_SERVER['PHP_AUTH_PW'] = 'password';
-        $state = array();
+        $state = [];
 
-        sspmod_saml_IdP_SAML2::processSOAPAuthnRequest($state);
+        \SimpleSAML\Module\saml\IdP\SAML2::processSOAPAuthnRequest($state);
 
         $this->assertEquals($username, $state['core:auth:username']);
         $this->assertEquals($password, $state['core:auth:password']);
@@ -16,23 +23,217 @@ class sspmod_saml_IdP_SAML2Test extends \PHPUnit_Framework_TestCase
 
     public function testProcessSOAPAuthnRequestMissingUsername()
     {
-        $this->setExpectedException('SimpleSAML_Error_Error', 'WRONGUSERPASS');
+        $this->setExpectedException('\SimpleSAML\Error\Error', 'WRONGUSERPASS');
 
         $_SERVER['PHP_AUTH_PW'] = 'password';
         unset($_SERVER['PHP_AUTH_USER']);
-        $state = array();
+        $state = [];
+        Configuration::loadFromArray([
+            'baseurlpath' => 'https://idp.example.com/',
+        ], '', 'simplesaml');
 
-        sspmod_saml_IdP_SAML2::processSOAPAuthnRequest($state);
+        \SimpleSAML\Module\saml\IdP\SAML2::processSOAPAuthnRequest($state);
     }
 
     public function testProcessSOAPAuthnRequestMissingPassword()
     {
-        $this->setExpectedException('SimpleSAML_Error_Error', 'WRONGUSERPASS');
+        $this->setExpectedException('\SimpleSAML\Error\Error', 'WRONGUSERPASS');
 
         $_SERVER['PHP_AUTH_USER'] = 'username';
         unset($_SERVER['PHP_AUTH_PW']);
-        $state = array();
+        $state = [];
+
+        \SimpleSAML\Module\saml\IdP\SAML2::processSOAPAuthnRequest($state);
+    }
+
+    /**
+     * Default values for the state array expected to be generated at the start of logins
+     * @var array
+     */
+    private $defaultExpectedAuthState = [
+        'Responder' =>['\SimpleSAML\Module\saml\IdP\SAML2', 'sendResponse'],
+        '\SimpleSAML\Auth\State.exceptionFunc' => ['\SimpleSAML\Module\saml\IdP\SAML2', 'handleAuthError'],
+        'saml:RelayState' => null,
+        'saml:RequestId' => null,
+        'saml:IDPList' => [],
+        'saml:ProxyCount' => null,
+        'saml:RequesterID' => null,
+        'ForceAuthn' => false,
+        'isPassive' => false,
+        'saml:ConsumerURL' => 'SP-specific',
+        'saml:Binding' => 'SP-specific',
+        'saml:NameIDFormat' => null,
+        'saml:AllowCreate' => true,
+        'saml:Extensions' => null,
+        'saml:RequestedAuthnContext' => null];
+
+    /**
+     * Test that invoking the idp initiated endpoint with the minimum necessary parameters works.
+     */
+    public function testIdPInitiatedLoginMinimumParams()
+    {
+        $state = $this->idpInitiatedHelper(['spentityid' => 'https://some-sp-entity-id']);
+        $this->assertEquals('https://some-sp-entity-id', $state['SPMetadata']['entityid']);
+
+        $this->assertStringStartsWith(
+            'http://idp.examlple.com/saml2/idp/SSOService.php?spentityid=https%3A%2F%2Fsome-sp-entity-id&cookie',
+            $state['\SimpleSAML\Auth\State.restartURL']
+        );
+        unset($state['saml:AuthnRequestReceivedAt']); // timestamp can't be tested in equality assertion
+        unset($state['SPMetadata']); // entityid asserted above
+        unset($state['\SimpleSAML\Auth\State.restartURL']); // url contains a cookie time which varies by test
+
+        $expectedState = $this->defaultExpectedAuthState;
+        $expectedState[ 'saml:ConsumerURL'] = 'https://example.com/Shibboleth.sso/SAML2/POST';
+        $expectedState[ 'saml:Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST';
+
+        $this->assertEquals($expectedState, $state);
+    }
+
+    /**
+     * Test that invoking the idp initiated endpoint with the optional parameters works.
+     */
+    public function testIdPInitiatedLoginOptionalParams()
+    {
+        $state = $this->idpInitiatedHelper([
+            'spentityid' => 'https://some-sp-entity-id',
+            'RelayState' => 'http://relay',
+            'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:PAOS',
+            'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
+
+        ]);
+        $this->assertEquals('https://some-sp-entity-id', $state['SPMetadata']['entityid']);
+
+        //currently only spentityid and relay state are used in the restart url.
+        $this->assertStringStartsWith(
+            'http://idp.examlple.com/saml2/idp/SSOService.php?'
+            . 'spentityid=https%3A%2F%2Fsome-sp-entity-id&RelayState=http%3A%2F%2Frelay&cookieTime',
+            $state['\SimpleSAML\Auth\State.restartURL']
+        );
+        unset($state['saml:AuthnRequestReceivedAt']); // timestamp can't be tested in equality assertion
+        unset($state['SPMetadata']); // entityid asserted above
+        unset($state['\SimpleSAML\Auth\State.restartURL']); // url contains a cookie time which varies by test
+
+        $expectedState = $this->defaultExpectedAuthState;
+        $expectedState['saml:ConsumerURL'] = 'https://example.com/Shibboleth.sso/SAML2/ECP';
+        $expectedState['saml:Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:PAOS';
+        $expectedState['saml:NameIDFormat'] = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress';
+        $expectedState['saml:RelayState'] = 'http://relay';
+
+        $this->assertEquals($expectedState, $state);
+    }
+
+    /**
+     * Test that invoking the idp initiated endpoint using minimum shib params works
+     */
+    public function testIdPInitShibCompatyMinimumParams()
+    {
+        //https://wiki.shibboleth.net/confluence/display/IDP30/UnsolicitedSSOConfiguration
+        // Shib uses the param providerId instead of spentityid
+        $state = $this->idpInitiatedHelper(['providerId' => 'https://some-sp-entity-id']);
+        $this->assertEquals('https://some-sp-entity-id', $state['SPMetadata']['entityid']);
+
+        $this->assertStringStartsWith(
+            'http://idp.examlple.com/saml2/idp/SSOService.php?spentityid=https%3A%2F%2Fsome-sp-entity-id&cookie',
+            $state['\SimpleSAML\Auth\State.restartURL']
+        );
+        unset($state['saml:AuthnRequestReceivedAt']); // timestamp can't be tested in equality assertion
+        unset($state['SPMetadata']); // entityid asserted above
+        unset($state['\SimpleSAML\Auth\State.restartURL']); // url contains a cookie time which varies by test
+
+        $expectedState = $this->defaultExpectedAuthState;
+        $expectedState[ 'saml:ConsumerURL'] = 'https://example.com/Shibboleth.sso/SAML2/POST';
+        $expectedState[ 'saml:Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST';
+
+        $this->assertEquals($expectedState, $state);
+    }
+
+    /**
+     * Test that invoking the idp initiated endpoint using minimum shib params works
+     */
+    public function testIdPInitShibCompatOptionalParams()
+    {
+        $state = $this->idpInitiatedHelper([
+            'providerId' => 'https://some-sp-entity-id',
+            'target' => 'http://relay',
+            'shire' => 'https://example.com/Shibboleth.sso/SAML2/ECP',
+        ]);
+        $this->assertEquals('https://some-sp-entity-id', $state['SPMetadata']['entityid']);
+
+        //currently only spentityid and relay state are used in the restart url.
+        $this->assertStringStartsWith(
+            'http://idp.examlple.com/saml2/idp/SSOService.php?'
+            . 'spentityid=https%3A%2F%2Fsome-sp-entity-id&RelayState=http%3A%2F%2Frelay&cookieTime',
+            $state['\SimpleSAML\Auth\State.restartURL']
+        );
+        unset($state['saml:AuthnRequestReceivedAt']); // timestamp can't be tested in equality assertion
+        unset($state['SPMetadata']); // entityid asserted above
+        unset($state['\SimpleSAML\Auth\State.restartURL']); // url contains a cookie time which varies by test
+
+        $expectedState = $this->defaultExpectedAuthState;
+        $expectedState['saml:ConsumerURL'] = 'https://example.com/Shibboleth.sso/SAML2/ECP';
+        $expectedState['saml:Binding'] = 'urn:oasis:names:tc:SAML:2.0:bindings:PAOS';
+        $expectedState['saml:RelayState'] = 'http://relay';
+
+        $this->assertEquals($expectedState, $state);
+    }
+
+    /**
+     * Invoke IDP initiated login with the given query parameters.
+     * Callers should validate the return state array or confirm appropriate exceptions are returned.
+     *
+     * @param array $queryParams
+     * @return string[] The state array used for handling the authentication request.
+     */
+    private function idpInitiatedHelper(array $queryParams)
+    {
+        /** @var $idpStub \PHPUnit_Framework_MockObject_MockObject|IdP */
+        $idpStub = $this->getMockBuilder(IdP::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $idpMetadata = Configuration::loadFromArray([
+            'entityid' => 'https://idp-entity.id',
+            'saml20.ecp' => true, //enable additional bindings so we can test selection logic
+        ]);
+
+        $idpStub->method("getConfig")
+            ->willReturn($idpMetadata);
+
+        // phpcs:disable
+        $spMetadataXml = <<< 'EOT'
+<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://some-sp-entity-id">
+   <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol">
+      <md:AssertionConsumerService index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://example.com/Shibboleth.sso/SAML2/POST" />
+      <md:AssertionConsumerService index="2" Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="https://example.com/Shibboleth.sso/SAML2/ECP" />
+   </md:SPSSODescriptor>
+</EntityDescriptor>
+EOT;
+        // phpcs:enable
+
+        Configuration::loadFromArray([
+            'baseurlpath' => 'https://idp.example.com/',
+            'metadata.sources' => [
+                ["type" => "xml", 'xml' => $spMetadataXml],
+            ],
+        ], '', 'simplesaml');
+
+        // Since we aren't really running on a webserver some of the url calculations done, such as for restart url
+        // won't line up perfectly
+        $_REQUEST = $_REQUEST + $queryParams;
+        $_SERVER['HTTP_HOST'] = 'idp.examlple.com';
+        $_SERVER['REQUEST_URI'] = '/saml2/idp/SSOService.php?' . http_build_query($queryParams);
+
+
+        $state = [];
+        $idpStub->expects($this->once())
+            ->method('handleAuthenticationRequest')
+            ->with($this->callback(function ($arg) use (&$state) {
+                $state = $arg;
+                return true;
+            }));
+
+        SAML2::receiveAuthnRequest($idpStub);
 
-        sspmod_saml_IdP_SAML2::processSOAPAuthnRequest($state);
+        return $state;
     }
 }
diff --git a/tests/routers/configLoader.php b/tests/routers/configLoader.php
index 724cada284b9ce0452a8a7cff3c56e537fe8aa84..57baa0a42f15355805609b437fac6d18c91dd009 100644
--- a/tests/routers/configLoader.php
+++ b/tests/routers/configLoader.php
@@ -33,7 +33,7 @@ require_once(dirname(__FILE__).'/../../vendor/autoload.php');
 
 // initialize configuration
 if (isset($config)) {
-    SimpleSAML_Configuration::loadFromArray($config, '[ARRAY]', 'simplesaml');
+    \SimpleSAML\Configuration::loadFromArray($config, '[ARRAY]', 'simplesaml');
 }
 
 // let the script proceed
diff --git a/tests/www/IndexTest.php b/tests/www/IndexTest.php
index be7d060121a32b0d275f17f41a811a857e9cd9e1..7d3bcedd02f685e30e698c17b95fd03da2cd880b 100644
--- a/tests/www/IndexTest.php
+++ b/tests/www/IndexTest.php
@@ -72,12 +72,12 @@ class IndexTest extends TestCase
         }
 
         // test most basic redirection
-        $this->updateConfig(array(
+        $this->updateConfig([
                 'baseurlpath' => 'http://example.org/simplesaml/'
-        ));
-        $resp = $this->server->get('/index.php', array(), array(
+        ]);
+        $resp = $this->server->get('/index.php', [], [
             CURLOPT_FOLLOWLOCATION => 0,
-        ));
+        ]);
         $this->assertEquals('302', $resp['code']);
         $this->assertEquals(
             'http://example.org/simplesaml/module.php/core/frontpage_welcome.php',
@@ -85,12 +85,12 @@ class IndexTest extends TestCase
         );
 
         // test non-default path and https
-        $this->updateConfig(array(
+        $this->updateConfig([
             'baseurlpath' => 'https://example.org/'
-        ));
-        $resp = $this->server->get('/index.php', array(), array(
+        ]);
+        $resp = $this->server->get('/index.php', [], [
             CURLOPT_FOLLOWLOCATION => 0,
-        ));
+        ]);
         $this->assertEquals('302', $resp['code']);
         $this->assertEquals(
             'https://example.org/module.php/core/frontpage_welcome.php',
@@ -98,12 +98,12 @@ class IndexTest extends TestCase
         );
 
         // test URL guessing
-        $this->updateConfig(array(
+        $this->updateConfig([
             'baseurlpath' => '/simplesaml/'
-        ));
-        $resp = $this->server->get('/index.php', array(), array(
+        ]);
+        $resp = $this->server->get('/index.php', [], [
             CURLOPT_FOLLOWLOCATION => 0,
-        ));
+        ]);
         $this->assertEquals('302', $resp['code']);
         $this->assertEquals(
             'http://'.$this->server_addr.'/simplesaml/module.php/core/frontpage_welcome.php',
diff --git a/tests/www/TemplateTest.php b/tests/www/TemplateTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..06dfe10808c2ea612f0050eeb3c20a915fd99f72
--- /dev/null
+++ b/tests/www/TemplateTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Simple test for syntax-checking Twig-templates.
+ *
+ * @author Tim van Dijen <tvdijen@gmail.com>
+ * @package SimpleSAMLphp
+ */
+
+namespace SimpleSAML\Test\Web;
+
+use PHPUnit\Framework\TestCase;
+
+use \SimpleSAML\Configuration;
+use \SimpleSAML\XHTML\Template;
+use \SimpleSAML\Module;
+
+class TemplateTest extends TestCase
+{
+    public function testSyntax()
+    {
+        $config = Configuration::loadFromArray([
+            'language.i18n.backend' => 'gettext/gettext',
+            'module.enable' => array_fill_keys(Module::getModules(), true),
+        ]);
+        Configuration::setPreLoadedConfig($config);
+
+        $basedir = dirname(dirname(dirname(__FILE__))).DIRECTORY_SEPARATOR.'templates';
+
+        // Base templates
+        $files = array_diff(scandir($basedir), ['.', '..']);
+        foreach ($files as $file) {
+            if (preg_match('/.twig$/', $file)) {
+                $t = new Template($config, $file);
+                ob_start();
+                try {
+                    $t->show();
+                    $this->addToAssertionCount(1);
+                } catch (\Twig_Error_Syntax $e) {
+                    $this->fail($e->getMessage().' in '.$e->getFile().':'.$e->getLine());
+                }
+                ob_end_clean();
+            }
+        }
+
+        // Module templates
+        foreach (Module::getModules() as $module) {
+            $basedir = Module::getModuleDir($module).DIRECTORY_SEPARATOR.'templates';
+            if (file_exists($basedir)) {
+                $files = array_diff(scandir($basedir), ['.', '..']);
+                foreach ($files as $file) {
+                    if (preg_match('/.twig$/', $file)) {
+                        $t = new Template($config, $module.':'.$file);
+                        ob_start();
+                        try {
+                            $t->show();
+                            $this->addToAssertionCount(1);
+                        } catch (\Twig_Error_Syntax $e) {
+                            $this->fail($e->getMessage().' in '.$e->getFile().':'.$e->getLine());
+                        }
+                        ob_end_clean();
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/www/_include.php b/www/_include.php
index 7c18a2525447ec5ea88eecab9b879fc121af5822..1960627f87cb594f71cd95355bec4f4d57ca05ca 100644
--- a/www/_include.php
+++ b/www/_include.php
@@ -4,27 +4,25 @@
 require_once(dirname(dirname(__FILE__)).'/lib/_autoload.php');
 
 // enable assertion handler for all pages
-SimpleSAML_Error_Assertion::installHandler();
+\SimpleSAML\Error\Assertion::installHandler();
 
 // show error page on unhandled exceptions
 function SimpleSAML_exception_handler($exception)
 {
-    SimpleSAML\Module::callHooks('exception_handler', $exception);
+    \SimpleSAML\Module::callHooks('exception_handler', $exception);
 
-    if ($exception instanceof SimpleSAML_Error_Error) {
+    if ($exception instanceof \SimpleSAML\Error\Error) {
         $exception->show();
-    } elseif ($exception instanceof Exception) {
-        $e = new SimpleSAML_Error_Error('UNHANDLEDEXCEPTION', $exception);
+    } elseif ($exception instanceof \Exception) {
+        $e = new \SimpleSAML\Error\Error('UNHANDLEDEXCEPTION', $exception);
         $e->show();
-    } else {
-        if (class_exists('Error') && $exception instanceof Error) {
-            $code = $exception->getCode();
-            $errno = ($code > 0) ? $code : E_ERROR;
-            $errstr = $exception->getMessage();
-            $errfile = $exception->getFile();
-            $errline = $exception->getLine();
-            SimpleSAML_error_handler($errno, $errstr, $errfile, $errline);
-        }
+    } elseif (class_exists('Error') && $exception instanceof \Error) {
+        $code = $exception->getCode();
+        $errno = ($code > 0) ? $code : E_ERROR;
+        $errstr = $exception->getMessage();
+        $errfile = $exception->getFile();
+        $errline = $exception->getLine();
+        SimpleSAML_error_handler($errno, $errstr, $errfile, $errline);
     }
 }
 
@@ -33,16 +31,7 @@ set_exception_handler('SimpleSAML_exception_handler');
 // log full backtrace on errors and warnings
 function SimpleSAML_error_handler($errno, $errstr, $errfile = null, $errline = 0, $errcontext = null)
 {
-    if (!class_exists('SimpleSAML\Logger')) {
-        /* We are probably logging a deprecation-warning during parsing. Unfortunately, the autoloader is disabled at
-         * this point, so we should stop here.
-         *
-         * See PHP bug: https://bugs.php.net/bug.php?id=47987
-         */
-        return false;
-    }
-
-    if (SimpleSAML\Logger::isErrorMasked($errno)) {
+    if (\SimpleSAML\Logger::isErrorMasked($errno)) {
         // masked error
         return false;
     }
@@ -55,7 +44,8 @@ function SimpleSAML_error_handler($errno, $errstr, $errfile = null, $errline = 0
     }
 
     // show an error with a full backtrace
-    $e = new SimpleSAML_Error_Exception('Error '.$errno.' - '.$errstr);
+    $context = (is_null($errfile) ? '' : " at $errfile:$errline");
+    $e = new \SimpleSAML\Error\Exception('Error '.$errno.' - '.$errstr.$context);
     $e->logError();
 
     // resume normal error processing
@@ -65,12 +55,12 @@ function SimpleSAML_error_handler($errno, $errstr, $errfile = null, $errline = 0
 set_error_handler('SimpleSAML_error_handler');
 
 try {
-    SimpleSAML_Configuration::getInstance();
-} catch (Exception $e) {
+    \SimpleSAML\Configuration::getInstance();
+} catch (\Exception $e) {
     throw new \SimpleSAML\Error\CriticalConfigurationError(
         $e->getMessage()
     );
 }
 
 // set the timezone
-SimpleSAML\Utils\Time::initTimezone();
+\SimpleSAML\Utils\Time::initTimezone();
diff --git a/www/admin/hostnames.php b/www/admin/hostnames.php
index 90d58c3869e2dc5449c6f9b241d1d8e0fea757fd..2948ef12da122a024b8a594f76d90a9f7f91df5f 100644
--- a/www/admin/hostnames.php
+++ b/www/admin/hostnames.php
@@ -2,30 +2,30 @@
 
 require_once('../_include.php');
 
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists..
-SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
-$attributes = array();
+$attributes = [];
 
-$attributes['HTTP_HOST'] = array($_SERVER['HTTP_HOST']);
-$attributes['HTTPS'] = isset($_SERVER['HTTPS'])? array($_SERVER['HTTPS']) : array();
-$attributes['SERVER_PROTOCOL'] = array($_SERVER['SERVER_PROTOCOL']);
-$attributes['SERVER_PORT'] = array($_SERVER['SERVER_PORT']);
+$attributes['HTTP_HOST'] = [$_SERVER['HTTP_HOST']];
+$attributes['HTTPS'] = isset($_SERVER['HTTPS']) ? [$_SERVER['HTTPS']] : [];
+$attributes['SERVER_PROTOCOL'] = [$_SERVER['SERVER_PROTOCOL']];
+$attributes['SERVER_PORT'] = [$_SERVER['SERVER_PORT']];
 
-$attributes['getBaseURL()'] = array(\SimpleSAML\Utils\HTTP::getBaseURL());
-$attributes['getSelfHost()'] = array(\SimpleSAML\Utils\HTTP::getSelfHost());
-$attributes['getSelfHostWithNonStandardPort()'] = array(\SimpleSAML\Utils\HTTP::getSelfHostWithNonStandardPort());
-$attributes['selfURLhost()'] = array(\SimpleSAML\Utils\HTTP::getSelfURLHost());
-$attributes['selfURLNoQuery()'] = array(\SimpleSAML\Utils\HTTP::getSelfURLNoQuery());
-$attributes['getSelfHostWithPath()'] = array(\SimpleSAML\Utils\HTTP::getSelfHostWithPath());
-$attributes['getFirstPathElement()'] = array(\SimpleSAML\Utils\HTTP::getFirstPathElement());
-$attributes['selfURL()'] = array(\SimpleSAML\Utils\HTTP::getSelfURL());
+$attributes['getBaseURL()'] = [\SimpleSAML\Utils\HTTP::getBaseURL()];
+$attributes['getSelfHost()'] = [\SimpleSAML\Utils\HTTP::getSelfHost()];
+$attributes['getSelfHostWithNonStandardPort()'] = [\SimpleSAML\Utils\HTTP::getSelfHostWithNonStandardPort()];
+$attributes['selfURLhost()'] = [\SimpleSAML\Utils\HTTP::getSelfURLHost()];
+$attributes['selfURLNoQuery()'] = [\SimpleSAML\Utils\HTTP::getSelfURLNoQuery()];
+$attributes['getSelfHostWithPath()'] = [\SimpleSAML\Utils\HTTP::getSelfHostWithPath()];
+$attributes['getFirstPathElement()'] = [\SimpleSAML\Utils\HTTP::getFirstPathElement()];
+$attributes['selfURL()'] = [\SimpleSAML\Utils\HTTP::getSelfURL()];
 
-$template = new SimpleSAML_XHTML_Template($config, 'hostnames.php');
+$template = new \SimpleSAML\XHTML\Template($config, 'hostnames.php');
 
 $template->data['remaining']  = $session->getAuthData('admin', 'Expire') - time();
 $template->data['attributes'] = $attributes;
diff --git a/www/admin/index.php b/www/admin/index.php
index a1f9558e1446a3821ec98c9038499aaf46c4daaf..41e9c200af4a8218ad2d143ccd4dfe9f0ce14e5c 100644
--- a/www/admin/index.php
+++ b/www/admin/index.php
@@ -2,26 +2,28 @@
 
 require_once('../_include.php');
 
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists..
-//SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
-$adminpages = array(
+$adminpages = [
     'hostnames.php' => 'Diagnostics on hostname, port and protocol',
     'phpinfo.php' => 'PHP info',
     '../module.php/sanitycheck/index.php' => 'Sanity check of your SimpleSAMLphp setup',
     'sandbox.php' => 'Sandbox for testing changes to layout and css',
-);
+];
 
-$template = new SimpleSAML_XHTML_Template($config, 'index.php');
+$logouturl = \SimpleSAML\Utils\Auth::getAdminLogoutURL();
+
+$template = new \SimpleSAML\XHTML\Template($config, 'index.php');
 
 $template->data['pagetitle'] = 'Admin';
 $template->data['adminpages'] = $adminpages;
 $template->data['remaining']  = $session->getAuthData('admin', 'Expire') - time();
 $template->data['valid'] = 'na';
-$template->data['logout'] = null;
+$template->data['logouturl'] = $logouturl;
 
 $template->show();
diff --git a/www/admin/metadata-converter.php b/www/admin/metadata-converter.php
index 52313f1b769c7cf054af2a4ecae06aadc8fd16b5..5ce928ac5987d8aa3b00ea5ea716613cf7988550 100644
--- a/www/admin/metadata-converter.php
+++ b/www/admin/metadata-converter.php
@@ -1,10 +1,11 @@
 <?php
+
 require_once('../_include.php');
 
 // make sure that the user has admin access rights
-SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
 if (!empty($_FILES['xmlfile']['tmp_name'])) {
     $xmldata = trim(file_get_contents($_FILES['xmlfile']['tmp_name']));
@@ -14,26 +15,25 @@ if (!empty($_FILES['xmlfile']['tmp_name'])) {
 
 if (!empty($xmldata)) {
     \SimpleSAML\Utils\XML::checkSAMLMessage($xmldata, 'saml-meta');
-    $entities = SimpleSAML_Metadata_SAMLParser::parseDescriptorsString($xmldata);
+    $entities = \SimpleSAML\Metadata\SAMLParser::parseDescriptorsString($xmldata);
 
     // get all metadata for the entities
     foreach ($entities as &$entity) {
-        $entity = array(
+        $entity = [
             'shib13-sp-remote'  => $entity->getMetadata1xSP(),
             'shib13-idp-remote' => $entity->getMetadata1xIdP(),
             'saml20-sp-remote'  => $entity->getMetadata20SP(),
             'saml20-idp-remote' => $entity->getMetadata20IdP(),
-        );
+        ];
     }
 
     // transpose from $entities[entityid][type] to $output[type][entityid]
-    $output = SimpleSAML\Utils\Arrays::transpose($entities);
+    $output = \SimpleSAML\Utils\Arrays::transpose($entities);
 
     // merge all metadata of each type to a single string which should be added to the corresponding file
     foreach ($output as $type => &$entities) {
         $text = '';
         foreach ($entities as $entityId => $entityMetadata) {
-
             if ($entityMetadata === null) {
                 continue;
             }
@@ -48,10 +48,10 @@ if (!empty($xmldata)) {
     }
 } else {
     $xmldata = '';
-    $output = array();
+    $output = [];
 }
 
-$template = new SimpleSAML_XHTML_Template($config, 'metadata-converter.php', 'admin');
+$template = new \SimpleSAML\XHTML\Template($config, 'metadata-converter.php', 'admin');
 $template->data['clipboard.js'] = true;
 $template->data['xmldata'] = $xmldata;
 $template->data['output'] = $output;
diff --git a/www/admin/phpinfo.php b/www/admin/phpinfo.php
index 2b6b3d7cc5e0dfdfd6695c6d84a03581d13bc8ad..eb46c93772028d40e703798478d239a39fcfacfc 100644
--- a/www/admin/phpinfo.php
+++ b/www/admin/phpinfo.php
@@ -3,6 +3,6 @@
 require_once('../_include.php');
 
 // Make sure that the user has admin access rights
-SimpleSAML\Utils\Auth::requireAdmin();
+\SimpleSAML\Utils\Auth::requireAdmin();
 
 phpinfo();
diff --git a/www/admin/sandbox.php b/www/admin/sandbox.php
index ec77569cf8ebb875bfd47d361f52c815e2376ba3..d7cf29365cc7c9bb41d1953ed99a0ef8908ff61d 100644
--- a/www/admin/sandbox.php
+++ b/www/admin/sandbox.php
@@ -2,18 +2,18 @@
 
 require_once('../_include.php');
 
-// Load SimpleSAMLphp, configuration
-$config = SimpleSAML_Configuration::getInstance();
-$session = SimpleSAML_Session::getSessionFromRequest();
+// Load SimpleSAMLphp configuration
+$config = \SimpleSAML\Configuration::getInstance();
+$session = \SimpleSAML\Session::getSessionFromRequest();
 
 // Check if valid local session exists..
 //SimpleSAML\Utils\Auth::requireAdmin();
 
-$template = new SimpleSAML_XHTML_Template($config, 'sandbox.php');
+$template = new \SimpleSAML\XHTML\Template($config, 'sandbox.php');
 
 $template->data['pagetitle'] = 'Sandbox';
 $template->data['sometext'] = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.';
-$template->data['remaining']  = $session->getAuthData('admin', 'Expire') - time();
+$template->data['remaining'] = $session->getAuthData('admin', 'Expire') - time();
 $template->data['logout'] = null;
 
 $template->show();
diff --git a/www/assets/css/lib/font-awesome.min.css b/www/assets/css/lib/font-awesome.min.css
new file mode 120000
index 0000000000000000000000000000000000000000..7fcdddc6b4616020f07bb73bcc4c3074020d30d7
--- /dev/null
+++ b/www/assets/css/lib/font-awesome.min.css
@@ -0,0 +1 @@
+../../../../node_modules/font-awesome/css/font-awesome.min.css
\ No newline at end of file
diff --git a/www/assets/css/lib/font-awesome/css b/www/assets/css/lib/font-awesome/css
new file mode 120000
index 0000000000000000000000000000000000000000..a2c6afc7251a2ccc39989b7cb5cba3a290b9f378
--- /dev/null
+++ b/www/assets/css/lib/font-awesome/css
@@ -0,0 +1 @@
+../../../../../node_modules/font-awesome/css
\ No newline at end of file
diff --git a/www/assets/css/lib/font-awesome/fonts b/www/assets/css/lib/font-awesome/fonts
new file mode 120000
index 0000000000000000000000000000000000000000..ded7220c2e1ec1872a450bea59edb09f23852630
--- /dev/null
+++ b/www/assets/css/lib/font-awesome/fonts
@@ -0,0 +1 @@
+../../../../../node_modules/font-awesome/fonts
\ No newline at end of file
diff --git a/www/assets/css/lib/pure-min.css b/www/assets/css/lib/pure-min.css
new file mode 120000
index 0000000000000000000000000000000000000000..66dcb9beeaa01cc647aab64e44275ebcbf55c4ed
--- /dev/null
+++ b/www/assets/css/lib/pure-min.css
@@ -0,0 +1 @@
+../../../../node_modules/purecss/build/pure-min.css
\ No newline at end of file
diff --git a/www/assets/css/lib/selectize.default.css b/www/assets/css/lib/selectize.default.css
new file mode 120000
index 0000000000000000000000000000000000000000..4846d5ae2dcdb9f0c1165d55356a56996107187d
--- /dev/null
+++ b/www/assets/css/lib/selectize.default.css
@@ -0,0 +1 @@
+../../../../node_modules/selectize/dist/css/selectize.default.css
\ No newline at end of file
diff --git a/www/assets/css/src/default-rtl.css b/www/assets/css/src/default-rtl.css
new file mode 100644
index 0000000000000000000000000000000000000000..3df1c9ce86998b56833c14cdb020a736ab6318e0
--- /dev/null
+++ b/www/assets/css/src/default-rtl.css
@@ -0,0 +1,174 @@
+/* these styles are in the head of this page because this is a unique page */
+
+/* THE BIG GUYS */
+html {
+    direction: rtl;
+}
+#header{
+    background: linear-gradient(-141deg, #b8002c 0%, #db0100 51%, #e8410c 75%);
+}
+#footer{
+    background: linear-gradient(-141deg, #b8002c 0%, #db0100 51%, #e8410c 75%);
+}
+/* LISTS */
+ul {
+    margin: .3em 2em 1.5em 0;
+}
+
+li {
+    margin-right: 2em;
+}
+
+/* TYPOGRAPHY */
+dl dd {
+    margin-right: 3em;
+}
+
+.efieldlist {
+    border-right: 1px solid #e6e6e6;
+}
+
+div.caution {
+    padding: .2em 60px .2em .2em;
+    background-position: right;
+}
+
+th.rowtitle {
+    text-align: right;
+}
+.enablebox table {
+    margin-right: 1em;
+}
+.enablebox.mini table {
+    float: left;
+}
+.enablebox tr td {
+    padding: .5px .5em 1px 1em;
+}
+
+/* Attribute presentation in example page */
+table.attributes td.attrname {
+    text-align: left;
+}
+
+fieldset.fancyfieldset {
+    margin: 2em 0px 1em 1em;
+}
+fieldset.fancyfieldset legend {
+    margin-right: 2em;
+}
+
+
+/* Reverse Float Left <-> Right */
+.right {
+    float: left;
+}
+.left {
+    float: right;
+}
+.v-center-right{
+    right: 0;
+}
+.logo-footer-right{
+    left:0;
+    right: auto;
+}
+.message-box {
+    border-left-style: initial;
+    order-left-width: 0;
+    border-left-color: none;
+    border-right-style: solid;
+    border-right-width: 0.3125rem;
+}
+.message-box.error{
+    border-right-color: #cc4b37;
+}
+.message-box.success{
+    border-right-color: #46cc48;
+}
+.code-box-title .clipboard-btn {
+    right: auto;
+    left: 0;
+    margin-left: 4px;
+    margin-right: auto;
+}
+
+/*selectize elements*/
+div .item{
+    float: right;
+}
+.selectize-input{
+    padding-right:8px;
+}
+.selectize-input:after{
+    transform: translate(-8px, 0);
+}
+
+/*purecss elements*/
+.pure-form-aligned .pure-control-group label {
+    text-align: left;
+    margin: 0 0 0 1em;
+}
+@media only screen and (max-width : 480px) {
+    .pure-form-aligned .pure-control-group label {
+        text-align: right;
+    }
+}
+.pure-form-aligned .pure-controls {
+    margin: 1.5em 11em 0 0;
+}
+.pure-form .pure-help-inline,
+.pure-form-message-inline {
+    padding-left: 0;
+    padding-right: 0.3em;
+}
+.pure-select{
+    float: left;
+}
+.pure-table-attributes ul{
+    margin:0;
+}
+.pure-table-attributes li{
+    margin:0;
+}
+
+/* language side menu on medium and small screens*/
+#layout.active #menu {
+    right: initial;
+    left: 11em;
+}
+#layout.active .menu-link {
+    right: initial;
+    left: 11em;
+}
+#menu {
+    right: initial;
+    margin-right: 0;
+    margin-left: -11em; /* "#menu" width */
+    left: 0;
+}
+#menu a {
+    padding: 0.6em 0.6em 0.6em 0em;
+}
+
+.menu-link {
+    right: initial;
+    left: 0; /* "#menu width" */
+}
+
+/* -- Responsive Styles (Media Queries) ------------------------------------- */
+
+@media screen and (max-width: 0em), screen and (min-width: 40em) {
+    #layout.active {
+        right: auto;
+        left: 11em;
+    }
+    #menuLink.menu-link.active {
+        right: auto;
+        left: 13em;
+    }
+    #foot.active {
+        margin-right: auto;
+        margin-left: 11em;
+    }
+}
diff --git a/www/assets/css/src/default.css b/www/assets/css/src/default.css
new file mode 100644
index 0000000000000000000000000000000000000000..f1721e22eb9089b4e717a7177bfd0c38dc3d94f7
--- /dev/null
+++ b/www/assets/css/src/default.css
@@ -0,0 +1,660 @@
+/* ***********************************************************
+GENERAL
+************************************************************ */
+* {
+    margin:0;
+    padding:0;
+}
+html, body{
+    height: 100%;
+}
+body {
+    font-family: sans-serif;
+    line-height: 1.5;
+    min-height: 100%;
+}
+.wrap{
+    width: 80%;
+    max-width: 1100px;
+    margin: auto;
+    position:relative;
+}
+.left {
+    float: left;
+}
+
+.right {
+    float: right;
+}
+.center {
+    padding: auto;
+    text-align: center;
+}
+.v-center { /*specify a height to center vertically*/
+    display: table-cell;
+    vertical-align: middle;
+}
+h1{
+    margin: 0.2em 0;
+    font-size: 3em;
+    font-weight: 300;
+}
+h2{
+    margin: 50px 0 20px 0;
+    font-weight: 300;
+    color: #1c1c1c;
+}
+h3{
+    font-weight: 300;
+    color: #2e3436;
+    padding: 0;
+    margin-top: 0;
+}
+p{
+    padding: 0.5em;
+    margin-bottom: 1em;
+}
+a{
+   color: midnightblue;
+}
+a:hover{
+    color: rgba(25,25,112,0.5);
+}
+.dark-bg a{
+    color: #e2e2e2;
+}
+.dark-bg a:hover{
+    color: rgba(0,0,0,0.75);
+}
+.overflow {
+    overflow: hidden;
+}
+ul{
+    padding-left: 1.5em;
+}
+/* ***********************************************************
+BUTTONS
+************************************************************ */
+.code-box-title .clipboard-btn {
+    background-color: #f0f0f0;
+    border: 1px solid #ccc;
+    position: absolute;
+    right:0;
+    height: inherit;
+    margin-top: -2em;
+    margin-right: 4px;
+}
+.pure-button-red,
+a.pure-button-red {
+    background-color: rgb(219, 1, 0);
+    color: #fff;
+}
+
+.pure-button.hollow {
+    background-color: #FFFFFF;
+    color: #6f6f6f;
+    border: solid 1px #E6E6E6;
+}
+.pure-button.hollow:hover {
+    background-image: none;
+}
+.pure-button.hollow[disabled]{
+    cursor: auto;
+    opacity: initial;
+    pointer-events: auto;
+    -webkit-user-drag: auto;
+    -webkit-user-select: auto;
+    -moz-user-select: text;
+    -ms-user-select: text;
+    user-select: text;
+}
+.pure-button-group .pure-button:first-child,
+.pure-button-group .pure-button:last-child {
+    -webkit-border-radius: 0;
+    -moz-border-radius: 0;
+    border-radius: 0;
+}
+
+.pure-button-group.two-elements .pure-button {
+    margin: 0;
+    line-height: unset;
+    border: 1px solid #E6E6E6;
+}
+.pure-button-group.two-elements .pure-button:first-child {
+    border-right: none;
+}
+.pure-button-group.two-elements .pure-button:last-child {
+    border-right: 1px solid #E6E6E6;
+}
+.pure-button-group .pure-button.show-files{
+    max-width: 450px;
+    overflow: hidden;
+}
+
+/* ***********************************************************
+SLIDING SIDE-MENU FOR SMALL SCREENS
+************************************************************ */
+/*
+Add transition to containers so they can push in and out.
+*/
+#layout,
+#menu,
+#foot,
+.menu-link {
+    -webkit-transition: all 0.2s ease-out;
+    -moz-transition: all 0.2s ease-out;
+    -ms-transition: all 0.2s ease-out;
+    -o-transition: all 0.2s ease-out;
+    transition: all 0.2s ease-out;
+}
+
+/*
+This is the parent `<div>` that contains the menu and the content area.
+*/
+#layout.active #menu {
+    right: 11em;
+    width: 11em;
+}
+#layout.active .menu-link {
+    right: 11em;
+}
+
+/*
+The `#menu` `<div>` is the parent `<div>` that contains the `.pure-menu` that
+appears on the left side of the page.
+*/
+#menu {
+    margin-right: -11em; /* "#menu" width */
+    width: 11em;
+    position: fixed;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 1000; /* so the menu or its navicon stays above all content */
+    background: #E8410C;
+    overflow-y: auto;
+    -webkit-overflow-scrolling: touch;
+}
+
+/*
+All anchors inside the menu should be styled like this.
+*/
+#menu a {
+    color: #ffffff;
+    border: none;
+    padding: 0.6em 0em 0.6em 0.6em;
+}
+
+/*
+Remove all background/borders, since we are applying them to #menu.
+*/
+#menu .pure-menu,
+#menu .pure-menu ul {
+    border: none;
+    background: transparent;
+}
+
+/*
+Add that light border to separate items into groups.
+*/
+#menu .pure-menu ul,
+#menu .pure-menu .menu-item-divided {
+    border-top: 1px solid #db0100;
+}
+/*
+Change color of the anchor links on hover/focus.
+*/
+#menu .pure-menu li a:hover,
+#menu .pure-menu li a:focus {
+    background: #db0100;
+}
+
+/*
+This styles the selected menu item `<li>`.
+*/
+#menu .pure-menu-selected,
+#menu .pure-menu-heading {
+    background: #ffa86f;
+    color: black;
+}
+
+/*
+This styles a link within a selected menu item `<li>`.
+*/
+#menu .pure-menu-selected a {
+    color: #fff;
+}
+
+/*
+This styles the menu heading.
+*/
+#menu .pure-menu-heading {
+    font-size: 110%;
+    color: #fff;
+    margin: 0;
+}
+.frontpage-menu .pure-menu-item {
+    border-bottom: 1px solid lightgrey;
+}
+.frontpage-menu .pure-menu-selected {
+    border-bottom: 1px solid black;
+    font-weight: bold;
+}
+
+/* -- Dynamic Button For Responsive Menu -------------------------------------*/
+
+/*
+The button to open/close the Menu is custom-made and not part of Pure. Here's
+how it works:
+*/
+
+/*
+`.menu-link` represents the responsive menu toggle that shows/hides on
+small screens.
+*/
+.menu-link {
+    position: relative;
+    display: block; /* show this only on small screens */
+    top: 0;
+    right: 0; /* "#menu width" */
+    background: transparent;
+    z-index: 10;
+    height: 2rem;
+    padding-top: 2rem;
+    padding-bottom: 2rem;
+    text-decoration: none;
+}
+.menu-link span:hover,
+.menu-link span:focus {
+    color: rgba(1,1,1,0.8);
+}
+.menu-link span {
+    position: relative;
+    display: block;
+    color: #FFFFFF;
+}
+.menu-link span,
+.menu-link span:before,
+.menu-link span:after {
+    background-color: transparent;
+}
+
+/* -- Responsive Styles (Media Queries) ------------------------------------- */
+
+@media screen and (max-width: 63.9375em) {
+    #layout.active {
+        position: relative;
+        right: 11em;
+        /* moves to right as many ems as the one used by the menu */
+    }
+    #menuLink.menu-link.active {
+        position: fixed;
+        right: 13em;
+    }
+    #foot.active {
+        margin-right: 11em;
+    }
+}
+
+
+/* ***********************************************************
+HEADER
+************************************************************ */
+#header{
+    height: 6rem;
+    background-color: darkred;
+    background: linear-gradient(141deg, #b8002c 0%, #db0100 51%, #e8410c 75%)
+}
+.logo-header{
+    min-width: 8em;
+    height: 6rem;
+    max-width: 70%;
+ }
+#logo{
+    font-family: sans-serif;
+    font-size: 2.5em;
+    color: white;
+    text-shadow: 0px 3px 2px rgba(83, 41, 0, 1);
+}
+.simple{
+    font-weight: 300;
+}
+.saml{
+    font-family: Verdana;
+    letter-spacing: -0.12em;
+    font-weight: 600;
+    margin-left: -0.05em;
+}
+.language-menu{
+    font-family: FontAwesome, sans-serif;
+    min-width: 10rem;
+}
+.language-bar {
+    height: 6rem;
+}
+
+/* ***********************************************************
+CONTENT
+************************************************************ */
+#layout {
+    position: relative;
+    right: 0;
+    padding-right: 0;
+  }
+#content {
+    padding-top: 2em;
+    padding-bottom: 4rem;
+}
+
+.message-box {
+    background-color: #f4f4f4;
+    border-left-color: #444444;
+    border-left-style: solid;
+    border-left-width: 0.3125rem;
+    box-shadow: 0 5px 8px -6px rgba(0, 0, 0, 0.2);
+    margin: 1rem 0;
+    padding: 1.3rem;
+    position: relative;
+}
+.message-box.error {
+    background-color: #f7e4e1;
+    border-left-color: #cc4b37;
+}
+.message-box.success {
+    background-color: #daf7e6;
+    border-left-color: #46cc48;
+}
+
+.auth_methods{
+    margin-top: 2em;
+    width: 35%;
+}
+.code-box{
+    border:1px solid #ccc;
+    margin-bottom: 1em;
+}
+.code-box-content{
+    font-size: 1em;
+    line-height: 1.15;
+    padding: 0.5em 1em;
+}
+.code-box-title{
+    border-bottom: 1px solid #ccc;
+    background-color: #e0e0e0;
+    padding: 0.5em 0 0.5em 0.5em;
+}
+
+/* ***********************************************************
+FOOTER
+************************************************************ */
+#layout{
+    min-height: 100%;
+    height: auto !important;
+    height: 100%;
+    margin: 0 auto -6rem; /*negative margin = footer height + padding-top + padding-bottom*/
+}
+#bottom, #push {
+    height:4rem;
+}
+#footer {
+    background-color: darkred;
+    background: linear-gradient(141deg, #b8002c 0%, #db0100 51%, #e8410c 75%);
+    height: 4rem;
+    padding: 2rem 0 0;
+    text-align: center;
+}
+.copyrights {
+    height:4rem;
+    font-size: .75em;
+}
+.logo-footer-right{
+    position: absolute;
+    right: 0;
+    top: 50%;
+    transform: translate(0, -50%);
+}
+.logo-footer {
+    height: 4rem;
+}
+
+/* ***********************************************************
+FORMS
+************************************************************ */
+.text-area{
+    margin-top: .5em;
+    width:100%;
+    font-size: 0.9em;
+    line-height: 1.15;
+}
+.file-upload input[type="url"][disabled]{
+    cursor: pointer;
+    color: inherit;
+}
+input[type="file"]{
+    color:black;
+}
+.form-align{
+     position: relative;
+ }
+.center-form{
+    display: inline-block;
+    margin-right: auto;
+    margin-left: auto;
+}
+.v-center-right{
+    position: absolute;
+    left: 0;
+    top: 50%;
+    transform: translate(0, -50%);
+}
+
+/* PURE */
+.pure-button,
+.pure-form input.edge,
+.pure-form textarea.edge {
+    -webkit-border-radius: 0;
+    -moz-border-radius: 0;
+    border-radius: 0;
+ }
+.pure-form-aligned .pure-controls{
+     margin: 0 0 0 11em;
+ }
+.pure-select{
+    float: right;
+}
+
+/* SELECTIZE */
+.selectize-input,
+.selectize-dropdown,
+.selectize-input.dropdown-active{
+    -webkit-border-radius: 0;
+    -moz-border-radius: 0;
+    border-radius: 0;
+}
+.selectize-input:after{
+    transform: translate(8px, 0);
+}
+div .item{
+    float: left;
+}
+.selectize-dropdown{
+    text-align: left;
+}
+
+.selectize-control.single .selectize-input, .selectize-dropdown.single {
+    background-color: white;
+    background-image: none;
+    border: 1px solid #ccc;
+    box-shadow: inset 0 1px 3px #ddd;
+    box-sizing: border-box;
+    font-size: inherit;
+    padding: 0.5em 0.6em;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+/* ***********************************************************
+IMAGES
+************************************************************ */
+.fa {
+    font-family: FontAwesome !important;
+}
+span.fa, i.fa {
+    padding: 0 0.5em;
+}
+.message-box span.fa,
+.message-box i.fa{
+    padding: 0;
+}
+
+/* ***********************************************************
+TABLES
+************************************************************ */
+.pure-table-attributes{
+    table-layout: fixed;
+    width:100%;
+}
+.attrname{
+    text-align: right;
+}
+.attrvalue{
+    overflow-wrap: break-word;
+}
+table.attributes ul{
+    padding: inherit;
+}
+/* ***********************************************************
+MEDIA QUERIES
+************************************************************ */
+
+@media screen and (max-width: 480px) {
+    .pure-form .pure-input-sm-1-1{
+        width: 100%;
+    }
+}
+@media screen and (max-width: 39.9375em) {
+    .hide-for-small-only {
+        display: none !important;
+    }
+    .selectize-input{
+        padding-right: 0.1rem;
+    }
+    body {
+        font-size:75%;
+    }
+    .wrap{
+        width: 90%;
+    }
+    .pure-form-aligned .pure-controls{
+        margin: 0.5em 0 0;
+        float: left;
+    }
+    #layout {
+        padding-top: 0;
+    }
+    .auth_methods {
+        width: 60%;
+    }
+    #logo{
+        font-size: 1.8em;
+    }
+}
+
+@media screen and (max-width: 0em), screen and (min-width: 40em) {
+    .show-for-small-only {
+        display: none !important;
+    }
+    .input-sm-placeholder {
+        display: inline-block;
+    }
+}
+
+@media screen and (min-width: 40em) and (max-width: 63.9375em) {
+    .hide-for-medium-only {
+        display: none !important;
+    }
+    body{
+        font-size: 85%;
+    }
+}
+@media screen and (max-width: 39.9375em) {
+    .show-for-medium {
+        display: none !important;
+    }
+}
+
+@media screen and (max-width: 39.9375em), screen and (min-width: 64em) {
+    .show-for-medium-only {
+        display: none !important;
+    }
+}
+@media screen and (min-width: 64em) {
+    .hide-for-large {
+        display: none !important;
+    }
+}
+@media screen and (max-width: 63.9375em) {
+    .show-for-large {
+        display: none !important;
+    }
+}
+
+/*************************************************
+ * Specifics for modules/core/frontpage*
+ ************************************************/
+code.simplesaml_version {
+    background: #f5f5f5;
+    border: 1px dotted #bbb;
+    padding: 1em;
+    color: #555;
+}
+.float-r {
+    float: right;
+}
+.enablebox table {
+    border: 1px solid #eee;
+
+    margin-left: 1em;
+}
+.enablebox.mini table {
+    float: right;
+}
+.enablebox tr td {
+    padding: .5px 1em 1px .5em;
+    margin: 0px;
+}
+.enablebox {
+    font-size: 85%;
+}
+.enablebox tr.enabled td {
+    background: #eee;
+}
+.enablebox tr.disabled td {
+    background: #ccc;
+}
+fieldset.fancyfieldset {
+    margin: 2em 1em 1em 0px;
+    border: 1px solid #bbb;
+}
+fieldset.fancyfieldset legend {
+    margin-left: 2em;
+    padding: 3px 2em 3px 2em;
+    border: 1px solid #bbb;
+}
+dt {
+    font-weight: bold;
+}
+.frontpage-menu {
+    margin-bottom: 1em;
+}
+.entity-name, .entity-deprecated, .entity-expired {
+    font-weight: bold;
+}
+.entity-expired {
+    color: #500;
+}
+div.preferredidp {
+    border: 1px dashed #ccc;
+    background: #eee;
+    padding: 2px 2em 2px 2em;
+}
diff --git a/www/assets/js/lib/clipboard.min.js b/www/assets/js/lib/clipboard.min.js
new file mode 120000
index 0000000000000000000000000000000000000000..da3d100ca2440beb4de5b97c2aacad08517b2ecd
--- /dev/null
+++ b/www/assets/js/lib/clipboard.min.js
@@ -0,0 +1 @@
+../../../../node_modules/clipboard/dist/clipboard.min.js
\ No newline at end of file
diff --git a/www/assets/js/lib/jquery-3.3.1.min.js b/www/assets/js/lib/jquery-3.3.1.min.js
new file mode 120000
index 0000000000000000000000000000000000000000..f0c4795a02bef0864c99673fda971d240436e0b9
--- /dev/null
+++ b/www/assets/js/lib/jquery-3.3.1.min.js
@@ -0,0 +1 @@
+../../../../node_modules/jquery/dist/jquery.min.js
\ No newline at end of file
diff --git a/www/assets/js/lib/selectize.min.js b/www/assets/js/lib/selectize.min.js
new file mode 120000
index 0000000000000000000000000000000000000000..9ba5ee18b844ee0c7ed57f3098f80aed5de13f81
--- /dev/null
+++ b/www/assets/js/lib/selectize.min.js
@@ -0,0 +1 @@
+../../../../node_modules/selectize/dist/js/standalone/selectize.min.js
\ No newline at end of file
diff --git a/www/assets/js/src/language.js b/www/assets/js/src/language.js
new file mode 100644
index 0000000000000000000000000000000000000000..0f4484728bd92788c217c3cc2248827fe0a3c10a
--- /dev/null
+++ b/www/assets/js/src/language.js
@@ -0,0 +1,17 @@
+
+$(document).ready(function () {
+    // get available languages
+    var languages = $.map($('#language_selector option') ,function (option) {
+        return option.text.toLowerCase();
+    });
+
+    $('#SelectLang').on("change", function (e) {
+        if (-1 !== $.inArray(
+            $('#language_selector-selectized').prev().text().toLowerCase(),
+            languages
+        )) {
+            e.currentTarget.submit();
+        }
+    });
+
+});
diff --git a/www/assets/js/src/script.js b/www/assets/js/src/script.js
new file mode 100644
index 0000000000000000000000000000000000000000..61e710f17f404359af63b5ac95d974625169fb18
--- /dev/null
+++ b/www/assets/js/src/script.js
@@ -0,0 +1,75 @@
+/**
+ * Set focus to the element with the given id.
+ *
+ * @param id  The id of the element which should receive focus.
+ */
+function SimpleSAML_focus(id)
+{
+    element = document.getElementById(id);
+    if (element != null) {
+        element.focus();
+    }
+}
+
+
+/**
+ * Show the given DOM element.
+ *
+ * @param id  The id of the element which should be shown.
+ */
+function SimpleSAML_show(id)
+{
+    element = document.getElementById(id);
+    if (element == null) {
+        return;
+    }
+
+    element.style.display = 'block';
+}
+
+
+/**
+ * Hide the given DOM element.
+ *
+ * @param id  The id of the element which should be hidden.
+ */
+function SimpleSAML_hide(id)
+{
+    element = document.getElementById(id);
+    if (element == null) {
+        return;
+    }
+
+    element.style.display = 'none';
+}
+
+// Attach the `fileselect` event to all file inputs on the page
+$(document).on('change', ':file', function () {
+    var input = $(this),
+        numFiles = input.get(0).files ? input.get(0).files.length : 1,
+        label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
+    input.trigger('fileselect', [numFiles, label]);
+});
+
+$(document).ready(function () {
+    $('.language-menu').selectize();
+    $('#organization').selectize();
+    new ClipboardJS('.clipboard-btn');
+
+// Watch for custom `fileselect` event
+    $(':file').on('fileselect', function (event, numFiles, label) {
+
+        var input = $(this).parents('.pure-button-group').find(':text'),
+            log = numFiles > 1 ? numFiles + ' files selected' : label;
+
+        if (input.length) {
+            input.val(log);
+        } else {
+            if (log) {
+                document.getElementById('show-file').innerHTML = log;
+            }
+        }
+    });
+
+});
+
diff --git a/www/assets/js/src/side_menu.js b/www/assets/js/src/side_menu.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef81946439db1fa19384a8c8bd23ff5622ad35c2
--- /dev/null
+++ b/www/assets/js/src/side_menu.js
@@ -0,0 +1,50 @@
+(function (window, document) {
+
+    var layout   = document.getElementById('layout'),
+        menu     = document.getElementById('menu'),
+        menuLink = document.getElementById('menuLink'),
+        content  = document.getElementById('content');
+    footer  = document.getElementById('foot');
+
+    function toggleClass(element, className)
+    {
+        var classes = element.className.split(/\s+/),
+            length = classes.length,
+            i = 0;
+
+        for (; i < length; i++) {
+            if (classes[i] === className) {
+                classes.splice(i, 1);
+                break;
+            }
+        }
+        // The className is not found
+        if (length === classes.length) {
+            classes.push(className);
+        }
+
+        element.className = classes.join(' ');
+    }
+
+    function toggleAll(e)
+    {
+        var active = 'active';
+
+        e.preventDefault();
+        toggleClass(layout, active);
+        toggleClass(menu, active);
+        toggleClass(menuLink, active);
+        toggleClass(footer, active);
+    }
+
+    menuLink.onclick = function (e) {
+        toggleAll(e);
+    };
+
+    content.onclick = function (e) {
+        if (menu.className.indexOf('active') !== -1) {
+            toggleAll(e);
+        }
+    };
+
+}(this, this.document));
diff --git a/www/authmemcookie.php b/www/authmemcookie.php
index d403aee138ba21a0429f5375329f369280832666..9825c62f54bc6ed9032b981eb43ae0882f989af9 100644
--- a/www/authmemcookie.php
+++ b/www/authmemcookie.php
@@ -16,15 +16,15 @@ require_once('_include.php');
 
 try {
     // load SimpleSAMLphp configuration
-    $globalConfig = SimpleSAML_Configuration::getInstance();
+    $globalConfig = \SimpleSAML\Configuration::getInstance();
 
     // check if this module is enabled
     if (!$globalConfig->getBoolean('enable.authmemcookie', false)) {
-        throw new SimpleSAML_Error_Error('NOACCESS');
+        throw new \SimpleSAML\Error\Error('NOACCESS');
     }
 
     // load Auth MemCookie configuration
-    $amc = SimpleSAML_AuthMemCookie::getInstance();
+    $amc = \SimpleSAML\AuthMemCookie::getInstance();
 
     $sourceId = $amc->getAuthSource();
     $s = new \SimpleSAML\Auth\Simple($sourceId);
@@ -33,19 +33,19 @@ try {
     $s->requireAuth();
 
     // generate session id and save it in a cookie
-    $sessionID = SimpleSAML\Utils\Random::generateID();
+    $sessionID = \SimpleSAML\Utils\Random::generateID();
     $cookieName = $amc->getCookieName();
     \SimpleSAML\Utils\HTTP::setCookie($cookieName, $sessionID);
 
     // generate the authentication information
     $attributes = $s->getAttributes();
 
-    $authData = array();
+    $authData = [];
 
     // username
     $usernameAttr = $amc->getUsernameAttr();
     if (!array_key_exists($usernameAttr, $attributes)) {
-        throw new Exception(
+        throw new \Exception(
             "The user doesn't have an attribute named '".$usernameAttr.
             "'. This attribute is expected to contain the username."
         );
@@ -56,14 +56,14 @@ try {
     $groupsAttr = $amc->getGroupsAttr();
     if ($groupsAttr !== null) {
         if (!array_key_exists($groupsAttr, $attributes)) {
-            throw new Exception(
+            throw new \Exception(
                 "The user doesn't have an attribute named '".$groupsAttr.
                 "'. This attribute is expected to contain the groups the user is a member of."
             );
         }
         $authData['Groups'] = $attributes[$groupsAttr];
     } else {
-        $authData['Groups'] = array();
+        $authData['Groups'] = [];
     }
 
     $authData['RemoteIP'] = $_SERVER['REMOTE_ADDR'];
@@ -96,11 +96,11 @@ try {
     $memcache->set($sessionID, $data, 0, $expirationTime);
 
     // register logout handler
-    $session = SimpleSAML_Session::getSessionFromRequest();
-    $session->registerLogoutHandler($sourceId, 'SimpleSAML_AuthMemCookie', 'logoutHandler');
+    $session = \SimpleSAML\Session::getSessionFromRequest();
+    $session->registerLogoutHandler($sourceId, '\SimpleSAML\AuthMemCookie', 'logoutHandler');
 
     // redirect the user back to this page to signal that the login is completed
     \SimpleSAML\Utils\HTTP::redirectTrustedURL(\SimpleSAML\Utils\HTTP::getSelfURL());
-} catch (Exception $e) {
-    throw new SimpleSAML_Error_Error('CONFIG', $e);
+} catch (\Exception $e) {
+    throw new \SimpleSAML\Error\Error('CONFIG', $e);
 }
diff --git a/www/errorreport.php b/www/errorreport.php
index 569db419929568a20568bb20df012a1a67a6ede6..0193e4767b589133c67e27bbef489fc0f9d072b9 100644
--- a/www/errorreport.php
+++ b/www/errorreport.php
@@ -2,13 +2,13 @@
 
 require_once('_include.php');
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
 // this page will redirect to itself after processing a POST request and sending the email
 if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
     // the message has been sent. Show error report page
 
-    $t = new SimpleSAML_XHTML_Template($config, 'errorreport.php', 'errors');
+    $t = new \SimpleSAML\XHTML\Template($config, 'errorreport.php', 'errors');
     $t->show();
     exit;
 }
@@ -19,14 +19,14 @@ $text = htmlspecialchars((string) $_REQUEST['text']);
 
 $data = null;
 try {
-    $session = SimpleSAML_Session::getSessionFromRequest();
+    $session = \SimpleSAML\Session::getSessionFromRequest();
     $data = $session->getData('core:errorreport', $reportId);
-} catch (Exception $e) {
-    SimpleSAML\Logger::error('Error loading error report data: '.var_export($e->getMessage(), true));
+} catch (\Exception $e) {
+    \SimpleSAML\Logger::error('Error loading error report data: '.var_export($e->getMessage(), true));
 }
 
 if ($data === null) {
-    $data = array(
+    $data = [
         'exceptionMsg'   => 'not set',
         'exceptionTrace' => 'not set',
         'reportId'       => $reportId,
@@ -34,7 +34,7 @@ if ($data === null) {
         'url'            => 'not set',
         'version'        => $config->getVersion(),
         'referer'        => 'not set',
-    );
+    ];
 
     if (isset($session)) {
         $data['trackId'] = $session->getTrackID();
@@ -69,11 +69,11 @@ $message = <<<MESSAGE
 <p>Track ID:</p>
 <pre>%s</pre>
 
-<p>Version: <tt>%s</tt></p>
+<p>Version: <code>%s</code></p>
 
-<p>Report ID: <tt>%s</tt></p>
+<p>Report ID: <code>%s</code></p>
 
-<p>Referer: <tt>%s</tt></p>
+<p>Referer: <code>%s</code></p>
 
 <hr />
 <div class="footer">
@@ -82,7 +82,7 @@ $message = <<<MESSAGE
 MESSAGE;
 $message = sprintf(
     $message,
-    htmlspecialchars($text),
+    $text,
     $data['exceptionMsg'],
     $data['exceptionTrace'],
     $data['url'],
@@ -121,7 +121,7 @@ if ($from === 'no-reply@example.org' && $replyto !== null) {
 // send the email
 $toAddress = $config->getString('technicalcontact_email', 'na@example.org');
 if ($config->getBoolean('errorreporting', true) && $toAddress !== 'na@example.org') {
-    $email = new SimpleSAML_XHTML_EMail($toAddress, 'SimpleSAMLphp error report', $from);
+    $email = new \SimpleSAML\XHTML\EMail($toAddress, 'SimpleSAMLphp error report', $from);
     $email->setBody($message);
     $email->send();
     SimpleSAML\Logger::error('Report with id '.$reportId.' sent to <'.$toAddress.'>.');
diff --git a/www/index.php b/www/index.php
index 42344ed94eeb4331489f6ccccf579ae215cc09b0..b5b456c7a8c3828829d28652896aae3aac3a1595 100644
--- a/www/index.php
+++ b/www/index.php
@@ -2,4 +2,10 @@
 
 require_once('_include.php');
 
+$config = \SimpleSAML\Configuration::getInstance();
+
+if ($config->getBoolean('usenewui', false)) {
+    \SimpleSAML\Utils\HTTP::redirectTrustedURL(SimpleSAML\Module::getModuleURL('core/login.php'));
+}
+
 \SimpleSAML\Utils\HTTP::redirectTrustedURL(SimpleSAML\Module::getModuleURL('core/frontpage_welcome.php'));
diff --git a/www/logout.php b/www/logout.php
index b87ca89b77438a8002021d9ee9a9e0cadf5565c3..97c7d2b41b2c768512fc4703fb4837e70eb50969 100644
--- a/www/logout.php
+++ b/www/logout.php
@@ -2,7 +2,7 @@
 
 require_once('_include.php');
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 
 if (array_key_exists('link_href', $_REQUEST)) {
     $link = \SimpleSAML\Utils\HTTP::checkURLAllowed($_REQUEST['link_href']);
@@ -16,7 +16,7 @@ if (array_key_exists('link_text', $_REQUEST)) {
     $text = '{logout:default_link_text}';
 }
 
-$t = new SimpleSAML_XHTML_Template($config, 'logout.php');
+$t = new \SimpleSAML\XHTML\Template($config, 'logout.php');
 $t->data['link'] = $link;
 $t->data['text'] = $text;
 $t->show();
diff --git a/www/module.php b/www/module.php
index 8e122f78e335a4614f6d3054483d293349d7aa94..caac395fb2ae60a16b314ffcdba0f5810e36c86d 100644
--- a/www/module.php
+++ b/www/module.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * Handler for module requests.
  *
@@ -12,10 +13,10 @@
 require_once('_include.php');
 
 // index pages - file names to attempt when accessing directories
-$indexFiles = array('index.php', 'index.html', 'index.htm', 'index.txt');
+$indexFiles = ['index.php', 'index.html', 'index.htm', 'index.txt'];
 
 // MIME types - key is file extension, value is MIME type
-$mimeTypes = array(
+$mimeTypes = [
     'bmp'   => 'image/x-ms-bmp',
     'css'   => 'text/css',
     'gif'   => 'image/gif',
@@ -36,10 +37,10 @@ $mimeTypes = array(
     'txt'   => 'text/plain',
     'xht'   => 'application/xhtml+xml',
     'xhtml' => 'application/xhtml+xml',
-);
+];
 
 if (empty($_SERVER['PATH_INFO'])) {
-    throw new SimpleSAML_Error_NotFound('No PATH_INFO to module.php');
+    throw new \SimpleSAML\Error\NotFound('No PATH_INFO to module.php');
 }
 
 $url = $_SERVER['PATH_INFO'];
@@ -53,7 +54,7 @@ unset($_SERVER['PATH_INFO']);
 $modEnd = strpos($url, '/', 1);
 if ($modEnd === false) {
     // the path must always be on the form /module/
-    throw new SimpleSAML_Error_NotFound('The URL must at least contain a module name followed by a slash.');
+    throw new \SimpleSAML\Error\NotFound('The URL must at least contain a module name followed by a slash.');
 }
 
 $module = substr($url, 1, $modEnd - 1);
@@ -63,7 +64,7 @@ if ($url === false) {
 }
 
 if (!SimpleSAML\Module::isModuleEnabled($module)) {
-    throw new SimpleSAML_Error_NotFound('The module \''.$module.'\' was either not found, or wasn\'t enabled.');
+    throw new \SimpleSAML\Error\NotFound('The module \''.$module.'\' was either not found, or wasn\'t enabled.');
 }
 
 /* Make sure that the request isn't suspicious (contains references to current directory or parent directory or
@@ -71,16 +72,15 @@ if (!SimpleSAML\Module::isModuleEnabled($module)) {
  * attempts to use Windows-style paths.
  */
 if (strpos($url, '\\') !== false) {
-    throw new SimpleSAML_Error_BadRequest('Requested URL contained a backslash.');
+    throw new SimpleSAML\Error\BadRequest('Requested URL contained a backslash.');
 } elseif (strpos($url, './') !== false) {
-    throw new SimpleSAML_Error_BadRequest('Requested URL contained \'./\'.');
+    throw new \SimpleSAML\Error\BadRequest('Requested URL contained \'./\'.');
 }
 
 $moduleDir = SimpleSAML\Module::getModuleDir($module).'/www/';
 
 // check for '.php/' in the path, the presence of which indicates that another php-script should handle the request
 for ($phpPos = strpos($url, '.php/'); $phpPos !== false; $phpPos = strpos($url, '.php/', $phpPos + 1)) {
-
     $newURL = substr($url, 0, $phpPos + 4);
     $param = substr($url, $phpPos + 4);
 
@@ -110,13 +110,13 @@ if (is_dir($path)) {
     /* Path is a directory - maybe no index file was found in the previous step, or maybe the path didn't end with
      * a slash. Either way, we don't do directory listings.
      */
-    throw new SimpleSAML_Error_NotFound('Directory listing not available.');
+    throw new \SimpleSAML\Error\NotFound('Directory listing not available.');
 }
 
 if (!file_exists($path)) {
     // file not found
     SimpleSAML\Logger::info('Could not find file \''.$path.'\'.');
-    throw new SimpleSAML_Error_NotFound('The URL wasn\'t found in the module.');
+    throw new \SimpleSAML\Error\NotFound('The URL wasn\'t found in the module.');
 }
 
 if (preg_match('#\.php$#D', $path)) {
diff --git a/www/resources/default-rtl.css b/www/resources/default-rtl.css
index 0113f82f1059079f5ec98d560e8843968ed850b4..df092c3d2ba09a3e277878d5d607357cb38936f2 100644
--- a/www/resources/default-rtl.css
+++ b/www/resources/default-rtl.css
@@ -2,69 +2,69 @@
 
 /* THE BIG GUYS */
 html {
-	direction: rtl;
+    direction: rtl;
 }
 
 /* LISTS */
 ul {
-	margin: .3em 2em 1.5em 0;
+    margin: .3em 2em 1.5em 0;
 }
 
 li {
-	margin-right: 2em;
+    margin-right: 2em;
 }
 
 #wrap {
-	text-align: right;
+    text-align: right;
 }
 
 /* TYPOGRAPHY */
 dl dd {
-	margin-right: 3em;
+    margin-right: 3em;
 }
 
 .efieldlist {
-	border-right: 1px solid #e6e6e6;
+    border-right: 1px solid #e6e6e6;
 }
 
 div.caution {
-	padding: .2em 60px .2em .2em;
-	background-position: right;
+    padding: .2em 60px .2em .2em;
+    background-position: right;
 }
 
 th.rowtitle {
-        text-align: right;
+    text-align: right;
 }
 .enablebox table {
-	margin-right: 1em;
+    margin-right: 1em;
 }
 .enablebox.mini table {
-	float: left;
+    float: left;
 }
 .enablebox tr td {
-	padding: .5px .5em 1px 1em;
+    padding: .5px .5em 1px 1em;
 }
 
 /* Attribute presentation in example page */
 table.attributes td.attrname {
-	text-align: left;
+    text-align: left;
 }
 
 fieldset.fancyfieldset {
-	margin: 2em 0px 1em 1em;
+    margin: 2em 0px 1em 1em;
 }
 fieldset.fancyfieldset legend {
-	margin-right: 2em;
+    margin-right: 2em;
 }
 
-.ui-tabs .ui-tabs-nav li { 
-	float: right; 
+.ui-tabs .ui-tabs-nav li {
+    float: right;
 }
 
 /* Reverse Float Left <-> Right */
 .float-r {
-	float: left;
+    float: left;
 }
 .float-l {
-	float: right;
+    float: right;
 }
diff --git a/www/resources/default.css b/www/resources/default.css
index 3c0371bb5cffa5add05af9b70e4fa132be57d426..f033b771621ec1542e5ce77240e5adf123545e84 100644
--- a/www/resources/default.css
+++ b/www/resources/default.css
@@ -2,474 +2,467 @@
 
 /* THE BIG GUYS */
 * {
-	margin: 0;
-	padding: 0;
+    margin: 0;
+    padding: 0;
 }
 
 body {
-	text-align: center;
-	padding: 10px 0;
-	background: #1c1c1c;
-/*	background-image: url(icons/ssplogo-fish.png);
-	background-repeat: no-repeat; */
-	color: #333;
-	font: 83%/1.5 arial,tahoma,verdana,sans-serif;
+    text-align: center;
+    padding: 10px 0;
+    background: #1c1c1c;
+/*    background-image: url(icons/ssplogo-fish.png); */
+/*    background-repeat: no-repeat; */
+    color: #333;
+    font: 83%/1.5 arial,tahoma,verdana,sans-serif;
 }
 
 .body-embed {
-	padding: 0;
-	background: #ffffff;
-	font: 83%/1.5 arial,tahoma,verdana,sans-serif;
+    padding: 0;
+    background: #ffffff;
+    font: 83%/1.5 arial,tahoma,verdana,sans-serif;
 }
 
 img {
-	border: none;
-	display: block;
+    border: none;
+    display: block;
 }
 
 hr {
-	margin: 1em 0;
-	background: #eee;
-	height: 1px;
-	color: #eee;
-	border: none;
-	clear: both;
+    margin: 1em 0;
+    background: #eee;
+    height: 1px;
+    color: #eee;
+    border: none;
+    clear: both;
 }
 
 /* LINKS */
 a, a:link, a:link, a:link, a:hover {
-
-	text-decoration: none;
-	color: #777;
-	border-bottom: 1px dotted #ccc;
-	font-weight: normal;
+    text-decoration: none;
+    color: #777;
+    border-bottom: 1px dotted #ccc;
+    font-weight: normal;
 }
 
-
 a:link, a:visited {
-	text-decoration: none;
-	color: #777;
-	border-bottom: 1px dotted #ccc;
-	font-weight: normal;
+    text-decoration: none;
+    color: #777;
+    border-bottom: 1px dotted #ccc;
+    font-weight: normal;
 }
 .ui-tabs-nav a {
-	border: none ! important;
-	text-decoration: none;
+    border: none ! important;
+    text-decoration: none;
 }
 a:visited {
-	color: #999;
+    color: #999;
 }
 
 a:hover, a:active {
-	color: #069;
-	text-decoration: none;
-	color: #333;
-	border-bottom: 1px solid #333;
+    color: #069;
+    text-decoration: none;
+    color: #333;
+    border-bottom: 1px solid #333;
 }
 
 #header a {
-	color: #fff;
-	text-decoration: none;
+    color: #fff;
+    text-decoration: none;
 }
 
 /* LISTS */
 ul {
-	margin: .3em 0 1.5em 2em;
+    margin: .3em 0 1.5em 2em;
 }
 
 ul.related {
-	margin-top: -1em;
+    margin-top: -1em;
 }
 
 li {
-	margin-left: 2em;
+    margin-left: 2em;
 }
 
 dt {
-	font-weight: bold;
+    font-weight: bold;
 }
 
 #wrap {
-	background: #fff;
+    background: #fff;
 
-	border: 1px solid #fff;
-	position: relative;
-	text-align: left;
+    border: 1px solid #fff;
+    position: relative;
+    text-align: left;
 
-	margin: 20px 75px 2em 75px;
-	max-width: 950px;
+    margin: 20px 75px 2em 75px;
+    max-width: 950px;
 }
 
 #languagebar {
-	padding-left: 10px;
-	padding-right: 10px;
+    padding-left: 10px;
+    padding-right: 10px;
 }
 #languagebar a:link, #languagebar a:visited {
-	text-decoration: none;
-	color: #777;
-	border-bottom: 1px dotted #ccc;
-	font-weight: normal;
+    text-decoration: none;
+    color: #777;
+    border-bottom: 1px dotted #ccc;
+    font-weight: normal;
 }
 #languagebar a:hover {
-	text-decoration: none;
-	color: #333;
-	border-bottom: 1px solid #333;
-
+    text-decoration: none;
+    color: #333;
+    border-bottom: 1px solid #333;
 }
 
 #header {
-	background: #666 url("header-bkg.png") repeat-x 0 100%;
-	margin: 0px;
-	padding: 0 0 8px;
+    background: #666 url("header-bkg.png") repeat-x 0 100%;
+    margin: 0px;
+    padding: 0 0 8px;
 }
 
 #header h1 {
-	color: #fff;
-	font-size: 145%;
-	padding: 20px 20px 12px;
+    color: #fff;
+    font-size: 145%;
+    padding: 20px 20px 12px;
 }
 
-
 #content, #footer {
-	padding: 0 20px;
+    padding: 0 20px;
 }
 
 /* TYPOGRAPHY */
 p, ul, ol {
-	margin: 0 0 1.5em;
+    margin: 0 0 1.5em;
 }
 
 h1, h2, h3, h4, h5, h6 {
-	letter-spacing: -1px;
-	font-family: arial,verdana,sans-serif;
-	margin: 1.2em 0 .3em;
-	color: #000;
-	border-bottom: 1px solid #eee;
-	padding-bottom: .1em;
+    letter-spacing: -1px;
+    font-family: arial,verdana,sans-serif;
+    margin: 1.2em 0 .3em;
+    color: #000;
+    border-bottom: 1px solid #eee;
+    padding-bottom: .1em;
 }
 
 h1 {
-	font-size: 196%;
-	margin-top: 0;
-	border: none;
+    font-size: 196%;
+    margin-top: 0;
+    border: none;
 }
 
 h2 {
-	font-size: 136%;
+    font-size: 136%;
 }
 
 h3 {
-	font-size: 126%;
+    font-size: 126%;
 }
 
 h4 {
-	font-size: 116%;
-	font-weight: bold;
+    font-size: 116%;
+    font-weight: bold;
 }
 
 h5 {
-	font-size: 106%;
+    font-size: 106%;
 }
 
 h6 {
-	font-size: 96%;
+    font-size: 96%;
 }
 
 input {
-	border: 1px solid #ddd;
-	border-radius: 3px;
-	padding: 5px;
-	line-height: 1.5em;
+    border: 1px solid #ddd;
+    border-radius: 3px;
+    padding: 5px;
+    line-height: 1.5em;
 }
 
 h1 a {
-	text-decoration: none;
-	border: none ! important;
-	color: white;
+    text-decoration: none;
+    border: none ! important;
+    color: white;
 }
 
 h1 a:hover {
-	border-bottom: 1px dotted #eee;
+    border-bottom: 1px dotted #eee;
 }
 
 #content {
-	margin-top: 2em;
+    margin-top: 2em;
 }
 
 .old {
-	text-decoration: line-through;
+    text-decoration: line-through;
 }
 
 dl dt {
-	color: #333;
+    color: #333;
 }
 
 dl dd {
-	color: #666;
-	margin-left: 3em;
-/*	font-family: monospace; */
+    color: #666;
+    margin-left: 3em;
+/*    font-family: monospace; */
 }
 
 .efieldlist {
-	padding: .4em;
-	margin: .8em;
-	border-top: 1px solid #e6e6e6;
-	border-left: 1px solid #e6e6e6;
+    padding: .4em;
+    margin: .8em;
+    border-top: 1px solid #e6e6e6;
+    border-left: 1px solid #e6e6e6;
 }
 
 .efieldlist.warning {
-	background-color: #922;
-	border: 1px solid #333;
-	color: white;
+    background-color: #922;
+    border: 1px solid #333;
+    color: white;
 }
 
 .efieldlist.warning h5 {
-	color: white;
+    color: white;
 }
 
 .efieldlist h5 {
-	font-weight: bold;
-	color: #200;
-	margin: .3em;
+    font-weight: bold;
+    color: #200;
+    margin: .3em;
 }
 
 .trackidtext {
-	border: 1px dashed #aaa;
-	background: #eaeaea;
-	padding: .6em;
-	margin: .4em;
+    border: 1px dashed #aaa;
+    background: #eaeaea;
+    padding: .6em;
+    margin: .4em;
 }
 
 .trackidtext .trackid {
-	border: 1px solid #ccc;
-	background: #eee;
-	margin: .4em;
-	padding: .4em;
-	font-family: monospace;
-	font-size: large;
+    border: 1px solid #ccc;
+    background: #eee;
+    margin: .4em;
+    padding: .4em;
+    font-family: monospace;
+    font-size: large;
 }
 
 div.caution {
-	background-color:  #FF9;
-	background-image: url('icons/experience/gtk-dialog-warning.48x48.png');
-	background-repeat: no-repeat;
-	border: thin solid #444;
-	padding: .2em .2em .2em 60px;
-	margin: 1em 0px 1em 0px;
+    background-color:  #FF9;
+    background-image: url('icons/experience/gtk-dialog-warning.48x48.png');
+    background-repeat: no-repeat;
+    border: thin solid #444;
+    padding: .2em .2em .2em 60px;
+    margin: 1em 0px 1em 0px;
 }
 
 th.rowtitle {
-        text-align: left;
+    text-align: left;
 }
 .enablebox table {
-	border: 1px solid #eee;
-
-	margin-left: 1em;
+    border: 1px solid #eee;
+    margin-left: 1em;
 }
 .enablebox.mini table {
-	float: right;
+    float: right;
 }
 .enablebox tr td {
-	padding: .5px 1em 1px .5em;
-	margin: 0px;
+    padding: .5px 1em 1px .5em;
+    margin: 0px;
 }
 .enablebox {
-	font-size: 85%;
+    font-size: 85%;
 }
 .enablebox tr.enabled td {
-	background: #eee;
+    background: #eee;
 }
 .enablebox tr.disabled td {
-	background: #ccc;
+    background: #ccc;
 }
 
 .metadatabox {
-	overflow: scroll;
-	border: 1px solid #eee;
-	padding: 0.5em;
-	border-radius: 3px;
+    overflow: scroll;
+    border: 1px solid #eee;
+    padding: 0.5em;
+    border-radius: 3px;
 }
 div.preferredidp {
-	border: 1px dashed #ccc;
-	background: #eee;
-	padding: 2px 2em 2px 2em;
+    border: 1px dashed #ccc;
+    background: #eee;
+    padding: 2px 2em 2px 2em;
 }
 
 table.modules {
-	border-collapse: collapse;
+    border-collapse: collapse;
 }
 table.modules tr td {
-	border-bottom: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
 }
 table.modules tr.even td {
-	background: #f0f0f0;
+    background: #f0f0f0;
 }
 
 /* Attribute presentation in example page */
 table.attributes {
-	width: 100%;
-	margin: 0px;
-	border: 1px solid #bbb;
-	border-collapse: collapse;
+    width: 100%;
+    margin: 0px;
+    border: 1px solid #bbb;
+    border-collapse: collapse;
 }
 
 table.attributes td.attrname {
-	text-align: right;
+    text-align: right;
 }
 
 table.attributes tr.even td {
-	background: #eee;
+    background: #eee;
 }
 
 table.attributes tr td {
-	border-bottom: 1px solid #bbb;
-	border-left: 0px;
-	border-right: 0px;
-	background: #fff;
-	padding-top: 5px;
-	padding-left: 1em;
-	padding-right: 1em;
-
-	vertical-align: top;
+    border-bottom: 1px solid #bbb;
+    border-left: 0px;
+    border-right: 0px;
+    background: #fff;
+    padding-top: 5px;
+    padding-left: 1em;
+    padding-right: 1em;
+    vertical-align: top;
 }
 
 .attrvalue {
-	word-break: break-all;
-	word-wrap: break-word;
+    word-break: break-all;
+    word-wrap: break-word;
 }
 
 table#table_with_attributes tr:last-child td {
-	border-bottom: none;
+    border-bottom: none;
 }
 
 fieldset.fancyfieldset {
-	margin: 2em 1em 1em 0px;
-	border: 1px solid #bbb;
+    margin: 2em 1em 1em 0px;
+    border: 1px solid #bbb;
 }
 fieldset.fancyfieldset legend {
-	margin-left: 2em;
-	padding: 3px 2em 3px 2em;
-	border: 1px solid #bbb;
+    margin-left: 2em;
+    padding: 3px 2em 3px 2em;
+    border: 1px solid #bbb;
 }
 
 div#confirmation input {
-	margin-top: .5em;
-	margin-bottom: .5em;
+    margin-top: .5em;
+    margin-bottom: .5em;
 }
 div#confirmation {
-	border: 1px solid #aaa;
-	background: #eee;
-	padding: .6em 1em .1em 1em;
+    border: 1px solid #aaa;
+    background: #eee;
+    padding: .6em 1em .1em 1em;
 }
 
 caption {
-	display: none;
+    display: none;
 }
 
 /* Left-to-Right CSS for RTL (Right to Left Support) */
 .float-r {
-	float: right;
+    float: right;
 }
 .float-l {
-	float: left;
+    float: left;
 }
 
 #mobile_remember_username, #mobile_remember_me {
-	display: none;
+    display: none;
 }
 
 @media handheld, only screen and (max-width: 480px), only screen and (max-device-width: 480px) {
-	#header, #languagebar, #footer, .erroricon, .loginicon, .logintext,
-	#regular_remember_username, #regular_remember_me {
-		display: none;
-	}
-	body {
-		font-size: 20px;
-	}
-	#wrap {
-		margin: 0;
-	}
-	h1,h2,h3,h4 {
-		font-size: 110%;
-	}
-
-	#content {
-		margin-bottom: 10px;
-		padding: 0;
-		padding-left: 5px;
-	}
-	input[type="text"], input[type="password"] {
-		height: 1.5em;
-		font-size: 1em;
-	}
-	.youareadmin {
-		font-size: 50%;
-	}
-	#mobilesubmit, #mobile_remember_username, #mobile_remember_me {
-		display: table-row;
-	}
+    #header, #languagebar, #footer, .erroricon, .loginicon, .logintext,
+    #regular_remember_username, #regular_remember_me {
+        display: none;
+    }
+    body {
+        font-size: 20px;
+    }
+    #wrap {
+        margin: 0;
+    }
+    h1,h2,h3,h4 {
+        font-size: 110%;
+    }
+
+    #content {
+        margin-bottom: 10px;
+        padding: 0;
+        padding-left: 5px;
+    }
+    input[type="text"], input[type="password"] {
+        height: 1.5em;
+        font-size: 1em;
+    }
+    .youareadmin {
+        font-size: 50%;
+    }
+    #mobilesubmit, #mobile_remember_username, #mobile_remember_me {
+        display: table-row;
+    }
 }
 
 .btn, .btnaddonright {
-	color: #000000;
-	border: 1px solid #eee;
-	border-radius: 3px;
-	background-color: #eee;
-	background-image: linear-gradient(#fcfcfc, #eee);
-	text-align: center;
-	padding: 5px;
-	cursor: hand;
+    color: #000000;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    background-color: #eee;
+    background-image: linear-gradient(#fcfcfc, #eee);
+    text-align: center;
+    padding: 5px;
+    cursor: hand;
 }
 
 .btn:hover, .btnaddonright:hover {
-	border-color: #ccc;
-	background-color: #ddd;
-	background-image: linear-gradient(#eee, #ddd);
-
+    border-color: #ccc;
+    background-color: #ddd;
+    background-image: linear-gradient(#eee, #ddd);
 }
 
 .btn img,
 .btnaddonright img {
-	max-height: 15px;
-	max-width: 15px;
+    max-height: 15px;
+    max-width: 15px;
 }
 
 .topright {
-	position: absolute;
-	right: 2em;
+    position: absolute;
+    right: 2em;
 }
 
 .input-group {
-	display: table;
+    display: table;
 }
 
 .input-group pre {
-	background: white;
-	position: relative;
-	width: 100%;
-	vertical-align: middle;
-	border: 1px solid #eee;
-	padding: 0.5em;
-	display: table-cell;
+    background: white;
+    position: relative;
+    width: 100%;
+    vertical-align: middle;
+    border: 1px solid #eee;
+    padding: 0.5em;
+    display: table-cell;
 }
 
 .input-group .btnaddonright {
-	position: relative;
-	display: inline-block;
-	border-bottom-left-radius: 0;
-	border-bottom-right-radius: 3px;
-	border-top-left-radius: 0;
-	border-top-right-radius: 3px;
-	border-left: none;
+    position: relative;
+    display: inline-block;
+    border-bottom-left-radius: 0;
+    border-bottom-right-radius: 3px;
+    border-top-left-radius: 0;
+    border-top-right-radius: 3px;
+    border-left: none;
 }
 
 .input-group .btnaddonright:hover {
-	border-left: 1px solid #ccc;
+    border-left: 1px solid #ccc;
 }
 
 .input-group .input-left {
-	border-bottom-left-radius: 3px;
-	border-bottom-right-radius: 0;
-	border-top-left-radius: 3px;
-	border-top-right-radius: 0;
+    border-bottom-left-radius: 3px;
+    border-bottom-right-radius: 0;
+    border-top-left-radius: 3px;
+    border-top-right-radius: 0;
 }
diff --git a/www/resources/post.js b/www/resources/post.js
index f551736512e1afdcdb94a81ed0c92783d130ec38..043bec73322079eb6d6e8bfd9f39bbb3b654615f 100644
--- a/www/resources/post.js
+++ b/www/resources/post.js
@@ -2,6 +2,6 @@
  * Automatically click the input button to redirect the user to
  * the SSO
  */
-window.onload = function(){
+window.onload = function () {
     document.getElementById('postLoginSubmitButton').click();
-};
\ No newline at end of file
+};
diff --git a/www/resources/script.js b/www/resources/script.js
index 3adf1b1f88e7573cc37c8dad40769a5e5fac264b..a195c24cb8fa8a1180dbec33e05796be5490af42 100644
--- a/www/resources/script.js
+++ b/www/resources/script.js
@@ -3,11 +3,12 @@
  *
  * @param id  The id of the element which should receive focus.
  */
-function SimpleSAML_focus(id) {
-  element = document.getElementById(id);
-  if(element != null) {
-    element.focus();
-  }
+function SimpleSAML_focus(id)
+{
+    element = document.getElementById(id);
+    if (element != null) {
+        element.focus();
+    }
 }
 
 
@@ -16,13 +17,14 @@ function SimpleSAML_focus(id) {
  *
  * @param id  The id of the element which should be shown.
  */
-function SimpleSAML_show(id) {
-  element = document.getElementById(id);
-  if (element == null) {
-    return;
-  }
+function SimpleSAML_show(id)
+{
+    element = document.getElementById(id);
+    if (element == null) {
+        return;
+    }
 
-  element.style.display = 'block';
+    element.style.display = 'block';
 }
 
 
@@ -31,11 +33,12 @@ function SimpleSAML_show(id) {
  *
  * @param id  The id of the element which should be hidden.
  */
-function SimpleSAML_hide(id) {
-  element = document.getElementById(id);
-  if (element == null) {
-    return;
-  }
+function SimpleSAML_hide(id)
+{
+    element = document.getElementById(id);
+    if (element == null) {
+        return;
+    }
 
-  element.style.display = 'none';
+    element.style.display = 'none';
 }
diff --git a/www/resources/slo.css b/www/resources/slo.css
index f1ac2fd4daa4278f68565efafe3b9e1190703d26..13946bcbaa5fb1175d41cfd65d315194b0c22294 100644
--- a/www/resources/slo.css
+++ b/www/resources/slo.css
@@ -1,19 +1,18 @@
 table#slostatustable {
-/*	width: 100%; */
-	border-collapse: collapse;
-	margin-bottom: 1em;
+/*  width: 100%; */
+    border-collapse: collapse;
+    margin-bottom: 1em;
 }
 table#slostatustable tr td {
-/*	border-top: 1px solid #ccc; */
-	padding-left: 4px;
-	padding-right: 4px;
+/*  border-top: 1px solid #ccc; */
+    padding-left: 4px;
+    padding-right: 4px;
 }
 table#slostatustable tr td.statustext {
-	min-width: 5em;
-	padding-left: 0px;
+    min-width: 5em;
+    padding-left: 0px;
 }
 
-
 table#slostatustable tr td.statustext span { display: none; }
 table#slostatustable tr.completed td.statustext span.completed { display: inline; }
 table#slostatustable tr.onhold td.statustext span.onhold { display: inline; }
@@ -21,66 +20,62 @@ table#slostatustable tr.inprogress td.statustext span.inprogress { display: inli
 table#slostatustable tr.failed td.statustext span.failed { display: inline; }
 
 table#slostatustable tr td.icons img {
-/*	margin: 3px; */
-	display: none;
+/*  margin: 3px; */
+    display: none;
 }
 table#slostatustable tr.completed td.icons img.completed { display: inline; }
 table#slostatustable tr.onhold td.icons img.onhold { display: inline; }
 table#slostatustable tr.inprogress td.icons img.inprogress { display: inline; }
 table#slostatustable tr.failed td.icons img.failed { display: inline; }
 
-
 iframe.hiddeniframe {
-	display: none;
+    display: none;
 }
 
 /* From old CSS
 
-
-
 div.allcompleted#interrupt {
-	display: none;
+    display: none;
 }
 div#interrupt a:link {
-	color: #036;
-	border-bottom: 1px dotted #036;
-	text-decoration: none;
+    color: #036;
+    border-bottom: 1px dotted #036;
+    text-decoration: none;
 }
 div#interrupt a:hover {
-	border-bottom: 1px solid #036;
+    border-bottom: 1px solid #036;
 }
 div#interrupt {
-	display: block;
-	border: 3px solid #036;
-	background: #39F;
-	padding: 1em;	
-	margin: .2em;
+    display: block;
+    border: 3px solid #036;
+    background: #39F;
+    padding: 1em;
+    margin: .2em;
 }
 div#iscompleted {
-	display: none;
-	border: 3px solid #993;
-	background: #FF9;
-	padding: 1em;
-	margin: .2em;
+    display: none;
+    border: 3px solid #993;
+    background: #FF9;
+    padding: 1em;
+    margin: .2em;
 }
 div.allcompleted#iscompleted {
-	display: block ! important;
+    display: block ! important;
 }
 div.inprogress, div.loggedout {
-
-	background: #eee; 
-	color: #444; 
-	padding: .2em 1em;
-	margin: .2em;
+    background: #eee;
+    color: #444;
+    padding: .2em 1em;
+    margin: .2em;
 }
 div.inprogress {
-	border: 1px dotted #888; 
+    border: 1px dotted #888;
 }
 div.loggedout {
-	border: 1px solid #888; 
-	background: #9f9 ! important ;
+    border: 1px solid #888;
+    background: #9f9 ! important;
 }
 iframe.hiddeniframe {
-	display: none;
+    display: none;
 }
- */
+*/
diff --git a/www/saml2/idp/ArtifactResolutionService.php b/www/saml2/idp/ArtifactResolutionService.php
index 39f705e657f8b01d3f54dc5768460655ddea78c0..16a99dc62e1285bb179ff4d8cd46ba8c44c26410 100644
--- a/www/saml2/idp/ArtifactResolutionService.php
+++ b/www/saml2/idp/ArtifactResolutionService.php
@@ -10,17 +10,17 @@
 
 require_once('../../_include.php');
 
-$config = SimpleSAML_Configuration::getInstance();
+$config = \SimpleSAML\Configuration::getInstance();
 if (!$config->getBoolean('enable.saml20-idp', false)) {
-    throw new SimpleSAML_Error_Error('NOACCESS');
+    throw new \SimpleSAML\Error\Error('NOACCESS');
 }
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
 $idpMetadata = $metadata->getMetaDataConfig($idpEntityId, 'saml20-idp-hosted');
 
 if (!$idpMetadata->getBoolean('saml20.sendartifact', false)) {
-    throw new SimpleSAML_Error_Error('NOACCESS');
+    throw new \SimpleSAML\Error\Error('NOACCESS');
 }
 
 $store = \SimpleSAML\Store::getInstance();
@@ -31,12 +31,13 @@ if ($store === false) {
 $binding = new \SAML2\SOAP();
 try {
     $request = $binding->receive();
-} catch (Exception $e) { // TODO: look for a specific exception
+} catch (Exception $e) {
+    // TODO: look for a specific exception
     // This is dirty. Instead of checking the message of the exception, \SAML2\Binding::getCurrentBinding() should throw
     // an specific exception when the binding is unknown, and we should capture that here. Also note that the exception
     // message here is bogus!
     if ($e->getMessage() === 'Invalid message received to AssertionConsumerService endpoint.') {
-        throw new SimpleSAML_Error_Error('ARSPARAMS', $e, 400);
+        throw new \SimpleSAML\Error\Error('ARSPARAMS', $e, 400);
     } else {
         throw $e; // do not ignore other exceptions!
     }
@@ -46,7 +47,7 @@ if (!($request instanceof \SAML2\ArtifactResolve)) {
 }
 
 $issuer = $request->getIssuer();
-$spMetadata = $metadata->getMetadataConfig($issuer, 'saml20-sp-remote');
+$spMetadata = $metadata->getMetaDataConfig($issuer, 'saml20-sp-remote');
 
 $artifact = $request->getArtifact();
 
@@ -64,5 +65,5 @@ $artifactResponse = new \SAML2\ArtifactResponse();
 $artifactResponse->setIssuer($idpEntityId);
 $artifactResponse->setInResponseTo($request->getId());
 $artifactResponse->setAny($responseXML);
-sspmod_saml_Message::addSign($idpMetadata, $spMetadata, $artifactResponse);
+\SimpleSAML\Module\saml\Message::addSign($idpMetadata, $spMetadata, $artifactResponse);
 $binding->send($artifactResponse);
diff --git a/www/saml2/idp/SSOService.php b/www/saml2/idp/SSOService.php
index f05e34c9c3c7adfbaa60a99c376585acbce6b3b9..c3e4916849996f768a08d8931b4fcf42235b9d81 100644
--- a/www/saml2/idp/SSOService.php
+++ b/www/saml2/idp/SSOService.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * The SSOService is part of the SAML 2.0 IdP code, and it receives incoming Authentication Requests
  * from a SAML 2.0 SP, parses, and process it, and then authenticates the user and sends the user back
@@ -10,16 +11,17 @@
 
 require_once('../../_include.php');
 
-SimpleSAML\Logger::info('SAML2.0 - IdP.SSOService: Accessing SAML 2.0 IdP endpoint SSOService');
+\SimpleSAML\Logger::info('SAML2.0 - IdP.SSOService: Accessing SAML 2.0 IdP endpoint SSOService');
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
-$idp = SimpleSAML_IdP::getById('saml2:' . $idpEntityId);
+$idp = \SimpleSAML\IdP::getById('saml2:'.$idpEntityId);
+
 try {
-    sspmod_saml_IdP_SAML2::receiveAuthnRequest($idp);
-} catch (Exception $e) {
+    \SimpleSAML\Module\saml\IdP\SAML2::receiveAuthnRequest($idp);
+} catch (\Exception $e) {
     if ($e->getMessage() === "Unable to find the current binding.") {
-        throw new SimpleSAML_Error_Error('SSOPARAMS', $e, 400);
+        throw new \SimpleSAML\Error\Error('SSOPARAMS', $e, 400);
     } else {
         throw $e; // do not ignore other exceptions!
     }
diff --git a/www/saml2/idp/SingleLogoutService.php b/www/saml2/idp/SingleLogoutService.php
index ab2a280229b7888ed79ca735e7dd71585331d360..6e6e9a5f851a682cf3cb134ba4cf074a88a0dc44 100644
--- a/www/saml2/idp/SingleLogoutService.php
+++ b/www/saml2/idp/SingleLogoutService.php
@@ -10,27 +10,28 @@
 
 require_once('../../_include.php');
 
-SimpleSAML\Logger::info('SAML2.0 - IdP.SingleLogoutService: Accessing SAML 2.0 IdP endpoint SingleLogoutService');
+\SimpleSAML\Logger::info('SAML2.0 - IdP.SingleLogoutService: Accessing SAML 2.0 IdP endpoint SingleLogoutService');
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
-$idp = SimpleSAML_IdP::getById('saml2:'.$idpEntityId);
+$idp = \SimpleSAML\IdP::getById('saml2:'.$idpEntityId);
 
 if (isset($_REQUEST['ReturnTo'])) {
     $idp->doLogoutRedirect(\SimpleSAML\Utils\HTTP::checkURLAllowed((string) $_REQUEST['ReturnTo']));
 } else {
     try {
-        sspmod_saml_IdP_SAML2::receiveLogoutMessage($idp);
-    } catch (Exception $e) { // TODO: look for a specific exception
+        \SimpleSAML\Module\saml\IdP\SAML2::receiveLogoutMessage($idp);
+    } catch (\Exception $e) {
+        // TODO: look for a specific exception
         /*
          * This is dirty. Instead of checking the message of the exception, \SAML2\Binding::getCurrentBinding() should
          * throw an specific exception when the binding is unknown, and we should capture that here
          */
         if ($e->getMessage() === 'Unable to find the current binding.') {
-            throw new SimpleSAML_Error_Error('SLOSERVICEPARAMS', $e, 400);
+            throw new \SimpleSAML\Error\Error('SLOSERVICEPARAMS', $e, 400);
         } else {
             throw $e; // do not ignore other exceptions!
         }
     }
 }
-assert(FALSE);
+assert(false);
diff --git a/www/saml2/idp/initSLO.php b/www/saml2/idp/initSLO.php
index 60b17fc5ff86ae9eb24b2a0ef39456c4ebd776dc..21576797dc174feab48981eb70fc52f869507193 100644
--- a/www/saml2/idp/initSLO.php
+++ b/www/saml2/idp/initSLO.php
@@ -1,15 +1,16 @@
 <?php
+
 require_once('../../_include.php');
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
-$idp = SimpleSAML_IdP::getById('saml2:'.$idpEntityId);
+$idp = \SimpleSAML\IdP::getById('saml2:'.$idpEntityId);
 
-SimpleSAML\Logger::info('SAML2.0 - IdP.initSLO: Accessing SAML 2.0 IdP endpoint init Single Logout');
+\SimpleSAML\Logger::info('SAML2.0 - IdP.initSLO: Accessing SAML 2.0 IdP endpoint init Single Logout');
 
 if (!isset($_GET['RelayState'])) {
-    throw new SimpleSAML_Error_Error('NORELAYSTATE');
+    throw new \SimpleSAML\Error\Error('NORELAYSTATE');
 }
 
 $idp->doLogoutRedirect(\SimpleSAML\Utils\HTTP::checkURLAllowed((string) $_GET['RelayState']));
-assert(FALSE);
+assert(false);
diff --git a/www/saml2/idp/metadata.php b/www/saml2/idp/metadata.php
index 0ea40211490802a293d5ab317a83d75db049120e..984fb9252d7ce0402701c3e0a08ef6c5257e51a6 100644
--- a/www/saml2/idp/metadata.php
+++ b/www/saml2/idp/metadata.php
@@ -8,12 +8,12 @@ use SimpleSAML\Utils\Crypto as Crypto;
 use SimpleSAML\Utils\HTTP as HTTP;
 use SimpleSAML\Utils\Config\Metadata as Metadata;
 
-// load SimpleSAMLphp, configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+// load SimpleSAMLphp configuration and metadata
+$config = \SimpleSAML\Configuration::getInstance();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
 if (!$config->getBoolean('enable.saml20-idp', false)) {
-    throw new SimpleSAML_Error_Error('NOACCESS');
+    throw new \SimpleSAML\Error\Error('NOACCESS');
 }
 
 // check if valid local session exists
@@ -23,22 +23,21 @@ if ($config->getBoolean('admin.protectmetadata', false)) {
 
 try {
     $idpentityid = isset($_GET['idpentityid']) ?
-        $_GET['idpentityid'] :
-        $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
+        $_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('saml20-idp-hosted');
     $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'saml20-idp-hosted');
 
-    $availableCerts = array();
+    $availableCerts = [];
 
-    $keys = array();
+    $keys = [];
     $certInfo = Crypto::loadPublicKey($idpmeta, false, 'new_');
     if ($certInfo !== null) {
         $availableCerts['new_idp.crt'] = $certInfo;
-        $keys[] = array(
+        $keys[] = [
             'type'            => 'X509Certificate',
             'signing'         => true,
             'encryption'      => true,
             'X509Certificate' => $certInfo['certData'],
-        );
+        ];
         $hasNewCert = true;
     } else {
         $hasNewCert = false;
@@ -46,29 +45,29 @@ try {
 
     $certInfo = Crypto::loadPublicKey($idpmeta, true);
     $availableCerts['idp.crt'] = $certInfo;
-    $keys[] = array(
+    $keys[] = [
         'type'            => 'X509Certificate',
         'signing'         => true,
         'encryption'      => ($hasNewCert ? false : true),
         'X509Certificate' => $certInfo['certData'],
-    );
+    ];
 
     if ($idpmeta->hasValue('https.certificate')) {
         $httpsCert = Crypto::loadPublicKey($idpmeta, true, 'https.');
         assert(isset($httpsCert['certData']));
         $availableCerts['https.crt'] = $httpsCert;
-        $keys[] = array(
+        $keys[] = [
             'type'            => 'X509Certificate',
             'signing'         => true,
             'encryption'      => false,
             'X509Certificate' => $httpsCert['certData'],
-        );
+        ];
     }
 
-    $metaArray = array(
+    $metaArray = [
         'metadata-set' => 'saml20-idp-remote',
         'entityid'     => $idpentityid,
-    );
+    ];
 
     $ssob = $metadata->getGenerated('SingleSignOnServiceBinding', 'saml20-idp-hosted');
     $slob = $metadata->getGenerated('SingleLogoutServiceBinding', 'saml20-idp-hosted');
@@ -77,30 +76,30 @@ try {
 
     if (is_array($ssob)) {
         foreach ($ssob as $binding) {
-            $metaArray['SingleSignOnService'][] = array(
+            $metaArray['SingleSignOnService'][] = [
                 'Binding'  => $binding,
                 'Location' => $ssol,
-            );
+            ];
         }
     } else {
-        $metaArray['SingleSignOnService'][] = array(
+        $metaArray['SingleSignOnService'][] = [
             'Binding'  => $ssob,
             'Location' => $ssol,
-        );
+        ];
     }
 
     if (is_array($slob)) {
         foreach ($slob as $binding) {
-            $metaArray['SingleLogoutService'][] = array(
+            $metaArray['SingleLogoutService'][] = [
                 'Binding'  => $binding,
                 'Location' => $slol,
-            );
+            ];
         }
     } else {
-        $metaArray['SingleLogoutService'][] = array(
+        $metaArray['SingleLogoutService'][] = [
             'Binding'  => $slob,
             'Location' => $slol,
-        );
+        ];
     }
 
     if (count($keys) === 1) {
@@ -111,31 +110,31 @@ try {
 
     if ($idpmeta->getBoolean('saml20.sendartifact', false)) {
         // Artifact sending enabled
-        $metaArray['ArtifactResolutionService'][] = array(
+        $metaArray['ArtifactResolutionService'][] = [
             'index'    => 0,
             'Location' => HTTP::getBaseURL().'saml2/idp/ArtifactResolutionService.php',
             'Binding'  => Constants::BINDING_SOAP,
-        );
+        ];
     }
 
     if ($idpmeta->getBoolean('saml20.hok.assertion', false)) {
         // Prepend HoK SSO Service endpoint.
-        array_unshift($metaArray['SingleSignOnService'], array(
+        array_unshift($metaArray['SingleSignOnService'], [
             'hoksso:ProtocolBinding' => Constants::BINDING_HTTP_REDIRECT,
             'Binding'                => Constants::BINDING_HOK_SSO,
             'Location'               => HTTP::getBaseURL().'saml2/idp/SSOService.php'
-        ));
+        ]);
     }
 
     if ($idpmeta->getBoolean('saml20.ecp', false)) {
-        $metaArray['SingleSignOnService'][] = array(
+        $metaArray['SingleSignOnService'][] = [
             'index' => 0,
-            'Binding' => SAML2_Const::BINDING_SOAP,
+            'Binding'  => Constants::BINDING_SOAP,
             'Location' => HTTP::getBaseURL().'saml2/idp/SSOService.php',
-        );
+        ];
     }
 
-    $metaArray['NameIDFormat'] = $idpmeta->getString(
+    $metaArray['NameIDFormat'] = $idpmeta->getArrayizeString(
         'NameIDFormat',
         'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
     );
@@ -148,7 +147,7 @@ try {
         );
 
         if (!$idpmeta->hasValue('OrganizationURL')) {
-            throw new SimpleSAML_Error_Exception('If OrganizationName is set, OrganizationURL must also be set.');
+            throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
         }
         $metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
     }
@@ -201,7 +200,7 @@ try {
         $metaArray['contacts'][] = Metadata::getContact($techcontact);
     }
 
-    $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid);
+    $metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($idpentityid);
     $metaBuilder->addMetadataIdP20($metaArray);
     $metaBuilder->addOrganizationInfo($metaArray);
 
@@ -210,29 +209,39 @@ try {
     $metaflat = '$metadata['.var_export($idpentityid, true).'] = '.var_export($metaArray, true).';';
 
     // sign the metadata if enabled
-    $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'SAML 2 IdP');
+    $metaxml = \SimpleSAML\Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'SAML 2 IdP');
 
     if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
         $defaultidp = $config->getString('default-saml20-idp', null);
 
-        $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin');
+        $t = new \SimpleSAML\XHTML\Template($config, 'metadata.php', 'admin');
 
         $t->data['clipboard.js'] = true;
         $t->data['available_certs'] = $availableCerts;
+        $certdata = [];
+        foreach (array_keys($availableCerts) as $availableCert) {
+            $certdata[$availableCert]['name'] = $availableCert;
+            $certdata[$availableCert]['url'] = SimpleSAML\Module::getModuleURL('saml/idp/certs.php').'/'.$availableCert;
+            $certdata[$availableCert]['comment'] = (
+                $availableCerts[$availableCert]['certFingerprint'][0] === 'afe71c28ef740bc87425be13a2263d37971da1f9' ?
+                'This is the default certificate. Generate a new certificate if this is a production system.' :
+                ''
+            );
+        }
+        $t->data['certdata'] = $certdata;
         $t->data['header'] = 'saml20-idp'; // TODO: Replace with headerString in 2.0
-        $t->data['headerString'] = $t->noop('metadata_saml20-idp');
+        $t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_saml20-idp');
         $t->data['metaurl'] = HTTP::getSelfURLNoQuery();
         $t->data['metadata'] = htmlspecialchars($metaxml);
         $t->data['metadataflat'] = htmlspecialchars($metaflat);
         $t->data['defaultidp'] = $defaultidp;
         $t->show();
     } else {
-
         header('Content-Type: application/xml');
 
         echo $metaxml;
         exit(0);
     }
-} catch (Exception $exception) {
-    throw new SimpleSAML_Error_Error('METADATA', $exception);
+} catch (\Exception $exception) {
+    throw new \SimpleSAML\Error\Error('METADATA', $exception);
 }
diff --git a/www/shib13/idp/SSOService.php b/www/shib13/idp/SSOService.php
index 1a65ab18f96ea6273e6a7e0c3a12b92b47322e03..14a014fcdb8e8e56b948534494fdea47c34ade5e 100644
--- a/www/shib13/idp/SSOService.php
+++ b/www/shib13/idp/SSOService.php
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * The SSOService is part of the Shibboleth 1.3 IdP code, and it receives incoming Authentication Requests
  * from a Shibboleth 1.3 SP, parses, and process it, and then authenticates the user and sends the user back
@@ -10,10 +11,11 @@
 
 require_once '../../_include.php';
 
-SimpleSAML\Logger::info('Shib1.3 - IdP.SSOService: Accessing Shibboleth 1.3 IdP endpoint SSOService');
+\SimpleSAML\Logger::info('Shib1.3 - IdP.SSOService: Accessing Shibboleth 1.3 IdP endpoint SSOService');
 
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 $idpEntityId = $metadata->getMetaDataCurrentEntityID('shib13-idp-hosted');
-$idp = SimpleSAML_IdP::getById('saml1:' . $idpEntityId);
-sspmod_saml_IdP_SAML1::receiveAuthnRequest($idp);
+$idp = \SimpleSAML\IdP::getById('saml1:'.$idpEntityId);
+\SimpleSAML\Module\saml\IdP\SAML1::receiveAuthnRequest($idp);
+
 assert(false);
diff --git a/www/shib13/idp/metadata.php b/www/shib13/idp/metadata.php
index 23c3f6857c3638b4b51dfdcb768e2c92bd540f31..acd5ee33a46b99877db0598eba10d367d8e1e023 100644
--- a/www/shib13/idp/metadata.php
+++ b/www/shib13/idp/metadata.php
@@ -3,48 +3,47 @@
 require_once('../../_include.php');
 
 // load configuration and metadata
-$config = SimpleSAML_Configuration::getInstance();
-$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
+$config = \SimpleSAML\Configuration::getInstance();
+$metadata = \SimpleSAML\Metadata\MetaDataStorageHandler::getMetadataHandler();
 
 if (!$config->getBoolean('enable.shib13-idp', false)) {
-    throw new SimpleSAML_Error_Error('NOACCESS');
+    throw new \SimpleSAML\Error\Error('NOACCESS');
 }
 
 // check if valid local session exists
 if ($config->getBoolean('admin.protectmetadata', false)) {
-    SimpleSAML\Utils\Auth::requireAdmin();
+    \SimpleSAML\Utils\Auth::requireAdmin();
 }
 
 try {
     $idpentityid = isset($_GET['idpentityid']) ?
-        $_GET['idpentityid'] :
-        $metadata->getMetaDataCurrentEntityID('shib13-idp-hosted');
+        $_GET['idpentityid'] : $metadata->getMetaDataCurrentEntityID('shib13-idp-hosted');
     $idpmeta = $metadata->getMetaDataConfig($idpentityid, 'shib13-idp-hosted');
 
-    $keys = array();
-    $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
+    $keys = [];
+    $certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, false, 'new_');
     if ($certInfo !== null) {
-        $keys[] = array(
+        $keys[] = [
             'type'            => 'X509Certificate',
             'signing'         => true,
             'encryption'      => false,
             'X509Certificate' => $certInfo['certData'],
-        );
+        ];
     }
 
-    $certInfo = SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
-    $keys[] = array(
+    $certInfo = \SimpleSAML\Utils\Crypto::loadPublicKey($idpmeta, true);
+    $keys[] = [
         'type'            => 'X509Certificate',
         'signing'         => true,
         'encryption'      => false,
         'X509Certificate' => $certInfo['certData'],
-    );
+    ];
 
-    $metaArray = array(
+    $metaArray = [
         'metadata-set'        => 'shib13-idp-remote',
         'entityid'            => $idpentityid,
         'SingleSignOnService' => $metadata->getGenerated('SingleSignOnService', 'shib13-idp-hosted'),
-    );
+    ];
 
     if (count($keys) === 1) {
         $metaArray['certData'] = $keys[0]['X509Certificate'];
@@ -52,7 +51,7 @@ try {
         $metaArray['keys'] = $keys;
     }
 
-    $metaArray['NameIDFormat'] = $idpmeta->getString('NameIDFormat', 'urn:mace:shibboleth:1.0:nameIdentifier');
+    $metaArray['NameIDFormat'] = $idpmeta->getArrayizeString('NameIDFormat', 'urn:mace:shibboleth:1.0:nameIdentifier');
 
     if ($idpmeta->hasValue('OrganizationName')) {
         $metaArray['OrganizationName'] = $idpmeta->getLocalizedString('OrganizationName');
@@ -62,39 +61,37 @@ try {
         );
 
         if (!$idpmeta->hasValue('OrganizationURL')) {
-            throw new SimpleSAML_Error_Exception('If OrganizationName is set, OrganizationURL must also be set.');
+            throw new \SimpleSAML\Error\Exception('If OrganizationName is set, OrganizationURL must also be set.');
         }
         $metaArray['OrganizationURL'] = $idpmeta->getLocalizedString('OrganizationURL');
     }
 
-
     $metaflat = '$metadata['.var_export($idpentityid, true).'] = '.var_export($metaArray, true).';';
 
-    $metaBuilder = new SimpleSAML_Metadata_SAMLBuilder($idpentityid);
+    $metaBuilder = new \SimpleSAML\Metadata\SAMLBuilder($idpentityid);
     $metaBuilder->addMetadataIdP11($metaArray);
     $metaBuilder->addOrganizationInfo($metaArray);
-    $metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact(array(
+    $metaBuilder->addContact('technical', \SimpleSAML\Utils\Config\Metadata::getContact([
         'emailAddress' => $config->getString('technicalcontact_email', null),
         'name'         => $config->getString('technicalcontact_name', null),
         'contactType'  => 'technical',
-    )));
+    ]));
     $metaxml = $metaBuilder->getEntityDescriptorText();
 
     // sign the metadata if enabled
-    $metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta->toArray(), 'Shib 1.3 IdP');
-
+    $metaxml = \SimpleSAML\Metadata\Signer::sign($metaxml, $idpmeta->toArray(), 'Shib 1.3 IdP');
 
     if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
         $defaultidp = $config->getString('default-shib13-idp', null);
 
-        $t = new SimpleSAML_XHTML_Template($config, 'metadata.php', 'admin');
+        $t = new \SimpleSAML\XHTML\Template($config, 'metadata.php', 'admin');
 
         $t->data['clipboard.js'] = true;
         $t->data['header'] = 'shib13-idp'; // TODO: Replace with headerString in 2.0
-        $t->data['headerString'] = $t->noop('metadata_shib13-idp');
+        $t->data['headerString'] = \SimpleSAML\Locale\Translate::noop('metadata_shib13-idp');
         $t->data['metaurl'] = \SimpleSAML\Utils\HTTP::addURLParameters(
             \SimpleSAML\Utils\HTTP::getSelfURLNoQuery(),
-            array('output' => 'xml')
+            ['output' => 'xml']
         );
         $t->data['metadata'] = htmlspecialchars($metaxml);
         $t->data['metadataflat'] = htmlspecialchars($metaflat);
@@ -107,6 +104,6 @@ try {
         echo $metaxml;
         exit(0);
     }
-} catch (Exception $exception) {
-    throw new SimpleSAML_Error_Error('METADATA', $exception);
+} catch (\Exception $exception) {
+    throw new \SimpleSAML\Error\Error('METADATA', $exception);
 }
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000000000000000000000000000000000000..1cbf92fed61b4dd0485ad90bf63e12791efecf7e
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,148 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+ansicolors@~0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef"
+  integrity sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8=
+
+async@^2.6.0:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
+  integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
+  dependencies:
+    lodash "^4.17.10"
+
+cardinal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9"
+  integrity sha1-UOIcGwqjdyn5N33vGWtanOyTLuk=
+  dependencies:
+    ansicolors "~0.2.1"
+    redeyed "~1.0.0"
+
+clipboard@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.1.tgz#a12481e1c13d8a50f5f036b0560fe5d16d74e46a"
+  integrity sha512-7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==
+  dependencies:
+    good-listener "^1.2.2"
+    select "^1.1.2"
+    tiny-emitter "^2.0.0"
+
+csv-parse@^2.0.0:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-2.5.0.tgz#65748997ecc3719c594622db1b9ea0e2eb7d56bb"
+  integrity sha512-4OcjOJQByI0YDU5COYw9HAqjo8/MOLLmT9EKyMCXUzgvh30vS1SlMK+Ho84IH5exN44cSnrYecw/7Zpu2m4lkA==
+
+delegate@^3.1.2:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+  integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
+
+esprima@~3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9"
+  integrity sha1-U88kes2ncxPlUcOqLnM0LT+099k=
+
+font-awesome@^4.7.0:
+  version "4.7.0"
+  resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
+  integrity sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=
+
+good-listener@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+  integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
+  dependencies:
+    delegate "^3.1.2"
+
+humanize@^0.0.9:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/humanize/-/humanize-0.0.9.tgz#1994ffaecdfe9c441ed2bdac7452b7bb4c9e41a4"
+  integrity sha1-GZT/rs3+nEQe0r2sdFK3u0yeQaQ=
+
+jquery-ui@^1.12.1:
+  version "1.12.1"
+  resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.12.1.tgz#bcb4045c8dd0539c134bc1488cdd3e768a7a9e51"
+  integrity sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE=
+
+jquery@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
+  integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==
+
+lodash@^4.17.10:
+  version "4.17.11"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+  integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+
+microplugin@0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/microplugin/-/microplugin-0.0.3.tgz#1fc2e1bb7c9e19e82bd84bba9137bbe71250d8cd"
+  integrity sha1-H8Lhu3yeGegr2Eu6kTe75xJQ2M0=
+
+minimist@~0.0.1:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+  integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+
+nan@2.9.x:
+  version "2.9.2"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866"
+  integrity sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==
+
+optimist@^0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
+  integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
+  dependencies:
+    minimist "~0.0.1"
+    wordwrap "~0.0.2"
+
+purecss@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/purecss/-/purecss-1.0.0.tgz#3dbcd9e2a7592448a69acb705cce16311bf4b785"
+  integrity sha512-gfC78WCOWNnfkzulx9aoWwcl+0JflhwKeJ+k9s/ZyIawfYNA4bqBmt0DtfgtQK9iuYMtGfbdE8R2AQMjSWR2VQ==
+
+redeyed@~1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a"
+  integrity sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=
+  dependencies:
+    esprima "~3.0.0"
+
+select@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+  integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
+
+selectize@^0.12.6:
+  version "0.12.6"
+  resolved "https://registry.yarnpkg.com/selectize/-/selectize-0.12.6.tgz#c2cf08cbaa4cb06c5e99bb452919d71b080690d6"
+  integrity sha512-bWO5A7G+I8+QXyjLfQUgh31VI4WKYagUZQxAXlDyUmDDNrFxrASV0W9hxCOl0XJ/XQ1dZEu3G9HjXV4Wj0yb6w==
+  dependencies:
+    microplugin "0.0.3"
+    sifter "^0.5.1"
+
+sifter@^0.5.1:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/sifter/-/sifter-0.5.3.tgz#5e6507fe8c114b2b28d90b6bf4e5b636e611e48b"
+  integrity sha1-XmUH/owRSyso2Qtr9OW2NuYR5Is=
+  dependencies:
+    async "^2.6.0"
+    cardinal "^1.0.0"
+    csv-parse "^2.0.0"
+    humanize "^0.0.9"
+    optimist "^0.6.1"
+
+tiny-emitter@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"
+  integrity sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==
+
+wordwrap@~0.0.2:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
+  integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=