Merge "Don't fail if keystone_policy is not available"
diff --git a/README.rst b/README.rst
index 6f9326e..1e0e822 100644
--- a/README.rst
+++ b/README.rst
@@ -334,7 +334,7 @@
         modules:
           - wsgi
 
-Enable Federated keystone
+Enable SAML2 Federated keystone
 
 .. code-block:: yaml
 
@@ -344,14 +344,16 @@
         - password
         - token
         - saml2
-        websso:
-          protocol: saml2
-          remote_id_attribute: Shib-Identity-Provider
+        federation:
+          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:
@@ -361,6 +363,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 05d0493..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.websso is defined %}
-{{ server.websso.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.websso is defined %}
-[{{ server.websso.protocol }}]
-remote_id_attribute = {{ server.websso.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,8 +803,8 @@
 # Entrypoint for the federation backend driver in the keystone.federation
 # namespace. (string value)
 #driver = sql
-{% if server.websso is defined %}
-driver = {{ server.websso.federation_driver }}
+{%- if server.get('federation', {}).federation_driver is defined %}
+driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
 # Value to be used when filtering assertion parameters from the environment.
@@ -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.websso is defined %}
-{%- if server.websso.trusted_dashboard is defined %}
-{%- for dashboard in server.websso.trusted_dashboard %}
+{%- 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 beaf74b..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.websso 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.websso 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 28991a4..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.websso is defined %}
-{{ server.websso.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]
 
@@ -858,8 +871,8 @@
 # Entrypoint for the federation backend driver in the keystone.federation
 # namespace. (string value)
 #driver = sql
-{%- if server.get('websso', {}).federation_driver is defined %}
-driver = {{ server.websso.federation_driver }}
+{%- if server.get('federation', {}).federation_driver is defined %}
+driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
 # Value to be used when filtering assertion parameters from the environment.
@@ -870,17 +883,14 @@
 # environment (e.g. if using the mod_shib plugin this value is `Shib-Identity-
 # Provider`). (string value)
 #remote_id_attribute = <None>
-{%- if server.websso is defined %}
-remote_id_attribute = {{ server.websso.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
 # 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('websso', {}).federated_domain_name is defined %}
-federated_domain_name = {{ server.websso.federated_domain_name }}
+{%- 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
@@ -889,8 +899,8 @@
 # example: trusted_dashboard=http://acme.com/auth/websso
 # trusted_dashboard=http://beta.com/auth/websso (multi valued)
 #trusted_dashboard =
-{%- if server.get('websso', {}).trusted_dashboard is defined %}
-{%- for dashboard in server.websso.trusted_dashboard %}
+{%- if server.get('federation', {}).trusted_dashboard is defined %}
+{%- for dashboard in server.federation.trusted_dashboard %}
 trusted_dashboard = {{ dashboard }}
 {%- endfor %}
 {%- endif %}
diff --git a/keystone/files/mitaka/wsgi-keystone.conf b/keystone/files/mitaka/wsgi-keystone.conf
index 763672d..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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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 6add60c..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.websso is defined %}
-{{ server.websso.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]
 
@@ -913,8 +925,8 @@
 # namespace. Keystone only provides a `sql` driver, so there is no reason to
 # set this option unless you are providing a custom entry point. (string value)
 #driver = sql
-{%- if server.get('websso', {}).federation_driver is defined %}
-driver = {{ server.websso.federation_driver }}
+{%- if server.get('federation', {}).federation_driver is defined %}
+driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
 # Prefix to use when filtering environment variable names for federated
@@ -927,17 +939,14 @@
 # `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.websso is defined %}
-remote_id_attribute = {{ server.websso.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
 # domain with 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('websso', {}).federated_domain_name is defined %}
-federated_domain_name = {{ server.websso.federated_domain_name }}
+{%- 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
@@ -947,8 +956,8 @@
 # trusted_dashboard=https://acme.example.com/auth/websso
 # trusted_dashboard=https://beta.example.com/auth/websso (multi valued)
 #trusted_dashboard =
-{%- if server.get('websso', {}).trusted_dashboard is defined %}
-{%- for dashboard in server.websso.trusted_dashboard %}
+{%- if server.get('federation', {}).trusted_dashboard is defined %}
+{%- for dashboard in server.federation.trusted_dashboard %}
 trusted_dashboard = {{ dashboard }}
 {%- endfor %}
 {%- endif %}
diff --git a/keystone/files/newton/wsgi-keystone.conf b/keystone/files/newton/wsgi-keystone.conf
index 763672d..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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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 aa442f2..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.websso is defined %}
-{{ server.websso.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]
 
@@ -985,8 +998,8 @@
 # namespace. Keystone only provides a `sql` driver, so there is no reason to
 # set this option unless you are providing a custom entry point. (string value)
 #driver = sql
-{%- if server.get('websso', {}).federation_driver is defined %}
-driver = {{ server.websso.federation_driver }}
+{%- if server.get('federation', {}).federation_driver is defined %}
+driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
 # Prefix to use when filtering environment variable names for federated
@@ -999,17 +1012,14 @@
 # `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.websso is defined %}
-remote_id_attribute = {{ server.websso.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
 # domain with 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('websso', {}).federated_domain_name is defined %}
-federated_domain_name = {{ server.websso.federated_domain_name }}
+{%- 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
@@ -1019,8 +1029,8 @@
 # trusted_dashboard=https://acme.example.com/auth/websso
 # trusted_dashboard=https://beta.example.com/auth/websso (multi valued)
 #trusted_dashboard =
-{%- if server.get('websso', {}).trusted_dashboard is defined %}
-{%- for dashboard in server.websso.trusted_dashboard %}
+{%- if server.get('federation', {}).trusted_dashboard is defined %}
+{%- for dashboard in server.federation.trusted_dashboard %}
 trusted_dashboard = {{ dashboard }}
 {%- endfor %}
 {%- endif %}
diff --git a/keystone/files/ocata/keystone.conf.RedHat b/keystone/files/ocata/keystone.conf.RedHat
index dd9a7c9..663854e 100644
--- a/keystone/files/ocata/keystone.conf.RedHat
+++ b/keystone/files/ocata/keystone.conf.RedHat
@@ -481,9 +481,9 @@
 # are being invoked to validate attributes in the request environment, it can
 # cause conflicts. (list value)
 #methods = external,password,token,oauth1,mapped
-{% if server.websso is defined %}
-methods = external,password,token,{{ server.websso.protocol }}
-{{ server.websso.protocol }} = keystone.auth.plugins.mapped.Mapped
+{% if server.federation is defined %}
+methods = external,password,token,{{ server.federation.protocol }}
+{{ server.federation.protocol }} = keystone.auth.plugins.mapped.Mapped
 {%- endif %}
 
 # Entry point for the password auth plugin module in the
@@ -964,8 +964,8 @@
 # namespace. Keystone only provides a `sql` driver, so there is no reason to
 # set this option unless you are providing a custom entry point. (string value)
 #driver = sql
-{%- if server.get('websso', {}).federation_driver is defined %}
-driver = {{ server.websso.federation_driver }}
+{%- if server.get('federation', {}).federation_driver is defined %}
+driver = {{ server.federation.federation_driver }}
 {%- endif %}
 
 # Prefix to use when filtering environment variable names for federated
@@ -978,8 +978,8 @@
 # `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.websso is defined %}
-remote_id_attribute = {{ server.websso.remote_id_attribute }}
+{%- 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
@@ -987,8 +987,8 @@
 # domain with 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('websso', {}).federated_domain_name is defined %}
-federated_domain_name = {{ server.websso.federated_domain_name }}
+{%- 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
@@ -998,8 +998,8 @@
 # trusted_dashboard=https://acme.example.com/auth/websso
 # trusted_dashboard=https://beta.example.com/auth/websso (multi valued)
 #trusted_dashboard =
-{%- if server.get('websso', {}).trusted_dashboard is defined %}
-{%- for dashboard in server.websso.trusted_dashboard %}
+{%- if server.get('federation', {}).trusted_dashboard is defined %}
+{%- for dashboard in server.federation.trusted_dashboard %}
 trusted_dashboard = {{ dashboard }}
 {%- endfor %}
 {%- endif %}
diff --git a/keystone/files/ocata/wsgi-keystone.conf b/keystone/files/ocata/wsgi-keystone.conf
index 763672d..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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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.websso is defined %}
-    {% if server.websso.shib_url_scheme is defined %}
-    ShibURLScheme {{ server.websso.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/server.sls b/keystone/server.sls
index c6e375d..b4de945 100644
--- a/keystone/server.sls
+++ b/keystone/server.sls
@@ -65,7 +65,7 @@
     - service: keystone_service
   {%- endif %}
 
-{% if server.websso is defined %}
+{% if server.federation is defined %}
 
 /etc/keystone/sso_callback_template.html:
   file.managed: