Merge "Add documentation for a test setup using SimpleSamlPhp"
diff --git a/README.md b/README.md
index 9a01e03..3575060 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@
 - [Okta](okta/README.md)
 - [Keycloak](keycloak/README.md)
 - [ADFS](adfs/README.md)
+- [SimpleSamlPHP](simplesamlphp/README.md)
 
 ### Download the plugin
 
diff --git a/simplesamlphp/README.md b/simplesamlphp/README.md
new file mode 100644
index 0000000..44646f4
--- /dev/null
+++ b/simplesamlphp/README.md
@@ -0,0 +1,88 @@
+# SimpleSamlPHP as Gerrit SAML provider
+
+[SimpleSamlPHP](https://simplesamlphp.org/) is open source Identity and Access
+Management tool and supports the SAML authentication protocol.
+
+## Objective
+
+This document provides a step-by-step tutorial how to set-up SimpleSamlPHP as
+SAML provider for Gerrit Code Review for development and guidance only.
+For production HTTPS protocol and other more secure credentials and keys
+would need to be put in place.
+
+## Prerequisites
+
+- [Docker](https://www.docker.com/get-started)
+- [Gerrit Code Review v2.15 or later](https://www.gerritcodereview.com)
+
+## Steps
+
+1. Install the `jamedjo/test-saml-idp` docker image:
+
+```bash
+docker run -it --rm --name=testsamlidp_idp \
+	-p 8080:8080 \
+	-p 8443:8443 \
+	-v $(realpath simplesamlphp/config/authsources.php):/var/www/simplesamlphp/config/authsources.php \
+	-v $(realpath simplesamlphp/config/config.php):/var/www/simplesamlphp/config/config.php \
+	-v $(realpath simplesamlphp/metadata/saml20-sp-remote.php):/var/www/simplesamlphp/metadata/saml20-sp-remote.php \
+	-v $(realpath simplesamlphp/metadata/saml20-idp-hosted.php):/var/www/simplesamlphp/metadata/saml20-idp-hosted.php \
+	-e SIMPLESAMLPHP_SP_ENTITY_ID=gerritSaml \
+	-e SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE=http://localhost/simplesaml/module.php/saml/sp/saml2-acs.php/test-sp \
+	-e SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE=http://localhost/simplesaml/module.php/saml/sp/saml2-logout.php/test-sp \
+	-d jamedjo/test-saml-idp
+```
+
+2. Add the following configuration settings to $GERRIT_SITE/etc/gerrit.config:
+
+```
+[gerrit]
+	basePath = git
+	canonicalWebUrl = http://localhost:8081/
+[auth]
+	type = HTTP
+	logoutUrl = http://localhost:8080/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo=http://localhost:8081
+	httpHeader = X-SAML-UserName
+	httpDisplaynameHeader = X-SAML-DisplayName
+	httpEmailHeader = X-SAML-EmailHeader
+	httpExternalIdHeader = X-SAML-ExternalId
+	autoUpdateAccountActiveStatus = true
+[saml]
+	serviceProviderEntityId = gerritSaml
+	keystorePath = /Users/d073103/sites/serviceuserMaster/etc/keystore
+	keystorePassword = pac4j-demo-password
+	privateKeyPassword = pac4j-demo-password
+	metadataPath = http://localhost:8080/simplesaml/saml2/idp/metadata.php
+	userNameAttr = username
+	emailAddressAttr = email
+	computedDisplayName = true
+	firstNameAttr = first_name
+	lastNameAttr = last_name
+[httpd]
+	listenUrl = http://*:8081/
+	filterClass = com.googlesource.gerrit.plugins.saml.SamlWebFilter
+```
+
+3. Generate keystore in `$GERRIT_SITE/etc` local keystore:
+
+```
+keytool -genkeypair -alias pac4j -keypass pac4j-demo-password \
+  -keystore samlKeystore.jks \
+  -storepass pac4j-demo-password -keyalg RSA -keysize 2048 -validity 365
+```
+
+4. Install the saml.jar filter into the `$GERRIT_SITE/lib` directory
+
+5. Start gerrit using: `$GERRIT_SITE/bin/gerrit.sh start`
+
+6. Enter gerrit URL in browser: http://localhost:8081 and hit "Sign In" button
+
+7. SimpleSamlPHP Login Dialog should appear
+
+8. Enter user: "user1" and password: "user1pass" (Note that additional users can
+be added in `config/authsources.php`.)
+
+9. You are redirected to gerrit and the first user/admin User One is created
+in gerrit with the right user name and email address.
+
+12. Congrats, you have Gerrit / SimpleSamlPHP SAML integration up and running.
diff --git a/simplesamlphp/config/authsources.php b/simplesamlphp/config/authsources.php
new file mode 100644
index 0000000..cc5eb19
--- /dev/null
+++ b/simplesamlphp/config/authsources.php
@@ -0,0 +1,38 @@
+<?php
+
+$config = array(
+    'admin' => array(
+        'core:AdminPassword',
+    ),
+
+    'example-userpass' => array(
+        'exampleauth:UserPass',
+        'user1:user1pass' => array(
+            'uid' => array('1'),
+            'username' => 'user1',
+            'first_name' => 'User',
+            'last_name' => 'One',
+            'email' => 'user_1@example.com',
+        ),
+        'user2:user2pass' => array(
+            'uid' => array('2'),
+            'username' => 'user2',
+            'first_name' => 'User',
+            'last_name' => 'Two',
+            'email' => 'user_2@example.com',
+        ),
+        'user3:user3pass' => array(
+            'uid' => array('3'),
+            'username' => 'user3',
+            'first_name' => 'User',
+            'last_name' => 'Three',
+            'email' => 'user_3@example.com',
+        ),
+        'user4:user4pass' => array(
+            'uid' => array('4'),
+            'username' => 'user4',
+            'name' => 'User Four',
+            'email' => 'user_4@example.com',
+        ),
+    ),
+);
diff --git a/simplesamlphp/config/config.php b/simplesamlphp/config/config.php
new file mode 100644
index 0000000..956caa5
--- /dev/null
+++ b/simplesamlphp/config/config.php
@@ -0,0 +1,835 @@
+<?php
+/*
+ * The configuration of SimpleSAMLphp
+ *
+ */
+
+$config = array(
+
+    /**
+     * Setup the following parameters to match the directory of your installation.
+     * See the user manual for more details.
+     *
+     * Valid format for baseurlpath is:
+     * [(http|https)://(hostname|fqdn)[:port]]/[path/to/simplesaml/]
+     * (note that it must end with a '/')
+     *
+     * The full url format is useful if your SimpleSAMLphp setup is hosted behind
+     * a reverse proxy. In that case you can specify the external url here.
+     *
+     * Please note that SimpleSAMLphp will then redirect all queries to the
+     * external url, no matter where you come from (direct access or via the
+     * reverse proxy).
+     */
+    'baseurlpath' => 'simplesaml/',
+    'certdir' => 'cert/',
+    'loggingdir' => 'log/',
+    'datadir' => 'data/',
+
+    /*
+     * A directory where SimpleSAMLphp can save temporary files.
+     *
+     * SimpleSAMLphp will attempt to create this directory if it doesn't exist.
+     */
+    'tempdir' => '/tmp/simplesaml',
+
+    /*
+     * If you enable this option, SimpleSAMLphp will log all sent and received messages
+     * to the log file.
+     *
+     * This option also enables logging of the messages that are encrypted and decrypted.
+     *
+     * Note: The messages are logged with the DEBUG log level, so you also need to set
+     * the 'logging.level' option to LOG_DEBUG.
+     */
+    'debug' => true,
+
+    /*
+     * When showerrors is enabled, all error messages and stack traces will be output
+     * to the browser.
+     *
+     * When errorreporting is enabled, a form will be presented for the user to report
+     * the error to technicalcontact_email.
+     */
+    'showerrors' => true,
+    'errorreporting' => true,
+
+    /**
+     * 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'),
+     */
+
+    /**
+     * This option allows you to enable validation of XML data against its
+     * schemas. A warning will be written to the log if validation fails.
+     */
+    'debug.validatexml' => false,
+
+    /**
+     * This password must be kept secret, and modified from the default value 123.
+     * This password will give access to the installation page of SimpleSAMLphp with
+     * metadata listing and diagnostics pages.
+     * You can also put a hash here; run "bin/pwgen.php" to generate one.
+     */
+    'auth.adminpassword' => ((getenv('SIMPLESAMLPHP_ADMIN_PASSWORD') != '') ? getenv('SIMPLESAMLPHP_ADMIN_PASSWORD') : 'secret'),
+    'admin.protectindexpage' => false,
+    'admin.protectmetadata' => false,
+
+    /**
+     * This is a secret salt used by SimpleSAMLphp when it needs to generate a secure hash
+     * of a value. It must be changed from its default value to a secret value. The value of
+     * '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
+     */
+    'secretsalt' => ((getenv('SIMPLESAMLPHP_SECRET_SALT') != '') ? getenv('SIMPLESAMLPHP_SECRET_SALT') : 'defaultsecretsalt'),
+
+    /*
+     * Some information about the technical persons running this installation.
+     * The email address will be used as the recipient address for error reports, and
+     * also as the technical contact in generated metadata.
+     */
+    'technicalcontact_name' => 'Administrator',
+    'technicalcontact_email' => 'na@example.org',
+
+    /*
+     * The timezone of the server. This option should be set to the timezone you want
+     * SimpleSAMLphp to report the time in. The default is to guess the timezone based
+     * on your system timezone.
+     *
+     * See this page for a list of valid timezones: http://php.net/manual/en/timezones.php
+     */
+    'timezone' => null,
+
+    /*
+     * Logging.
+     *
+     * define the minimum log level to log
+     *        SimpleSAML_Logger::ERR        No statistics, only errors
+     *        SimpleSAML_Logger::WARNING    No statistics, only warnings/errors
+     *        SimpleSAML_Logger::NOTICE    Statistics and errors
+     *        SimpleSAML_Logger::INFO        Verbose logs
+     *        SimpleSAML_Logger::DEBUG    Full debug logs - not recommended for production
+     *
+     * Choose logging handler.
+     *
+     * Options: [syslog,file,errorlog]
+     *
+     */
+    'logging.level' => SimpleSAML_Logger::DEBUG,
+    'logging.handler' => 'file',
+
+    /*
+     * Specify the format of the logs. Its use varies depending on the log handler used (for instance, you cannot
+     * control here how dates are displayed when using the syslog or errorlog handlers), but in general the options
+     * are:
+     *
+     * - %date{<format>}: the date and time, with its format specified inside the brackets. See the PHP documentation
+     *   of the strftime() function for more information on the format. If the brackets are omitted, the standard
+     *   format is applied. This can be useful if you just want to control the placement of the date, but don't care
+     *   about the format.
+     *
+     * - %process: the name of the SimpleSAMLphp process. Remember you can configure this in the 'logging.processname'
+     *   option below.
+     *
+     * - %level: the log level (name or number depending on the handler used).
+     *
+     * - %stat: if the log entry is intended for statistical purposes, it will print the string 'STAT ' (bear in mind
+     *   the trailing space).
+     *
+     * - %trackid: the track ID, an identifier that allows you to track a single session.
+     *
+     * - %srcip: the IP address of the client. If you are behind a proxy, make sure to modify the
+     *   $_SERVER['REMOTE_ADDR'] variable on your code accordingly to the X-Forwarded-For header.
+     *
+     * - %msg: the message to be logged.
+     *
+     */
+    //'logging.format' => '%date{%b %d %H:%M:%S} %process %level %stat[%trackid] %msg',
+
+    /*
+     * Choose which facility should be used when logging with syslog.
+     *
+     * These can be used for filtering the syslog output from SimpleSAMLphp into its
+     * own file by configuring the syslog daemon.
+     *
+     * See the documentation for openlog (http://php.net/manual/en/function.openlog.php) for available
+     * facilities. Note that only LOG_USER is valid on windows.
+     *
+     * The default is to use LOG_LOCAL5 if available, and fall back to LOG_USER if not.
+     */
+    'logging.facility' => defined('LOG_LOCAL5') ? constant('LOG_LOCAL5') : LOG_USER,
+
+    /*
+     * The process name that should be used when logging to syslog.
+     * The value is also written out by the other logging handlers.
+     */
+    'logging.processname' => 'simplesamlphp',
+
+    /* Logging: file - Logfilename in the loggingdir from above.
+     */
+    'logging.logfile' => 'simplesamlphp.log',
+
+    /* (New) statistics output configuration.
+     *
+     * 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.
+        /*
+        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',
+    ),
+     */
+    ),
+
+    /*
+     * Database
+     *
+     * This database configuration is optional. If you are not using
+     * core functionality or modules that require a database, you can
+     * skip this configuration.
+     */
+
+    /*
+     * Database connection string.
+     * Ensure that you have the required PDO database driver installed
+     * for your connection string.
+     */
+    'database.dsn' => 'mysql:host=localhost;dbname=saml',
+
+    /*
+     * SQL database credentials
+     */
+    'database.username' => 'simplesamlphp',
+    'database.password' => 'secret',
+
+    /*
+     * (Optional) Table prefix
+     */
+    'database.prefix' => '',
+
+    /*
+     * True or false if you would like a persistent database connection
+     */
+    'database.persistent' => false,
+
+    /*
+     * Database slave configuration is optional as well. If you are only
+     * running a single database server, leave this blank. If you have
+     * a master/slave configuration, you can define as many slave servers
+     * as you want here. Slaves will be picked at random to be queried from.
+     *
+     * 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.
+     */
+    'database.slaves' => array(
+        /*
+    array(
+    'dsn' => 'mysql:host=myslave;dbname=saml',
+    'username' => 'simplesamlphp',
+    'password' => 'secret',
+    'persistent' => false,
+    ),
+     */
+    ),
+
+    /*
+     * Enable
+     *
+     * Which functionality in SimpleSAMLphp do you want to enable. Normally you would enable only
+     * one of the functionalities below, but in some cases you could run multiple functionalities.
+     * In example when you are setting up a federation bridge.
+     */
+    'enable.saml20-idp' => true,
+    'enable.shib13-idp' => true,
+    'enable.adfs-idp' => false,
+    'enable.wsfed-sp' => false,
+    'enable.authmemcookie' => false,
+
+    /*
+     * Module enable configuration
+     *
+     * Configuration to override module enabling/disabling.
+     *
+     * Example:
+     *
+     * 'module.enable' => array(
+     *     // Setting to TRUE enables.
+     *     'exampleauth' => TRUE,
+     *     // Setting to FALSE disables.
+     *     'saml' => FALSE,
+     *     // Unset or NULL uses default.
+     *     'core' => NULL,
+     * ),
+     *
+     */
+
+    /*
+     * This value is the duration of the session in seconds. Make sure that the time duration of
+     * cookies both at the SP and the IdP exceeds this duration.
+     */
+    'session.duration' => 8 * (60 * 60), // 8 hours.
+
+    /*
+     * Sets the duration, in seconds, data should be stored in the datastore. As the datastore is used for
+     * login and logout requests, thid option will control the maximum time these operations can take.
+     * The default is 4 hours (4*60*60) seconds, which should be more than enough for these operations.
+     */
+    'session.datastore.timeout' => (4 * 60 * 60), // 4 hours
+
+    /*
+     * Sets the duration, in seconds, auth state should be stored.
+     */
+    'session.state.timeout' => (60 * 60), // 1 hour
+
+    /*
+     * Option to override the default settings for the session cookie name
+     */
+    'session.cookie.name' => 'SimpleSAMLSessionIDIdp',
+
+    /*
+     * Expiration time for the session cookie, in seconds.
+     *
+     * Defaults to 0, which means that the cookie expires when the browser is closed.
+     *
+     * Example:
+     *  'session.cookie.lifetime' => 30*60,
+     */
+    'session.cookie.lifetime' => 0,
+
+    /*
+     * Limit the path of the cookies.
+     *
+     * Can be used to limit the path of the cookies to a specific subdirectory.
+     *
+     * Example:
+     *  'session.cookie.path' => '/simplesaml/',
+     */
+    'session.cookie.path' => '/',
+
+    /*
+     * Cookie domain.
+     *
+     * Can be used to make the session cookie available to several domains.
+     *
+     * Example:
+     *  'session.cookie.domain' => '.example.org',
+     */
+    'session.cookie.domain' => null,
+
+    /*
+     * Set the secure flag in the cookie.
+     *
+     * Set this to TRUE if the user only accesses your service
+     * through https. If the user can access the service through
+     * both http and https, this must be set to FALSE.
+     */
+    'session.cookie.secure' => false,
+
+    /*
+     * Enable secure POST from HTTPS to HTTP.
+     *
+     * If you have some SP's on HTTP and IdP is normally on HTTPS, this option
+     * enables secure POSTing to HTTP endpoint without warning from browser.
+     *
+     * For this to work, module.php/core/postredirect.php must be accessible
+     * also via HTTP on IdP, e.g. if your IdP is on
+     * https://idp.example.org/ssp/, then
+     * http://idp.example.org/ssp/module.php/core/postredirect.php must be accessible.
+     */
+    'enable.http_post' => false,
+
+    /*
+     * Options to override the default settings for php sessions.
+     */
+    'session.phpsession.cookiename' => 'PHPSESSIDIDP',
+    'session.phpsession.savepath' => null,
+    'session.phpsession.httponly' => true,
+
+    /*
+     * Option to override the default settings for the auth token cookie
+     */
+    'session.authtoken.cookiename' => 'SimpleSAMLAuthTokenIdp',
+
+    /*
+     * Options for remember me feature for IdP sessions. Remember me feature
+     * has to be also implemented in authentication source used.
+     *
+     * Option 'session.cookie.lifetime' should be set to zero (0), i.e. cookie
+     * expires on browser session if remember me is not checked.
+     *
+     * Session duration ('session.duration' option) should be set according to
+     * 'session.rememberme.lifetime' option.
+     *
+     * It's advised to use remember me feature with session checking function
+     * defined with 'session.check_function' option.
+     */
+    'session.rememberme.enable' => false,
+    'session.rememberme.checked' => false,
+    'session.rememberme.lifetime' => (14 * 86400),
+
+    /**
+     * Custom function for session checking called on session init and loading.
+     * See docs/simplesamlphp-advancedfeatures.txt for function code example.
+     *
+     * Example:
+     *   'session.check_function' => array('sspmod_example_Util', 'checkSession'),
+     */
+
+    /*
+     * Languages available, RTL languages, and what language is 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',
+    ),
+    'language.rtl' => array('ar', 'dv', 'fa', 'ur', 'he'),
+    'language.default' => 'en',
+
+    /*
+     * Options to override the default settings for the language parameter
+     */
+    'language.parameter.name' => 'language',
+    'language.parameter.setcookie' => true,
+
+    /*
+     * Options to override the default settings for the language cookie
+     */
+    'language.cookie.name' => 'language',
+    'language.cookie.domain' => null,
+    'language.cookie.path' => '/',
+    'language.cookie.lifetime' => (60 * 60 * 24 * 900),
+
+    /**
+     * Custom getLanguage function called from SimpleSAML_XHTML_Template::getLanguage().
+     * Function should return language code of one of the available languages or NULL.
+     * See SimpleSAML_XHTML_Template::getLanguage() source code for more info.
+     *
+     * This option can be used to implement a custom function for determining
+     * the default language for the user.
+     *
+     * Example:
+     *   'language.get_language_function' => array('sspmod_example_Template', 'getLanguage'),
+     */
+
+    /*
+     * Extra dictionary for attribute names.
+     * This can be used to define local attributes.
+     *
+     * The format of the parameter is a string with <module>:<dictionary>.
+     *
+     * Specifying this option will cause us to look for modules/<module>/dictionaries/<dictionary>.definition.json
+     * The dictionary should look something like:
+     *
+     * {
+     *     "firstattribute": {
+     *         "en": "English name",
+     *         "no": "Norwegian name"
+     *     },
+     *     "secondattribute": {
+     *         "en": "English name",
+     *         "no": "Norwegian name"
+     *     }
+     * }
+     *
+     * Note that all attribute names in the dictionary must in lowercase.
+     *
+     * Example: 'attributes.extradictionary' => 'ourmodule:ourattributes',
+     */
+    'attributes.extradictionary' => null,
+
+    /*
+     * Which theme directory should be used?
+     */
+    'theme.use' => 'default',
+
+    /*
+     * Default IdP for WS-Fed.
+     */
+    'default-wsfed-idp' => 'urn:federation:pingfederate:localhost',
+
+    /*
+     * Whether the discovery service should allow the user to save his choice of IdP.
+     */
+    'idpdisco.enableremember' => true,
+    'idpdisco.rememberchecked' => true,
+
+    // Disco service only accepts entities it knows.
+    'idpdisco.validate' => true,
+
+    'idpdisco.extDiscoveryStorage' => null,
+
+    /*
+     * IdP Discovery service look configuration.
+     * Wether to display a list of idp or to display a dropdown box. For many IdP' a dropdown box
+     * gives the best use experience.
+     *
+     * When using dropdown box a cookie is used to highlight the previously chosen IdP in the dropdown.
+     * This makes it easier for the user to choose the IdP
+     *
+     * Options: [links,dropdown]
+     *
+     */
+    'idpdisco.layout' => 'dropdown',
+
+    /*
+     * Whether SimpleSAMLphp should sign the response or the assertion in SAML 1.1 authentication
+     * responses.
+     *
+     * The default is to sign the assertion element, but that can be overridden by setting this
+     * option to TRUE. It can also be overridden on a pr. SP basis by adding an option with the
+     * same name to the metadata of the SP.
+     */
+    'shib13.signresponse' => true,
+
+    /*
+     * Authentication processing filters that will be executed for all IdPs
+     * Both Shibboleth and SAML 2.0
+     */
+    'authproc.idp' => array(
+        /* Enable the authproc filter below to add URN Prefixces to all attributes
+        10 => array(
+        'class' => 'core:AttributeMap', 'addurnprefix'
+        ), */
+        /* Enable the authproc filter below to automatically generated eduPersonTargetedID.
+        20 => 'core:TargetedID',
+         */
+
+        // Adopts language from attribute to use in UI
+        30 => 'core:LanguageAdaptor',
+
+        /* Add a realm attribute from edupersonprincipalname
+        40 => 'core:AttributeRealm',
+         */
+        45 => array(
+            '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.
+         */
+        50 => 'core:AttributeLimit',
+
+        /*
+         * Search attribute "distinguishedName" for pattern and replaces if found
+
+        60 => array(
+        'class' => 'core:AttributeAlter',
+        'pattern' => '/OU=studerende/',
+        'replacement' => 'Student',
+        'subject' => 'distinguishedName',
+        '%replace',
+        ),
+         */
+
+        /*
+         * Consent module is enabled (with no permanent storage, using cookies).
+
+        90 => array(
+        'class' => 'consent:Consent',
+        'store' => 'consent:Cookie',
+        'focus' => 'yes',
+        '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(
+        /*
+        10 => array(
+        'class' => 'core:AttributeMap', 'removeurnprefix'
+        ),
+         */
+
+        /*
+         * Generate the 'group' attribute populated from other variables, including eduPersonAffiliation.
+        60 => array(
+        'class' => 'core:GenerateGroups', 'eduPersonAffiliation'
+        ),
+         */
+        /*
+         * All users will be members of 'users' and 'members'
+        61 => array(
+        'class' => 'core:AttributeAdd', 'groups' => array('users', 'members')
+        ),
+         */
+
+        // Adopts language from attribute to use in UI
+        90 => 'core:LanguageAdaptor',
+
+    ),
+
+    /*
+     * This option configures the metadata sources. The metadata sources is given as an array with
+     * different metadata sources. When searching for metadata, simpleSAMPphp will search through
+     * the array from start to end.
+     *
+     * Each element in the array is an associative array which configures the metadata source.
+     * The type of the metadata source is given by the 'type' element. For each type we have
+     * different configuration options.
+     *
+     * Flat file metadata handler:
+     * - 'type': This is always 'flatfile'.
+     * - 'directory': The directory we will load the metadata files from. The default value for
+     *                this option is the value of the 'metadatadir' configuration option, or
+     *                'metadata/' if that option is unset.
+     *
+     * XML metadata handler:
+     * This metadata handler parses an XML file with either an EntityDescriptor element or an
+     * EntitiesDescriptor element. The XML file may be stored locally, or (for debugging) on a remote
+     * web server.
+     * The XML hetadata handler defines the following options:
+     * - 'type': This is always 'xml'.
+     * - 'file': Path to the XML file with the metadata.
+     * - 'url': The URL to fetch metadata from. THIS IS ONLY FOR DEBUGGING - THERE IS NO CACHING OF THE RESPONSE.
+     *
+     * MDX metadata handler:
+     * This metadata handler looks up for the metadata of an entity at the given MDX server.
+     * The MDX metadata handler defines the following options:
+     * - 'type': This is always 'mdx'.
+     * - 'server': URL of the MDX server (url:port). Mandatory.
+     * - 'validateFingerprint': The fingerprint of the certificate used to sign the metadata.
+     *                          You don't need this option if you don't want to validate the signature on the metadata. Optional.
+     * - 'cachedir': Directory where metadata can be cached. Optional.
+     * - 'cachelength': Maximum time metadata cah be cached, in seconds. Default to 24
+     *                  hours (86400 seconds). Optional.
+     *
+     * PDO metadata handler:
+     * This metadata handler looks up metadata of an entity stored in a database.
+     *
+     * Note: If you are using the PDO metadata handler, you must configure the database
+     * options in this configuration file.
+     *
+     * The PDO metadata handler defines the following options:
+     * - 'type': This is always 'pdo'.
+     *
+     *
+     * Examples:
+     *
+     * This example defines two flatfile sources. One is the default metadata directory, the other
+     * is a metadata directory with autogenerated metadata files.
+     *
+     * 'metadata.sources' => array(
+     *     array('type' => 'flatfile'),
+     *     array('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'),
+     *     ),
+     *
+     * This example defines an mdx source.
+     * 'metadata.sources' => array(
+     *     array('type' => 'mdx', server => 'http://mdx.server.com:8080', 'cachedir' => '/var/simplesamlphp/mdx-cache', 'cachelength' => 86400)
+     *     ),
+     *
+     * This example defines an pdo source.
+     * 'metadata.sources' => array(
+     *     array('type' => 'pdo')
+     *     ),
+     *
+     * Default:
+     * 'metadata.sources' => array(
+     *     array('type' => 'flatfile')
+     *     ),
+     */
+    'metadata.sources' => array(
+        array('type' => 'flatfile'),
+    ),
+
+    /*
+     * Configure the datastore for SimpleSAMLphp.
+     *
+     * - 'phpsession': Limited datastore, which uses the PHP session.
+     * - 'memcache': Key-value datastore, based on memcache.
+     * - 'sql': SQL datastore, using PDO.
+     *
+     * The default datastore is 'phpsession'.
+     *
+     * (This option replaces the old 'session.handler'-option.)
+     */
+    'store.type' => 'phpsession',
+
+    /*
+     * The DSN the sql datastore should connect to.
+     *
+     * See http://www.php.net/manual/en/pdo.drivers.php for the various
+     * syntaxes.
+     */
+    'store.sql.dsn' => 'sqlite:/path/to/sqlitedatabase.sq3',
+
+    /*
+     * The username and password to use when connecting to the database.
+     */
+    'store.sql.username' => null,
+    'store.sql.password' => null,
+
+    /*
+     * The prefix we should use on our tables.
+     */
+    'store.sql.prefix' => 'SimpleSAMLphp',
+
+    /*
+     * Configuration for the 'memcache' session store. This allows you to store
+     * multiple redundant copies of sessions on different memcache servers.
+     *
+     * 'memcache_store.servers' is an array of server groups. Every data
+     * item will be mirrored in every server group.
+     *
+     * Each server group is an array of servers. The data items will be
+     * load-balanced between all servers in each server group.
+     *
+     * Each server is an array of parameters for the server. The following
+     * options are available:
+     *  - 'hostname': This is the hostname or ip address where the
+     *    memcache server runs. This is the only required option.
+     *  - 'port': This is the port number of the memcache server. If this
+     *    option isn't set, then we will use the 'memcache.default_port'
+     *    ini setting. This is 11211 by default.
+     *  - 'weight': This sets the weight of this server in this server
+     *    group. http://php.net/manual/en/function.Memcache-addServer.php
+     *    contains more information about the weight option.
+     *  - 'timeout': The timeout for this server. By default, the timeout
+     *    is 3 seconds.
+     *
+     * 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'),
+     *     ),
+     * ),
+     *
+     * 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' => array(
+        array(
+            array('hostname' => 'localhost'),
+        ),
+    ),
+
+    /*
+     * This value allows you to set a prefix for memcache-keys. The default
+     * for this value is 'SimpleSAMLphp', which is fine in most cases.
+     *
+     * When running multiple instances of SSP on the same host, and more
+     * than one instance is using memcache, you probably want to assign
+     * a unique value per instance to this setting to avoid data collision.
+     */
+    'memcache_store.prefix' => null,
+
+    /*
+     * This value is the duration data should be stored in memcache. Data
+     * will be dropped from the memcache servers when this time expires.
+     * The time will be reset every time the data is written to the
+     * memcache servers.
+     *
+     * This value should always be larger than the 'session.duration'
+     * option. Not doing this may result in the session being deleted from
+     * the memcache servers while it is still in use.
+     *
+     * Set this value to 0 if you don't want data to expire.
+     *
+     * Note: The oldest data will always be deleted if the memcache server
+     * runs out of storage space.
+     */
+    'memcache_store.expires' => 36 * (60 * 60), // 36 hours.
+
+    /*
+     * Should signing of generated metadata be enabled by default.
+     *
+     * Metadata signing can also be enabled for a individual SP or IdP by setting the
+     * same option in the metadata for the SP or IdP.
+     */
+    'metadata.sign.enable' => false,
+
+    /*
+     * The default key & certificate which should be used to sign generated metadata. These
+     * are files stored in the cert dir.
+     * These values can be overridden by the options with the same names in the SP or
+     * IdP metadata.
+     *
+     * If these aren't specified here or in the metadata for the SP or IdP, then
+     * the 'certificate' and 'privatekey' option in the metadata will be used.
+     * if those aren't set, signing of metadata will fail.
+     */
+    'metadata.sign.privatekey' => null,
+    'metadata.sign.privatekey_pass' => null,
+    'metadata.sign.certificate' => null,
+
+    /*
+     * Proxy to use for retrieving URLs.
+     *
+     * Example:
+     *   'proxy' => 'tcp://proxy.example.com:5100'
+     */
+    'proxy' => null,
+
+    /*
+     * Array of domains that are allowed when generating links or redirections
+     * to URLs. SimpleSAMLphp will use this option to determine whether to
+     * to consider a given URL valid or not, but you should always validate
+     * URLs obtained from the input on your own (i.e. ReturnTo or RelayState
+     * parameters obtained from the $_REQUEST array).
+     *
+     * SimpleSAMLphp will automatically add your own domain (either by checking
+     * it dynamically, or by using the domain defined in the 'baseurlpath'
+     * directive, the latter having precedence) to the list of trusted domains,
+     * in case this option is NOT set to NULL. In that case, you are explicitly
+     * telling SimpleSAMLphp to verify URLs.
+     *
+     * Set to an empty array to disallow ALL redirections or links pointing to
+     * an external URL other than your own domain. This is the default behaviour.
+     *
+     * Set to NULL to disable checking of URLs. DO NOT DO THIS UNLESS YOU KNOW
+     * WHAT YOU ARE DOING!
+     *
+     * Example:
+     *   'trusted.url.domains' => array('sp.example.com', 'app.example.com'),
+     */
+    'trusted.url.domains' => array(),
+
+    'validate.authnrequest' => true,
+);
diff --git a/simplesamlphp/metadata/saml20-idp-hosted.php b/simplesamlphp/metadata/saml20-idp-hosted.php
new file mode 100644
index 0000000..7413076
--- /dev/null
+++ b/simplesamlphp/metadata/saml20-idp-hosted.php
@@ -0,0 +1,25 @@
+<?php
+
+$metadata['http://localhost:8080/simplesaml/saml2/idp/metadata.php'] = array(
+    'host' => 'localhost',
+    'auth' => 'example-userpass',
+    'entityid' => 'http://localhost:8080/simplesaml/saml2/idp/metadata.php',
+    'contacts' => array(
+    ),
+    'metadata-set' => 'saml20-idp-hosted',
+    'SingleSignOnServiceBinding' => array(
+        0 => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+        1 => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+    ),
+    'SingleLogoutServiceBinding' => array(
+        0 => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+        1 => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+    ),
+    'ArtifactResolutionService' => array(
+    ),
+    'NameIDFormats' => array(
+        0 => 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
+    ),
+    'privatekey' => 'server.pem',
+    'certificate' => 'server.crt',
+);
diff --git a/simplesamlphp/metadata/saml20-sp-remote.php b/simplesamlphp/metadata/saml20-sp-remote.php
new file mode 100644
index 0000000..c9d5936
--- /dev/null
+++ b/simplesamlphp/metadata/saml20-sp-remote.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * SAML 2.0 remote SP metadata for SimpleSAMLphp.
+ *
+ * See: https://simplesamlphp.org/docs/stable/simplesamlphp-reference-sp-remote
+ */
+
+$metadata['gerritSaml'] = array(
+    'entityid' => 'gerritSaml',
+    'contacts' => array(
+    ),
+    'metadata-set' => 'saml20-sp-remote',
+    'expire' => 2249280670,
+    'AssertionConsumerService' => array(
+        0 => array(
+            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+            'Location' => 'http://localhost:8081/plugins/saml/callback?client_name=SAML2Client',
+            'index' => 0,
+        ),
+    ),
+    'SingleLogoutService' => array(
+        0 => array(
+            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST',
+            'Location' => 'http://localhost:8081/plugins/saml/callback?client_name=SAML2Client&logoutendpoint=true',
+        ),
+        1 => array(
+            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign',
+            'Location' => 'http://localhost:8081/plugins/saml/callback?client_name=SAML2Client&logoutendpoint=true',
+        ),
+        2 => array(
+            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
+            'Location' => 'http://localhost:8081/plugins/saml/callback?client_name=SAML2Client&logoutendpoint=true',
+        ),
+        3 => array(
+            'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP',
+            'Location' => 'http://localhost:8081/plugins/saml/callback?client_name=SAML2Client&logoutendpoint=true',
+        ),
+    ),
+    'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
+    'authproc' => array(
+        1 => array(
+            'class' => 'saml:AttributeNameID',
+            'attribute' => 'username',
+            'Format' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
+        ),
+    ),
+    'keys' => array(
+        0 => array(
+            'encryption' => false,
+            'signing' => true,
+            'type' => 'X509Certificate',
+            'X509Certificate' => 'MIIDdzCCAl+gAwIBAgIEFJJc0DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAw
+  DgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYD
+  VQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTIxMDQwODA2MDE1MVoXDTIyMDQwODA2
+  MDE1MVowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5r
+  bm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93
+  bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKL01jq3y+1g7qN2+ieNQ7VjRJpLNMgy
+  yOmdQ28kWbNNemB5mO/LqpU5kCfZJRSvwh4rSoZxOG3FkChOhUyZMr9SBFHNB1HGAE/JSh+1g2eh
+  x315LBvKKB5EMfsWB4fi37nEkLmlrV6BLl0TcKCoQTIn4DkHsb5OmUu/tqVE2u2w0G6YxZRu2CmL
+  acbaTTS6HAgJQmsZBpVq+NfyqOyabV3aYvpE5oWsVNRRkFrEeNQ6sQGTVUkjuvMTHLgI40DEg1Is
+  vPSrT2K5FZ/ImWZwzWWzj3htJJ938KfXygISunuNce7CUSldWnC8oUDbTnb+TpXVFG30xX6P2uG3
+  NcULFdcCAwEAAaMhMB8wHQYDVR0OBBYEFHQpiu87m0wXW5uiGQMewPZsamxYMA0GCSqGSIb3DQEB
+  CwUAA4IBAQCYdqwk+Iv1/bCZi8+MuuFKparAydfEG+eFyOPUPdP9MhmuK7xgSpgu282rLTeQ+izg
+  BgFOMzRS1EAe07y878eovUEGi+YYtFWORp3G/7Pa5ZFVEZ/nS/BDYhYzVF59EnmDd9qf0fFSnv9B
+  FZc98Pe1vzc0XbwScOMtpZMkA3jCqtV8jITNvD+79SaFkiDE8m1xp8dBSBxJN9H1CgfOx5cbRbVd
+  UFkH8KpwVwzlR8MjnTdcq7JQPX5f78aCJ1Wl3t5yz5Gs9+WLa1tPGn+ucb8qkONeSlCUgQ3x5C+1
+  wzhwl/zxYfJfODzCtjH3ObQfkoBDUF2b5OxkldgsOxl3R6he',
+        ),
+        1 => array(
+            'encryption' => true,
+            'signing' => false,
+            'type' => 'X509Certificate',
+            'X509Certificate' => 'MIIDdzCCAl+gAwIBAgIEFJJc0DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdVbmtub3duMRAw
+  DgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQKEwdVbmtub3duMRAwDgYD
+  VQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMB4XDTIxMDQwODA2MDE1MVoXDTIyMDQwODA2
+  MDE1MVowbDEQMA4GA1UEBhMHVW5rbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5r
+  bm93bjEQMA4GA1UEChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93
+  bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKL01jq3y+1g7qN2+ieNQ7VjRJpLNMgy
+  yOmdQ28kWbNNemB5mO/LqpU5kCfZJRSvwh4rSoZxOG3FkChOhUyZMr9SBFHNB1HGAE/JSh+1g2eh
+  x315LBvKKB5EMfsWB4fi37nEkLmlrV6BLl0TcKCoQTIn4DkHsb5OmUu/tqVE2u2w0G6YxZRu2CmL
+  acbaTTS6HAgJQmsZBpVq+NfyqOyabV3aYvpE5oWsVNRRkFrEeNQ6sQGTVUkjuvMTHLgI40DEg1Is
+  vPSrT2K5FZ/ImWZwzWWzj3htJJ938KfXygISunuNce7CUSldWnC8oUDbTnb+TpXVFG30xX6P2uG3
+  NcULFdcCAwEAAaMhMB8wHQYDVR0OBBYEFHQpiu87m0wXW5uiGQMewPZsamxYMA0GCSqGSIb3DQEB
+  CwUAA4IBAQCYdqwk+Iv1/bCZi8+MuuFKparAydfEG+eFyOPUPdP9MhmuK7xgSpgu282rLTeQ+izg
+  BgFOMzRS1EAe07y878eovUEGi+YYtFWORp3G/7Pa5ZFVEZ/nS/BDYhYzVF59EnmDd9qf0fFSnv9B
+  FZc98Pe1vzc0XbwScOMtpZMkA3jCqtV8jITNvD+79SaFkiDE8m1xp8dBSBxJN9H1CgfOx5cbRbVd
+  UFkH8KpwVwzlR8MjnTdcq7JQPX5f78aCJ1Wl3t5yz5Gs9+WLa1tPGn+ucb8qkONeSlCUgQ3x5C+1
+  wzhwl/zxYfJfODzCtjH3ObQfkoBDUF2b5OxkldgsOxl3R6he',
+        ),
+    ),
+    'validate.authnrequest' => false,
+    'validate.logout' => false,
+    'saml20.sign.assertion' => false,
+);