Add support of Keystone OIDC Federation

Some parameters are optional while some other ones are exlusive between each other.

  keystone:
    server:
      auth_methods:
      - password
      - token
      - saml2
      - oidc
      service_name: apache2
      federation:
        saml2:
          protocol: saml2
          remote_id_attribute: Shib-Identity-Provider
          shib_url_scheme: https
          shib_compat_valid_user: 'on'
        oidc:
          protocol: oidc
          remote_id_attribute: HTTP_OIDC_ISS
          remote_id_attribute_value: https://accounts.google.com
          oidc_claim_prefix: "OIDC-"
          oidc_response_type: id_token
          oidc_scope: "openid email profile"
          oidc_provider_metadata_url: https://accounts.google.com/.well-known/openid-configuration
          oidc_client_id: <openid_client_id>
          oidc_client_secret: <openid_client_secret>
          oidc_crypto_passphrase: openstack
          oidc_redirect_uri: https://key.example.com:5000/v3/auth/OS-FEDERATION/websso/oidc/redirect
          oidc_oauth_introspection_endpoint: https://www.googleapis.com/oauth2/v1/tokeninfo
          oidc_oauth_introspection_token_param_name: access_token
          oidc_oauth_remote_user_claim: user_id
          oidc_ssl_validate_server: 'off'
          oidc_oauth_verify_shared_keys:
            - type: plain
              kid: example1
              key: examplekeycontentplain
            - type: hex
              kid: example2
              key: examplekeycontenthex
          oidc_oauth_verify_cert_files:
            - kid: example3
              filename: /root/example3.crt
            - kid: example4
              filename: /root/example4.crt
        federated_domain_name: Default
        trusted_dashboard:
          - https://${_param:cluster_public_host}/auth/websso/

Change-Id: Ib05b99ebf69b622da7e113f0bd0a5ed8037f5c6b
diff --git a/README.rst b/README.rst
index 10d0a0c..a7f7082 100644
--- a/README.rst
+++ b/README.rst
@@ -323,7 +323,7 @@
         modules:
           - wsgi
 
-Enable Federated keystone
+Enable SAML2 Federated keystone
 
 .. code-block:: yaml
 
@@ -334,13 +334,15 @@
         - token
         - saml2
         federation:
-          protocol: saml2
-          remote_id_attribute: Shib-Identity-Provider
+          saml2:
+            protocol: saml2
+            remote_id_attribute: Shib-Identity-Provider
+            shib_url_scheme: https
+            shib_compat_valid_user: 'on'
           federation_driver: keystone.contrib.federation.backends.sql.Federation
           federated_domain_name: Federated
           trusted_dashboard:
-            - http://${_param:proxy_vip_address_public}/horizon/auth/websso/
-          shib_url_scheme: https
+            - https://${_param:cluster_public_host}/horizon/auth/websso/
     apache:
       server:
         pkgs:
@@ -350,6 +352,48 @@
           - wsgi
           - shib2
 
+Enable OIDC Federated keystone
+
+.. code-block:: yaml
+
+    keystone:
+      server:
+        auth_methods:
+        - password
+        - token
+        - oidc
+        federation:
+        oidc:
+            protocol: oidc
+            remote_id_attribute: HTTP_OIDC_ISS
+            remote_id_attribute_value: https://accounts.google.com
+            oidc_claim_prefix: "OIDC-"
+            oidc_response_type: id_token
+            oidc_scope: "openid email profile"
+            oidc_provider_metadata_url: https://accounts.google.com/.well-known/openid-configuration
+            oidc_client_id: <openid_client_id>
+            oidc_client_secret: <openid_client_secret>
+            oidc_crypto_passphrase: openstack
+            oidc_redirect_uri: https://key.example.com:5000/v3/auth/OS-FEDERATION/websso/oidc/redirect
+            oidc_oauth_introspection_endpoint: https://www.googleapis.com/oauth2/v1/tokeninfo
+            oidc_oauth_introspection_token_param_name: access_token
+            oidc_oauth_remote_user_claim: user_id
+            oidc_ssl_validate_server: 'off'
+        federated_domain_name: Federated
+        federation_driver: keystone.contrib.federation.backends.sql.Federation
+        trusted_dashboard:
+          - https://${_param:cluster_public_host}/auth/websso/
+    apache:
+      server:
+        pkgs:
+          - apache2
+          - libapache2-mod-auth-openidc
+        modules:
+          - wsgi
+          - auth_openidc
+
+Notes: Ubuntu Trusty repository doesn't contain libapache2-mod-auth-openidc package. Additonal repository should be added to source list.
+
 Use a custom identity driver with custom options
 
 .. code-block:: yaml
diff --git a/keystone/files/liberty/keystone.conf.Debian b/keystone/files/liberty/keystone.conf.Debian
index 8f8fcc2..1a3ba25 100644
--- a/keystone/files/liberty/keystone.conf.Debian
+++ b/keystone/files/liberty/keystone.conf.Debian
@@ -309,10 +309,13 @@
 {% if server.auth_methods is defined %}
 methods = {{ server.auth_methods |join(',') }}
 {%- endif %}
-{% if server.federation is defined %}
-{{ server.federation.protocol }} = keystone.auth.plugins.mapped.Mapped
-{%- endif %}
 
+{%- if server.get('federation', {}).oidc is defined %}
+{{ server.federation.oidc.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+{%- if server.get('federation', {}).saml2 is defined %}
+{{ server.federation.saml2.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
 # Entrypoint for the password auth plugin module in the keystone.auth.password
 # namespace. (string value)
 #password = <None>
@@ -330,11 +333,6 @@
 # namespace. (string value)
 #oauth1 = <None>
 
-{% if server.federation is defined %}
-[{{ server.federation.protocol }}]
-remote_id_attribute = {{ server.federation.remote_id_attribute }}
-{%- endif %}
-
 [cache]
 
 #
@@ -786,6 +784,15 @@
 # Its value may be silently ignored in the future.
 #cert_required = false
 
+{%- if server.get('federation', {}).saml2 is defined %}
+[{{ server.federation.saml2.protocol }}]
+remote_id_attribute = {{ server.federation.saml2.remote_id_attribute }}
+{%- endif %}
+
+{%- if server.get('federation', {}).oidc is defined %}
+[{{ server.federation.oidc.protocol }}]
+remote_id_attribute = {{ server.federation.oidc.remote_id_attribute }}
+{%- endif %}
 
 [federation]
 
@@ -796,7 +803,7 @@
 # Entrypoint for the federation backend driver in the keystone.federation
 # namespace. (string value)
 #driver = sql
-{% if server.federation is defined %}
+{%- if server.get('federation', {}).federation_driver is defined %}
 driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
@@ -814,6 +821,9 @@
 # this name or update an existing domain to this name. You are not advised to
 # change this value unless you really have to. (string value)
 #federated_domain_name = Federated
+{%- if server.get('federation', {}).federated_domain_name is defined %}
+federated_domain_name = {{ server.federation.federated_domain_name }}
+{%- endif %}
 
 # A list of trusted dashboard hosts. Before accepting a Single Sign-On request
 # to return a token, the origin host must be a member of the trusted_dashboard
@@ -821,13 +831,11 @@
 # example: trusted_dashboard=http://acme.com trusted_dashboard=http://beta.com
 # (multi valued)
 #trusted_dashboard =
-{%- if server.federation is defined %}
-{%- if server.federation.trusted_dashboard is defined %}
+{%- if server.get('federation', {}).trusted_dashboard is defined %}
 {%- for dashboard in server.federation.trusted_dashboard %}
 trusted_dashboard = {{ dashboard }}
 {%- endfor %}
 {%- endif %}
-{%- endif %}
 
 # Location of Single Sign-On callback handler, will return a token to a trusted
 # dashboard host. (string value)
diff --git a/keystone/files/liberty/wsgi-keystone.conf b/keystone/files/liberty/wsgi-keystone.conf
index 51f19d0..c461e3a 100644
--- a/keystone/files/liberty/wsgi-keystone.conf
+++ b/keystone/files/liberty/wsgi-keystone.conf
@@ -1,27 +1,99 @@
 {%- from "keystone/map.jinja" import server with context %}
 {%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
-Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
-Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
+{% macro setup_oidc() -%}
+    SetEnv HTTP_OIDC_ISS {{ server.federation.oidc.remote_id_attribute_value }}
+    {% if server.federation.oidc.oidc_claim_prefix is defined %}
+    OIDCClaimPrefix "{{ server.federation.oidc.oidc_claim_prefix }}"
+    {%- endif %}
+    OIDCClientID "{{ server.federation.oidc.oidc_client_id}}"
+    {% if server.federation.oidc.oidc_client_secret is defined %}
+    OIDCClientSecret "{{ server.federation.oidc.oidc_client_secret }}"
+    {%- endif %}
+    OIDCCryptoPassphrase "{{ server.federation.oidc.oidc_crypto_passphrase }}"
+    OIDCRedirectURI "{{ server.federation.oidc.oidc_redirect_uri }}"
+    {% if server.federation.oidc.oidc_provider_metadata_url is defined %}
+    OIDCProviderMetadataURL "{{ server.federation.oidc.oidc_provider_metadata_url }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_response_type is defined %}
+    OIDCResponseType "{{ server.federation.oidc.oidc_response_type }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_scope is defined %}
+    OIDCScope "{{ server.federation.oidc.oidc_scope }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_ssl_validate_server is defined %}
+    OIDCSSLValidateServer "{{ server.federation.oidc.oidc_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_ssl_validate_server is defined %}
+    OIDCOAuthSSLValidateServer "{{ server.federation.oidc.oidc_oauth_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_endpoint is defined %}
+    OIDCOAuthIntrospectionEndpoint "{{ server.federation.oidc.oidc_oauth_introspection_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_token_param_name is defined %}
+    OIDCOAuthIntrospectionTokenParamName "{{ server.federation.oidc.oidc_oauth_introspection_token_param_name }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_remote_user_claim is defined %}
+    OIDCOAuthRemoteUserClaim "{{ server.federation.oidc.oidc_oauth_remote_user_claim }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_verify_jwks_uri is defined %}
+    OIDCOAuthVerifyJwksUri "{{ server.federation.oidc.oidc_oauth_verify_jwks_uri }}"
+    {%- endif %}
+    {% if server.federation.oidc.odic_token_iat_slack is defined %}
+    OIDCIDTokenIatSlack "{{ server.federation.oidc.odic_token_iat_slack }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_issuer is defined %}
+    OIDCProviderIssuer "{{ server.federation.oidc.oidc_provider_issuer }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_authorization_endpoint is defined %}
+    OIDCProviderAuthorizationEndpoint "{{ server.federation.oidc.oidc_provider_authorization_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint is defined %}
+    OIDCProviderTokenEndpoint "{{ server.federation.oidc.oidc_provider_token_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint_auth is defined %}
+    OIDCProviderTokenEndpointAuth "{{ server.federation.oidc.oidc_provider_token_endpoint_auth }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_user_info_endpoint is defined %}
+    OIDCProviderUserInfoEndpoint "{{ server.federation.oidc.oidc_provider_user_info_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_jwks_uri is defined %}
+    OIDCProviderJwksUri "{{ server.federation.oidc.oidc_provider_jwks_uri }}"
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_shared_keys is defined %}
+    {%- set shared_keys_list = [] %}
+    {%- for shared_key_def in server.federation.oidc.oidc_oauth_verify_shared_keys %}
+    {%- do shared_keys_list.append("\""+shared_key_def.type+"#"+shared_key_def.kid+"#"+shared_key_def.key+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifySharedKeys {{ shared_keys_list|join(" ") }}
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_cert_files is defined %}
+    {%- set cert_files_list = [] %}
+    {%- for cert_file_def in server.federation.oidc.oidc_oauth_verify_cert_files %}
+    {%- do cert_files_list.append("\""+cert_file_def.kid+"#"+cert_file_def.filename+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifyCertFiles {{ cert_files_list|join(" ") }}
+    {%- endif %}
 
-<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000>
-{%- include "apache/files/_name.conf" %}
-{%- include "apache/files/_ssl.conf" %}
-{%- include "apache/files/_locations.conf" %}
-
-    WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
-    WSGIProcessGroup keystone-public
-    WSGIScriptAlias / /usr/bin/keystone-wsgi-public
-    WSGIApplicationGroup %{GLOBAL}
-    WSGIPassAuthorization On
-    ErrorLogFormat "%{cu}t %M"
-{%- include "apache/files/_log.conf" %}
-
-    <Directory /usr/bin>
-      Require all granted
-    </Directory>
-
-    {% if server.federation is defined %}
-    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/oidc/auth>
+      AuthType oauth20
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/websso/oidc">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/oidc/websso">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+{% macro setup_saml2() -%}
+    {% if server.federation.saml2.shib_url_scheme is defined %}
+    ShibURLScheme {{ server.federation.saml2.shib_url_scheme }}
+    {%- endif %}
+    {% if server.federation.saml2.shib_compat_valid_user is defined %}
+    ShibCompatValidUser {{ server.federation.saml2.shib_compat_valid_user }}
+    {%- endif %}
     <Location /Shibboleth.sso>
       SetHandler shib
     </Location>
@@ -43,6 +115,34 @@
       ShibExportAssertion Off
       Require valid-user
     </LocationMatch>
+{% endmacro -%}
+
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
+Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
+
+<VirtualHost {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000>
+{%- include "apache/files/_name.conf" %}
+{%- include "apache/files/_ssl.conf" %}
+{%- include "apache/files/_locations.conf" %}
+
+    WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}
+    WSGIProcessGroup keystone-public
+    WSGIScriptAlias / /usr/bin/keystone-wsgi-public
+    WSGIApplicationGroup %{GLOBAL}
+    WSGIPassAuthorization On
+    ErrorLogFormat "%{cu}t %M"
+{%- include "apache/files/_log.conf" %}
+
+    <Directory /usr/bin>
+      Require all granted
+    </Directory>
+
+    {% if server.get('federation', {}).saml2 is defined %}
+    WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
+    {{ setup_saml2() }}
+    {%- endif %}
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
@@ -64,29 +164,13 @@
       Require all granted
     </Directory>
 
-    {% if server.federation is defined %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
diff --git a/keystone/files/mitaka/keystone.conf.Debian b/keystone/files/mitaka/keystone.conf.Debian
index 1267de1..d834c20 100644
--- a/keystone/files/mitaka/keystone.conf.Debian
+++ b/keystone/files/mitaka/keystone.conf.Debian
@@ -357,8 +357,12 @@
 {% if server.auth_methods is defined %}
 methods = {{ server.auth_methods |join(',') }}
 {%- endif %}
-{% if server.federation is defined %}
-{{ server.federation.protocol }} = keystone.auth.plugins.mapped.Mapped
+
+{%- if server.get('federation', {}).oidc is defined %}
+{{ server.federation.oidc.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+{%- if server.get('federation', {}).saml2 is defined %}
+{{ server.federation.saml2.protocol }} = keystone.auth.plugins.mapped.Mapped
 {%- endif %}
 
 # Entrypoint for the password auth plugin module in the keystone.auth.password
@@ -848,6 +852,15 @@
 # Its value may be silently ignored in the future.
 #cert_required = false
 
+{%- if server.get('federation', {}).saml2 is defined %}
+[{{ server.federation.saml2.protocol }}]
+remote_id_attribute = {{ server.federation.saml2.remote_id_attribute }}
+{%- endif %}
+
+{%- if server.get('federation', {}).oidc is defined %}
+[{{ server.federation.oidc.protocol }}]
+remote_id_attribute = {{ server.federation.oidc.remote_id_attribute }}
+{%- endif %}
 
 [federation]
 
@@ -870,9 +883,6 @@
 # environment (e.g. if using the mod_shib plugin this value is `Shib-Identity-
 # Provider`). (string value)
 #remote_id_attribute = <None>
-{%- if server.federation is defined %}
-remote_id_attribute = {{ server.federation.remote_id_attribute }}
-{%- endif %}
 
 # A domain name that is reserved to allow federated ephemeral users to have a
 # domain concept. Note that an admin will not be able to create a domain with
diff --git a/keystone/files/mitaka/wsgi-keystone.conf b/keystone/files/mitaka/wsgi-keystone.conf
index aff6ff3..b31b5c5 100644
--- a/keystone/files/mitaka/wsgi-keystone.conf
+++ b/keystone/files/mitaka/wsgi-keystone.conf
@@ -1,5 +1,122 @@
 {%- from "keystone/map.jinja" import server with context %}
 {%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+{% macro setup_oidc() -%}
+    SetEnv HTTP_OIDC_ISS {{ server.federation.oidc.remote_id_attribute_value }}
+    {% if server.federation.oidc.oidc_claim_prefix is defined %}
+    OIDCClaimPrefix "{{ server.federation.oidc.oidc_claim_prefix }}"
+    {%- endif %}
+    OIDCClientID "{{ server.federation.oidc.oidc_client_id}}"
+    {% if server.federation.oidc.oidc_client_secret is defined %}
+    OIDCClientSecret "{{ server.federation.oidc.oidc_client_secret }}"
+    {%- endif %}
+    OIDCCryptoPassphrase "{{ server.federation.oidc.oidc_crypto_passphrase }}"
+    OIDCRedirectURI "{{ server.federation.oidc.oidc_redirect_uri }}"
+    {% if server.federation.oidc.oidc_provider_metadata_url is defined %}
+    OIDCProviderMetadataURL "{{ server.federation.oidc.oidc_provider_metadata_url }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_response_type is defined %}
+    OIDCResponseType "{{ server.federation.oidc.oidc_response_type }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_scope is defined %}
+    OIDCScope "{{ server.federation.oidc.oidc_scope }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_ssl_validate_server is defined %}
+    OIDCSSLValidateServer "{{ server.federation.oidc.oidc_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_ssl_validate_server is defined %}
+    OIDCOAuthSSLValidateServer "{{ server.federation.oidc.oidc_oauth_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_endpoint is defined %}
+    OIDCOAuthIntrospectionEndpoint "{{ server.federation.oidc.oidc_oauth_introspection_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_token_param_name is defined %}
+    OIDCOAuthIntrospectionTokenParamName "{{ server.federation.oidc.oidc_oauth_introspection_token_param_name }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_remote_user_claim is defined %}
+    OIDCOAuthRemoteUserClaim "{{ server.federation.oidc.oidc_oauth_remote_user_claim }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_verify_jwks_uri is defined %}
+    OIDCOAuthVerifyJwksUri "{{ server.federation.oidc.oidc_oauth_verify_jwks_uri }}"
+    {%- endif %}
+    {% if server.federation.oidc.odic_token_iat_slack is defined %}
+    OIDCIDTokenIatSlack "{{ server.federation.oidc.odic_token_iat_slack }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_issuer is defined %}
+    OIDCProviderIssuer "{{ server.federation.oidc.oidc_provider_issuer }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_authorization_endpoint is defined %}
+    OIDCProviderAuthorizationEndpoint "{{ server.federation.oidc.oidc_provider_authorization_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint is defined %}
+    OIDCProviderTokenEndpoint "{{ server.federation.oidc.oidc_provider_token_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint_auth is defined %}
+    OIDCProviderTokenEndpointAuth "{{ server.federation.oidc.oidc_provider_token_endpoint_auth }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_user_info_endpoint is defined %}
+    OIDCProviderUserInfoEndpoint "{{ server.federation.oidc.oidc_provider_user_info_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_jwks_uri is defined %}
+    OIDCProviderJwksUri "{{ server.federation.oidc.oidc_provider_jwks_uri }}"
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_shared_keys is defined %}
+    {%- set shared_keys_list = [] %}
+    {%- for shared_key_def in server.federation.oidc.oidc_oauth_verify_shared_keys %}
+    {%- do shared_keys_list.append("\""+shared_key_def.type+"#"+shared_key_def.kid+"#"+shared_key_def.key+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifySharedKeys {{ shared_keys_list|join(" ") }}
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_cert_files is defined %}
+    {%- set cert_files_list = [] %}
+    {%- for cert_file_def in server.federation.oidc.oidc_oauth_verify_cert_files %}
+    {%- do cert_files_list.append("\""+cert_file_def.kid+"#"+cert_file_def.filename+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifyCertFiles {{ cert_files_list|join(" ") }}
+    {%- endif %}
+
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/oidc/auth>
+      AuthType oauth20
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/websso/oidc">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/oidc/websso">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+{% macro setup_saml2() -%}
+    {% if server.federation.saml2.shib_url_scheme is defined %}
+    ShibURLScheme {{ server.federation.saml2.shib_url_scheme }}
+    {%- endif %}
+    {% if server.federation.saml2.shib_compat_valid_user is defined %}
+    ShibCompatValidUser {{ server.federation.saml2.shib_compat_valid_user }}
+    {%- endif %}
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
 
@@ -29,32 +146,12 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
@@ -85,32 +182,13 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
diff --git a/keystone/files/newton/keystone.conf.Debian b/keystone/files/newton/keystone.conf.Debian
index dfccfbf..a464ac3 100644
--- a/keystone/files/newton/keystone.conf.Debian
+++ b/keystone/files/newton/keystone.conf.Debian
@@ -417,10 +417,13 @@
 {% if server.auth_methods is defined %}
 methods = {{ server.auth_methods |join(',') }}
 {%- endif %}
-{% if server.federation is defined %}
-{{ server.federation.protocol }} = keystone.auth.plugins.mapped.Mapped
-{%- endif %}
 
+{%- if server.get('federation', {}).oidc is defined %}
+{{ server.federation.oidc.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+{%- if server.get('federation', {}).saml2 is defined %}
+{{ server.federation.saml2.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
 # Entry point for the password auth plugin module in the
 # `keystone.auth.password` namespace. You do not need to set this unless you
 # are overriding keystone's own password authentication plugin. (string value)
@@ -902,6 +905,15 @@
 #admin_port = 35357
 admin_port = 35357
 
+{%- if server.get('federation', {}).saml2 is defined %}
+[{{ server.federation.saml2.protocol }}]
+remote_id_attribute = {{ server.federation.saml2.remote_id_attribute }}
+{%- endif %}
+
+{%- if server.get('federation', {}).oidc is defined %}
+[{{ server.federation.oidc.protocol }}]
+remote_id_attribute = {{ server.federation.oidc.remote_id_attribute }}
+{%- endif %}
 
 [federation]
 
@@ -927,9 +939,6 @@
 # `mod_auth_openidc`, this could be `HTTP_OIDC_ISS`. For `mod_auth_mellon`,
 # this could be `MELLON_IDP`. (string value)
 #remote_id_attribute = <None>
-{%- if server.federation is defined %}
-remote_id_attribute = {{ server.federation.remote_id_attribute }}
-{%- endif %}
 
 # An arbitrary domain name that is reserved to allow federated ephemeral users
 # to have a domain concept. Note that an admin will not be able to create a
diff --git a/keystone/files/newton/wsgi-keystone.conf b/keystone/files/newton/wsgi-keystone.conf
index aff6ff3..b31b5c5 100644
--- a/keystone/files/newton/wsgi-keystone.conf
+++ b/keystone/files/newton/wsgi-keystone.conf
@@ -1,5 +1,122 @@
 {%- from "keystone/map.jinja" import server with context %}
 {%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+{% macro setup_oidc() -%}
+    SetEnv HTTP_OIDC_ISS {{ server.federation.oidc.remote_id_attribute_value }}
+    {% if server.federation.oidc.oidc_claim_prefix is defined %}
+    OIDCClaimPrefix "{{ server.federation.oidc.oidc_claim_prefix }}"
+    {%- endif %}
+    OIDCClientID "{{ server.federation.oidc.oidc_client_id}}"
+    {% if server.federation.oidc.oidc_client_secret is defined %}
+    OIDCClientSecret "{{ server.federation.oidc.oidc_client_secret }}"
+    {%- endif %}
+    OIDCCryptoPassphrase "{{ server.federation.oidc.oidc_crypto_passphrase }}"
+    OIDCRedirectURI "{{ server.federation.oidc.oidc_redirect_uri }}"
+    {% if server.federation.oidc.oidc_provider_metadata_url is defined %}
+    OIDCProviderMetadataURL "{{ server.federation.oidc.oidc_provider_metadata_url }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_response_type is defined %}
+    OIDCResponseType "{{ server.federation.oidc.oidc_response_type }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_scope is defined %}
+    OIDCScope "{{ server.federation.oidc.oidc_scope }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_ssl_validate_server is defined %}
+    OIDCSSLValidateServer "{{ server.federation.oidc.oidc_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_ssl_validate_server is defined %}
+    OIDCOAuthSSLValidateServer "{{ server.federation.oidc.oidc_oauth_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_endpoint is defined %}
+    OIDCOAuthIntrospectionEndpoint "{{ server.federation.oidc.oidc_oauth_introspection_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_token_param_name is defined %}
+    OIDCOAuthIntrospectionTokenParamName "{{ server.federation.oidc.oidc_oauth_introspection_token_param_name }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_remote_user_claim is defined %}
+    OIDCOAuthRemoteUserClaim "{{ server.federation.oidc.oidc_oauth_remote_user_claim }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_verify_jwks_uri is defined %}
+    OIDCOAuthVerifyJwksUri "{{ server.federation.oidc.oidc_oauth_verify_jwks_uri }}"
+    {%- endif %}
+    {% if server.federation.oidc.odic_token_iat_slack is defined %}
+    OIDCIDTokenIatSlack "{{ server.federation.oidc.odic_token_iat_slack }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_issuer is defined %}
+    OIDCProviderIssuer "{{ server.federation.oidc.oidc_provider_issuer }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_authorization_endpoint is defined %}
+    OIDCProviderAuthorizationEndpoint "{{ server.federation.oidc.oidc_provider_authorization_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint is defined %}
+    OIDCProviderTokenEndpoint "{{ server.federation.oidc.oidc_provider_token_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint_auth is defined %}
+    OIDCProviderTokenEndpointAuth "{{ server.federation.oidc.oidc_provider_token_endpoint_auth }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_user_info_endpoint is defined %}
+    OIDCProviderUserInfoEndpoint "{{ server.federation.oidc.oidc_provider_user_info_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_jwks_uri is defined %}
+    OIDCProviderJwksUri "{{ server.federation.oidc.oidc_provider_jwks_uri }}"
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_shared_keys is defined %}
+    {%- set shared_keys_list = [] %}
+    {%- for shared_key_def in server.federation.oidc.oidc_oauth_verify_shared_keys %}
+    {%- do shared_keys_list.append("\""+shared_key_def.type+"#"+shared_key_def.kid+"#"+shared_key_def.key+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifySharedKeys {{ shared_keys_list|join(" ") }}
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_cert_files is defined %}
+    {%- set cert_files_list = [] %}
+    {%- for cert_file_def in server.federation.oidc.oidc_oauth_verify_cert_files %}
+    {%- do cert_files_list.append("\""+cert_file_def.kid+"#"+cert_file_def.filename+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifyCertFiles {{ cert_files_list|join(" ") }}
+    {%- endif %}
+
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/oidc/auth>
+      AuthType oauth20
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/websso/oidc">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/oidc/websso">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+{% macro setup_saml2() -%}
+    {% if server.federation.saml2.shib_url_scheme is defined %}
+    ShibURLScheme {{ server.federation.saml2.shib_url_scheme }}
+    {%- endif %}
+    {% if server.federation.saml2.shib_compat_valid_user is defined %}
+    ShibCompatValidUser {{ server.federation.saml2.shib_compat_valid_user }}
+    {%- endif %}
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
 
@@ -29,32 +146,12 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
@@ -85,32 +182,13 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
diff --git a/keystone/files/ocata/keystone.conf.Debian b/keystone/files/ocata/keystone.conf.Debian
index f5c5a12..5374c5d 100644
--- a/keystone/files/ocata/keystone.conf.Debian
+++ b/keystone/files/ocata/keystone.conf.Debian
@@ -484,8 +484,12 @@
 {% if server.auth_methods is defined %}
 methods = {{ server.auth_methods |join(',') }}
 {%- endif %}
-{% if server.federation is defined %}
-{{ server.federation.protocol }} = keystone.auth.plugins.mapped.Mapped
+
+{%- if server.get('federation', {}).oidc is defined %}
+{{ server.federation.oidc.protocol }} = keystone.auth.plugins.mapped.Mapped
+{%- endif %}
+{%- if server.get('federation', {}).saml2 is defined %}
+{{ server.federation.saml2.protocol }} = keystone.auth.plugins.mapped.Mapped
 {%- endif %}
 
 # Entry point for the password auth plugin module in the
@@ -974,6 +978,15 @@
 # Specifies the distribution of the keystone server. (string value)
 #Distribution = Ubuntu
 
+{%- if server.get('federation', {}).saml2 is defined %}
+[{{ server.federation.saml2.protocol }}]
+remote_id_attribute = {{ server.federation.saml2.remote_id_attribute }}
+{%- endif %}
+
+{%- if server.get('federation', {}).oidc is defined %}
+[{{ server.federation.oidc.protocol }}]
+remote_id_attribute = {{ server.federation.oidc.remote_id_attribute }}
+{%- endif %}
 
 [federation]
 
@@ -999,9 +1012,6 @@
 # `mod_auth_openidc`, this could be `HTTP_OIDC_ISS`. For `mod_auth_mellon`,
 # this could be `MELLON_IDP`. (string value)
 #remote_id_attribute = <None>
-{%- if server.federation is defined %}
-remote_id_attribute = {{ server.federation.remote_id_attribute }}
-{%- endif %}
 
 # An arbitrary domain name that is reserved to allow federated ephemeral users
 # to have a domain concept. Note that an admin will not be able to create a
diff --git a/keystone/files/ocata/wsgi-keystone.conf b/keystone/files/ocata/wsgi-keystone.conf
index aff6ff3..b31b5c5 100644
--- a/keystone/files/ocata/wsgi-keystone.conf
+++ b/keystone/files/ocata/wsgi-keystone.conf
@@ -1,5 +1,122 @@
 {%- from "keystone/map.jinja" import server with context %}
 {%- set site = salt['pillar.get']('apache:server:site:'+site_name) %}
+{% macro setup_oidc() -%}
+    SetEnv HTTP_OIDC_ISS {{ server.federation.oidc.remote_id_attribute_value }}
+    {% if server.federation.oidc.oidc_claim_prefix is defined %}
+    OIDCClaimPrefix "{{ server.federation.oidc.oidc_claim_prefix }}"
+    {%- endif %}
+    OIDCClientID "{{ server.federation.oidc.oidc_client_id}}"
+    {% if server.federation.oidc.oidc_client_secret is defined %}
+    OIDCClientSecret "{{ server.federation.oidc.oidc_client_secret }}"
+    {%- endif %}
+    OIDCCryptoPassphrase "{{ server.federation.oidc.oidc_crypto_passphrase }}"
+    OIDCRedirectURI "{{ server.federation.oidc.oidc_redirect_uri }}"
+    {% if server.federation.oidc.oidc_provider_metadata_url is defined %}
+    OIDCProviderMetadataURL "{{ server.federation.oidc.oidc_provider_metadata_url }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_response_type is defined %}
+    OIDCResponseType "{{ server.federation.oidc.oidc_response_type }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_scope is defined %}
+    OIDCScope "{{ server.federation.oidc.oidc_scope }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_ssl_validate_server is defined %}
+    OIDCSSLValidateServer "{{ server.federation.oidc.oidc_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_ssl_validate_server is defined %}
+    OIDCOAuthSSLValidateServer "{{ server.federation.oidc.oidc_oauth_ssl_validate_server }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_endpoint is defined %}
+    OIDCOAuthIntrospectionEndpoint "{{ server.federation.oidc.oidc_oauth_introspection_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_introspection_token_param_name is defined %}
+    OIDCOAuthIntrospectionTokenParamName "{{ server.federation.oidc.oidc_oauth_introspection_token_param_name }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_remote_user_claim is defined %}
+    OIDCOAuthRemoteUserClaim "{{ server.federation.oidc.oidc_oauth_remote_user_claim }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_oauth_verify_jwks_uri is defined %}
+    OIDCOAuthVerifyJwksUri "{{ server.federation.oidc.oidc_oauth_verify_jwks_uri }}"
+    {%- endif %}
+    {% if server.federation.oidc.odic_token_iat_slack is defined %}
+    OIDCIDTokenIatSlack "{{ server.federation.oidc.odic_token_iat_slack }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_issuer is defined %}
+    OIDCProviderIssuer "{{ server.federation.oidc.oidc_provider_issuer }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_authorization_endpoint is defined %}
+    OIDCProviderAuthorizationEndpoint "{{ server.federation.oidc.oidc_provider_authorization_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint is defined %}
+    OIDCProviderTokenEndpoint "{{ server.federation.oidc.oidc_provider_token_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_token_endpoint_auth is defined %}
+    OIDCProviderTokenEndpointAuth "{{ server.federation.oidc.oidc_provider_token_endpoint_auth }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_user_info_endpoint is defined %}
+    OIDCProviderUserInfoEndpoint "{{ server.federation.oidc.oidc_provider_user_info_endpoint }}"
+    {%- endif %}
+    {% if server.federation.oidc.oidc_provider_jwks_uri is defined %}
+    OIDCProviderJwksUri "{{ server.federation.oidc.oidc_provider_jwks_uri }}"
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_shared_keys is defined %}
+    {%- set shared_keys_list = [] %}
+    {%- for shared_key_def in server.federation.oidc.oidc_oauth_verify_shared_keys %}
+    {%- do shared_keys_list.append("\""+shared_key_def.type+"#"+shared_key_def.kid+"#"+shared_key_def.key+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifySharedKeys {{ shared_keys_list|join(" ") }}
+    {%- endif %}
+    {%- if server.federation.oidc.oidc_oauth_verify_cert_files is defined %}
+    {%- set cert_files_list = [] %}
+    {%- for cert_file_def in server.federation.oidc.oidc_oauth_verify_cert_files %}
+    {%- do cert_files_list.append("\""+cert_file_def.kid+"#"+cert_file_def.filename+"\"") %}
+    {%- endfor %}
+    OIDCOAuthVerifyCertFiles {{ cert_files_list|join(" ") }}
+    {%- endif %}
+
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/oidc/auth>
+      AuthType oauth20
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/websso/oidc">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch "/v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/oidc/websso">
+      AuthType openid-connect
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+{% macro setup_saml2() -%}
+    {% if server.federation.saml2.shib_url_scheme is defined %}
+    ShibURLScheme {{ server.federation.saml2.shib_url_scheme }}
+    {%- endif %}
+    {% if server.federation.saml2.shib_compat_valid_user is defined %}
+    ShibCompatValidUser {{ server.federation.saml2.shib_compat_valid_user }}
+    {%- endif %}
+    <Location /Shibboleth.sso>
+      SetHandler shib
+    </Location>
+    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
+      ShibRequestSetting requireSession 1
+      AuthType shibboleth
+      ShibExportAssertion Off
+      Require valid-user
+    </LocationMatch>
+{% endmacro -%}
+
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:5000
 Listen {% if server.bind.address is defined %}{{ server.bind.address }}{% else %}{{ server.bind.public_address }}{% endif %}:35357
 
@@ -29,32 +146,12 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-public/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>
@@ -85,32 +182,13 @@
         </IfVersion>
     </Directory>
 
-    {% if server.federation is defined %}
-    {% if server.federation.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.federation.shib_url_scheme }}
-    {%- endif %}
+    {% if server.get('federation', {}).saml2 is defined %}
     WSGIScriptAliasMatch ^(/v3/OS-FEDERATION/identity_providers/.*?/protocols/.*?/auth)$ /usr/bin/keystone-wsgi-admin/$1
-    <Location /Shibboleth.sso>
-      SetHandler shib
-    </Location>
-    <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/.*?/protocols/saml2/websso>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/auth/OS-FEDERATION/websso/saml2>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
-    <LocationMatch /v3/OS-FEDERATION/identity_providers/.*?/protocols/saml2/auth>
-      ShibRequestSetting requireSession 1
-      AuthType shibboleth
-      ShibExportAssertion Off
-      Require valid-user
-    </LocationMatch>
+    {{ setup_saml2() }}
+    {%- endif %}
+
+    {% if server.get('federation', {}).oidc is defined %}
+    {{ setup_oidc() }}
     {%- endif %}
 
 </VirtualHost>