[java-oidc-common] 01/01: JCOMOIDC-48 - Move OIDC.SSO profile bean to commons

Phil Smart philip.smart at jisc.ac.uk
Thu Feb 2 14:53:34 UTC 2023


This is an automated email from the git hooks/post-receive script.

philsmart pushed a commit to branch dev/JCOMOIDC-48
in repository java-oidc-common.

View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=4b0f057bfbe7a9b85925382d5f3ad1ba7941c9f1

commit 4b0f057bfbe7a9b85925382d5f3ad1ba7941c9f1
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Tue Jan 31 09:57:54 2023 +0000

    JCOMOIDC-48 - Move OIDC.SSO profile bean to commons
    
     - Move profile beans, related classes, and related config to commons
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-48
---
 .../common/conf/attributes/oidc-claim-rules.xml    | 428 +++++++++++++++++++++
 .../oidc/common/conf/authn/oidc-credentials.xml    |  75 ++++
 .../net/shibboleth/oidc/common/module.properties   |   9 +
 .../config/AbstractOIDCSSOConfiguration.java       |  44 ++-
 .../profile/config/CredentialsListFactory.java     |  65 ++++
 .../config/OIDCAuthorizationConfiguration.java     | 148 +------
 ...nticationContextClassRequestLookupFunction.java | 114 ++++++
 ...ticationContextClassResponseLookupFunction.java | 115 ++++++
 ...th2ClientAuthenticableProfileConfiguration.java | 131 ++++++-
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  28 ++
 .../idp/service/attribute/registry/postconfig.xml  |  25 ++
 .../idp/service/relying-party/postconfig.xml       | 328 ++++++++++++++++
 .../profile/config/CredentialsListFactoryTest.java |  83 ++++
 ...thenticationContextClassLookupFunctionTest.java | 134 +++++++
 ...tionContextClassResponseLookupFunctionTest.java | 127 ++++++
 15 files changed, 1705 insertions(+), 149 deletions(-)

diff --git a/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/attributes/oidc-claim-rules.xml b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/attributes/oidc-claim-rules.xml
new file mode 100644
index 0000000..9de853b
--- /dev/null
+++ b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/attributes/oidc-claim-rules.xml
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+                           
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <!-- https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims -->
+
+    <bean parent="shibboleth.TranscodingRuleLoader">
+    <constructor-arg>
+    <list>
+
+        <!-- Typical inetOrgPerson attributes that map to standard claims. -->
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">displayName</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">name</prop>
+                    <prop key="displayName.en">Display name</prop>
+                    <prop key="displayName.de">Anzeigename</prop>
+                    <prop key="displayName.fr">Nom</prop>
+                    <prop key="displayName.it">Nome</prop>
+                    <prop key="displayName.ja">表示名</prop>
+                    <prop key="description.en">The name that should appear in white-pages-like applications for this person.</prop>
+                    <prop key="description.de">Anzeigename</prop>
+                    <prop key="description.fr">Nom complet d'affichage</prop>
+                    <prop key="description.it">Nome</prop>
+                    <prop key="description.ja">アプリケーションでの表示に用いられる英字氏名</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">givenName</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">given_name</prop>
+                    <prop key="displayName.en">Given name</prop>
+                    <prop key="displayName.de">Vorname</prop>
+                    <prop key="displayName.fr">Prénom</prop>
+                    <prop key="displayName.it">Nome</prop>
+                    <prop key="displayName.ja">名</prop>
+                    <prop key="description.en">Given name of a person</prop>
+                    <prop key="description.de">Vorname</prop>
+                    <prop key="description.fr">Prénom de l'utilisateur</prop>
+                    <prop key="description.it">Nome</prop>
+                    <prop key="description.ja">氏名(名)の英語表記</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">homePhone</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">phone_number</prop>
+                    <prop key="displayName.en">Private phone number</prop>
+                    <prop key="displayName.de">Telefon Privat</prop>
+                    <prop key="displayName.fr">Teléphone personnel</prop>
+                    <prop key="displayName.it">Numero di telefono privato</prop>
+                    <prop key="displayName.ja">自宅電話番号</prop>
+                    <prop key="description.en">Private phone number</prop>
+                    <prop key="description.de">Private Telefonnummer</prop>
+                    <prop key="description.fr">Numéro de téléphone de domicile de la personne</prop>
+                    <prop key="description.it">Numero di telefono privato</prop>
+                    <prop key="description.ja">自宅の電話番号</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">mail</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">email</prop>
+                    <prop key="displayName.en">E-mail</prop>
+                    <prop key="displayName.de">E-Mail</prop>
+                    <prop key="displayName.fr">Email</prop>
+                    <prop key="displayName.it">E-mail</prop>
+                    <prop key="displayName.ja">メールアドレス</prop>
+                    <prop key="description.en">E-Mail: Preferred address for e-mail to be sent to this person</prop>
+                    <prop key="description.de">E-Mail-Adresse</prop>
+                    <prop key="description.de-ch">E-Mail Adresse</prop>
+                    <prop key="description.fr">Adresse de courrier électronique</prop>
+                    <prop key="description.it">E-Mail: l'indirizzo e-mail preferito dall'utente</prop>
+                    <prop key="description.ja">メールアドレス</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">preferredLanguage</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">locale</prop>
+                    <prop key="displayName.en">Preferred Language</prop>
+                    <prop key="displayName.de">Bevorzugte Sprache</prop>
+                    <prop key="displayName.fr">Langue préférée</prop>
+                    <prop key="displayName.it">Lingua preferita</prop>
+                    <prop key="displayName.ja">希望言語</prop>
+                    <prop key="description.en">Preferred language: Users preferred language (see RFC1766)</prop>
+                    <prop key="description.de">Bevorzugte Sprache (siehe RFC1766)</prop>
+                    <prop key="description.fr">Exemple: fr, de, it, en, ... (voir RFC1766)</prop>
+                    <prop key="description.it">Lingua preferita: la lingua preferita dall'utente (cfr. RFC1766)</prop>
+                    <prop key="description.ja">利用者が希望する言語(RFC1766 を参照)</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">sn</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">family_name</prop>
+                    <prop key="displayName.en">Surname</prop>
+                    <prop key="displayName.de">Nachname</prop>
+                    <prop key="displayName.fr">Nom de famille</prop>
+                    <prop key="displayName.it">Cognome</prop>
+                    <prop key="displayName.ja">姓</prop>
+                    <prop key="description.en">Surname or family name</prop>
+                    <prop key="description.de">Familienname</prop>
+                    <prop key="description.fr">Nom de famille de l'utilisateur.</prop>
+                    <prop key="description.it">Cognome dell'utilizzatore</prop>
+                    <prop key="description.ja">氏名(姓)の英語表記</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">telephoneNumber</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">phone_number</prop>
+                    <prop key="displayName.en">Business phone number</prop>
+                    <prop key="displayName.de">Telefon Geschäft</prop>
+                    <prop key="displayName.fr">Teléphone professionnel</prop>
+                    <prop key="displayName.it">Numero di telefono dell'ufficio</prop>
+                    <prop key="displayName.ja">所属機関内電話番号</prop>
+                    <prop key="description.en">Business phone number: Office or campus phone number</prop>
+                    <prop key="description.de">Telefonnummer am Arbeitsplatz</prop>
+                    <prop key="description.fr">Teléphone de l'institut, de l'université</prop>
+                    <prop key="description.it">Numero di telefono dell'ufficio</prop>
+                    <prop key="description.ja">所属機関での利用者の電話番号</prop>
+                </props>
+            </property>
+        </bean>
+        
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">uid</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">preferred_username</prop>
+                    <prop key="displayName.en">User ID</prop>
+                    <prop key="displayName.de">Benutzer-ID</prop>
+                    <prop key="displayName.fr">ID utilisateur</prop>
+                    <prop key="displayName.it">ID dell'utente</prop>
+                    <prop key="displayName.ja">ユーザID</prop>
+                    <prop key="description.en">A unique identifier for a person, mainly used for user identification within the user's home organization.</prop>
+                    <prop key="description.de">Eine eindeutige Nummer für eine Person, welche hauptsächlich zur Identifikation innerhalb der Organisation benutzt wird.</prop>
+                    <prop key="description.fr">Identifiant de connexion d'une personnes sur les systèmes informatiques.</prop>
+                    <prop key="description.it">Identificativo unico della persona, usato per l'identificazione dell'utente all'interno della organizzazione di appartenenza.</prop>
+                    <prop key="description.ja">所属機関内で一意の利用者識別子</prop>
+                </props>
+            </property>
+        </bean>
+
+        <!-- eduPerson attributes that map to standard claims. -->
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">eduPersonNickname</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">nickname</prop>
+                    <prop key="displayName.en">Nickname</prop>
+                    <prop key="displayName.de">Kurzname</prop>
+                    <prop key="displayName.de-ch">Übername</prop>
+                    <prop key="displayName.fr">Surnom</prop>
+                    <prop key="displayName.it">Diminutivo</prop>
+                    <prop key="displayName.ja">ニックネーム</prop>
+                    <prop key="description.en">Person's nickname, or the informal name by which they are accustomed to be hailed.</prop>
+                    <prop key="description.de">Kurzname einer Person, oder üblicher Rufname zur Begrüßung.</prop>
+                    <prop key="description.de-ch">Übername einer Person, oder üblicher Rufname zur Begrüssung.</prop>
+                    <prop key="description.fr">Nom personnalisable pour un usage informel.</prop>
+                    <prop key="description.it">Diminutivo della persona, o  soprannome.</prop>
+                    <prop key="description.ja">利用者のニックネームもしくは通称</prop>
+                </props>
+            </property>
+        </bean>
+
+        <!-- A subset of the major eduPerson attributes that have no standard claim mapping. -->
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">eduPersonAssurance</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">eduPersonAssurance</prop>
+                    <prop key="displayName.en">Assurance level</prop>
+                    <prop key="displayName.de">Vertrauensgrad</prop>
+                    <prop key="displayName.fr">Niveau de confiance</prop>
+                    <prop key="displayName.it">Livello di sicurezza</prop>
+                    <prop key="displayName.ja">保証レベル</prop>
+                    <prop key="description.en">Set of URIs that assert compliance with specific standards for identity assurance.</prop>
+                    <prop key="description.de">URIs die eine gewisse Zusicherung für spezifische Standards des Vertrauens beinhalten</prop>
+                    <prop key="description.fr">Un ensemble d'URI qui attestent la conformité selon un standard pour les niveaux d'assurance d'identités</prop>
+                    <prop key="description.it">Un insieme di URI che asseriscono l'osservanza dei livelli di sicurezza richiesti</prop>
+                    <prop key="description.ja">IDの保証レベルに関して特定の基準に準拠していることを示すURI</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">eduPersonEntitlement</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">eduPersonEntitlement</prop>
+                    <prop key="displayName.en">Entitlement</prop>
+                    <prop key="displayName.de">Berechtigung</prop>
+                    <prop key="displayName.fr">Entitlement</prop>
+                    <prop key="displayName.it">Prerogativa</prop>
+                    <prop key="displayName.ja">資格情報</prop>
+                    <prop key="description.en">Member of: URI (either URL or URN) that indicates a set of rights to specific resources based on an agreement across the releavant community</prop>
+                    <prop key="description.de">Zeichenkette, die Rechte für spezifische Ressourcen beschreibt</prop>
+                    <prop key="description.fr">Membre de: URI (soit une URL ou une URN) décrivant un droit spécific d'accès.</prop>
+                    <prop key="description.it">Membro delle seguenti URI (sia URL o URN) che rappresentano diritti specifici d'accesso validi in tutta la communità</prop>
+                    <prop key="description.ja">特定のアプリケーションもしくはコミュニティ内の複数リソースへのアクセス権限を持つことを示すURI(URLもしくはURN)</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">eduPersonPrincipalName</prop>
+                    <prop key="transcoder">OIDCScopedStringTranscoder</prop>
+                    <prop key="oidc.name">eduPersonPrincipalName</prop>
+                    <prop key="displayName.en">Principal name</prop>
+                    <prop key="displayName.de">Persönliche ID</prop>
+                    <prop key="displayName.fr">Principal Name</prop>
+                    <prop key="displayName.it">Principal Name</prop>
+                    <prop key="displayName.ja">プリンシパルID</prop>
+                    <prop key="description.en">A unique identifier for a person, mainly for inter-institutional user identification.</prop>
+                    <prop key="description.de">Eindeutige Benutzeridentifikation</prop>
+                    <prop key="description.de-ch">Eindeutige Benützeridentifikation</prop>
+                    <prop key="description.fr">L'identifiant unique de l'utilisateur</prop>
+                    <prop key="description.it">Un ID personale che identifica chiaramente l'utente in seno alla sua organizzazione</prop>
+                    <prop key="description.ja">フェデレーション内で一意かつ永続的な利用者識別子</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">eduPersonScopedAffiliation</prop>
+                    <prop key="transcoder">OIDCScopedStringTranscoder</prop>
+                    <prop key="oidc.name">eduPersonScopedAffiliation</prop>
+                    <prop key="displayName.en">Scoped affiliation</prop>
+                    <prop key="displayName.de">Zugehörigkeit</prop>
+                    <prop key="displayName.fr">Affiliation</prop>
+                    <prop key="displayName.it">Tipo di membro</prop>
+                    <prop key="displayName.ja">スコープ付き職位</prop>
+                    <prop key="description.en">Specifies the person's affiliation within a particular security domain</prop>
+                    <prop key="description.de">Art der Zugehörigkeit zur Heimatorganisation</prop>
+                    <prop key="description.de-ch">Art der Zugehörigkeit zur Heimorganisation</prop>
+                    <prop key="description.fr">Type d'affiliation dans l'organisation</prop>
+                    <prop key="description.it">Tipo di membro: Tipo di lavoro svolto per l'organizzazione</prop>
+                    <prop key="description.ja">セキュリティドメインのスコープが付いた所属機関における職位</prop>
+                </props>
+            </property>
+        </bean>
+
+        <!-- The remainder are standard OIDC claims, which we map based on the actual claim name. -->
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">address</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.asObject">true</prop>
+                    <prop key="oidc.name">address</prop>
+                    <prop key="displayName.en">Postal address</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">birthdate</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">birthdate</prop>
+                    <prop key="displayName.en">Date of birth</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">email_verified</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">email_verified</prop>
+                    <prop key="oidc.asBoolean">true</prop>
+                    <prop key="displayName.en">E-mail verification status</prop>
+                    <prop key="description.en">Indicates whether e-mail address has been verified by the issuer</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">gender</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">gender</prop>
+                    <prop key="displayName.en">Gender</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">middle_name</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">middle_name</prop>
+                    <prop key="displayName.en">Middle name</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">phone_number_verified</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">phone_number_verified</prop>
+                    <prop key="oidc.asBoolean">true</prop>
+                    <prop key="displayName.en">Phone number verification status</prop>
+                    <prop key="description.en">Indicates whether phone number has been verified by the issuer</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">picture</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">picture</prop>
+                    <prop key="displayName.en">Picture</prop>
+                    <prop key="description.en">URL of personal photo</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">profile</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">profile</prop>
+                    <prop key="displayName.en">Profile page</prop>
+                    <prop key="description.en">URL of personal profile page</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">website</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">website</prop>
+                    <prop key="displayName.en">Web site</prop>
+                    <prop key="description.en">URL to personal web site</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">updated_at</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">updated_at</prop>
+                    <prop key="oidc.asInteger">true</prop>
+                    <prop key="displayName.en">Last update of information</prop>
+                </props>
+            </property>
+        </bean>
+
+        <bean parent="shibboleth.TranscodingProperties">
+            <property name="properties">
+                <props merge="true">
+                    <prop key="id">zoneinfo</prop>
+                    <prop key="transcoder">OIDCStringTranscoder</prop>
+                    <prop key="oidc.name">zoneinfo</prop>
+                    <prop key="displayName.en">Time zone</prop>
+                </props>
+            </property>
+        </bean>
+
+    </list>
+    </constructor-arg>
+    </bean>
+    
+</beans>
diff --git a/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/authn/oidc-credentials.xml b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/authn/oidc-credentials.xml
new file mode 100644
index 0000000..f38eb9a
--- /dev/null
+++ b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/conf/authn/oidc-credentials.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <!--
+    This file contains default OIDC signing credentials. This file should be imported into credentials.xml.
+    -->
+    
+    <bean id="shibboleth.oidc.DefaultRSSigningCredential" parent="shibboleth.oidc.JWKCredential"
+        p:resource="%{idp.signing.oidc.rs.key:#{null}}" p:failIfResourceIsNull="false" />
+
+    <bean id="shibboleth.oidc.DefaultESSigningCredential" parent="shibboleth.oidc.JWKCredential"
+        p:resource="%{idp.signing.oidc.es.key:#{null}}" p:failIfResourceIsNull="false" />
+
+    <bean id="shibboleth.oidc.DefaultRSAEncryptionCredential" parent="shibboleth.oidc.JWKCredential"
+        p:resource="%{idp.signing.oidc.rsa.enc.key:#{null}}" p:failIfResourceIsNull="false" />
+           
+    
+    <!-- 
+        The default credential is based on the client_secret, and will be the only used credential in most cases.
+    -->
+    <bean id="shibboleth.authn.oidc.rp.DefaultCredential" parent="shibboleth.oidc.ClientSecretCredential"
+        p:secret="%{idp.authn.oidc.rp.client.clientSecret:#{null}}"/>
+
+    <!--
+    Lists ALL of your OP's response signing credentials for the default security configuration. 
+    If you define additional signing credentials make sure to include them within this list.
+    -->
+    <util:list id="shibboleth.oidc.SigningCredentials">
+        <ref bean="shibboleth.oidc.DefaultRSSigningCredential" />
+        <ref bean="shibboleth.oidc.DefaultESSigningCredential" />
+    </util:list>
+
+    <!--
+    Lists ALL of your OP's request decryption credentials for the default security configuration.
+    If you  define additional decryption credentials make sure to include them within this list.
+    -->
+    <util:list id="shibboleth.oidc.EncryptionCredentials">
+        <ref bean="shibboleth.oidc.DefaultRSAEncryptionCredential" />
+    </util:list>
+
+    <!--
+    If you need to publish a key set different from shibboleth.oidc.EncryptionCredentials, define
+    a list bean named "shibboleth.oidc.EncryptionCredentialsToPublish".
+    -->
+
+    <!-- Example of two active encryption credentials, but only publishing the second before removing from use. -->
+    <!--
+    <util:list id="shibboleth.oidc.EncryptionCredentialsToPublish">
+        <ref bean="shibboleth.oidc.OnlyNewDefaultRSAEncryptionCredential" />
+    </util:list>
+    -->
+
+    <!--
+    If you need to publish a key set different from shibboleth.oidc.SigningCredentials, define
+    a list bean named "shibboleth.oidc.SigningCredentialsToPublish".
+    -->
+    
+    <!-- Example of publishing two signing credentials, before active use. -->
+    <!--
+    <util:list id="shibboleth.oidc.SigningCredentialsToPublish">
+        <ref bean="shibboleth.oidc.DefaultRSSigningCredential" />
+        <ref bean="shibboleth.oidc.DefaultESSigningCredential" />
+        <ref bean="shibboleth.oidc.UpcomingDefaultRSSigningCredential" />
+    </util:list>
+    -->
+
+</beans>
diff --git a/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/module.properties b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/module.properties
index bfea30c..3aaeacc 100644
--- a/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/module.properties
+++ b/oidc-common-plugin/src/main/resources/net/shibboleth/oidc/common/module.properties
@@ -9,3 +9,12 @@ idp.oidc.common.3.plugin = net.shibboleth.oidc.common
 idp.oidc.common.3.name = Module to provide common OIDC processing
 idp.oidc.common.3.desc = Module that provides common OIDC processing functions for other plugins to use
 idp.oidc.common.3.url = /OIDCCommon
+
+idp.oidc.common.3.1.src =  /net/shibboleth/oidc/common/conf/authn/oidc-credentials.xml
+idp.oidc.common.3.1.dest = conf/oidc-credentials.xml
+idp.oidc.common.3.1.replace = false
+
+idp.oidc.common.3.2.src = /net/shibboleth/oidc/common/conf/attributes/oidc-claim-rules.xml
+idp.oidc.common.3.2.dest = conf/attributes/oidc-claim-rules.xml
+idp.oidc.common.3.2.replace = false
+
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCSSOConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCSSOConfiguration.java
index c38c42f..93615f8 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCSSOConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCSSOConfiguration.java
@@ -96,7 +96,10 @@ public abstract class AbstractOIDCSSOConfiguration extends AbstractOAuth2FlowAwa
     /** Lookup function to supply strategy bi-function for manipulating access token claims set. */ 
     @Nonnull
     private Function<ProfileRequestContext,BiFunction<ProfileRequestContext,Map<String,Object>,Map<String,Object>>>
-        accessTokenClaimsSetManipulationStrategyLookupStrategy;
+        accessTokenClaimsSetManipulationStrategyLookupStrategy;    
+    
+    /** Lookup function to override the default response_mode for a given response_type.*/
+    @Nonnull private Function<ProfileRequestContext, String> responseModeLookupStrategy;
 
     /**
      * Creates a new configuration instance.
@@ -122,9 +125,12 @@ public abstract class AbstractOIDCSSOConfiguration extends AbstractOAuth2FlowAwa
 
         idTokenManipulationStrategyLookupStrategy = FunctionSupport.constant(null);
         accessTokenClaimsSetManipulationStrategyLookupStrategy = FunctionSupport.constant(null);
+        
+        responseModeLookupStrategy = FunctionSupport.constant(null);
     }
     
     /** {@inheritDoc} */
+    @Override
     @Nullable @NotEmpty public String getIssuer(@Nullable final ProfileRequestContext profileRequestContext) {
         return issuerLookupStrategy.apply(profileRequestContext);
     }
@@ -148,6 +154,7 @@ public abstract class AbstractOIDCSSOConfiguration extends AbstractOAuth2FlowAwa
     }
 
     /** {@inheritDoc} */
+    @Override
     public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
         return resolveAttributesPredicate.test(profileRequestContext);
     }
@@ -590,5 +597,40 @@ public abstract class AbstractOIDCSSOConfiguration extends AbstractOAuth2FlowAwa
         accessTokenClaimsSetManipulationStrategyLookupStrategy = Constraint.isNotNull(strategy,
                 "Lookup strategy cannot be null");
     }
+    
+    /**
+     * Set the lookup strategy to determine the response_mode for authorization requests.
+     *
+     * @param strategy the strategy to use
+     * 
+     * @since 2.2.0
+     */
+    public void setResponseModeLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+        responseModeLookupStrategy = Constraint.isNotNull(strategy, "ResponseMode lookup strategy can not be null");
+    }
+
+    /**
+     * Get the response_mode to use for authorization requests.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return the response_mode
+     * 
+     * @since 2.2.0
+     */
+    public String getResponseMode(@Nullable final ProfileRequestContext profileRequestContext) {
+        return responseModeLookupStrategy.apply(profileRequestContext);
+    }
+
+    /**
+     * Set the response_mode to use for authorization requests.
+     *
+     * @param responseMode the response_mode to use
+     * 
+     * @since 2.2.0
+     */
+    public void setResponseMode(@Nonnull final String responseMode) {
+        responseModeLookupStrategy = FunctionSupport.constant(responseMode);
+    }
 
 }
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/CredentialsListFactory.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/CredentialsListFactory.java
new file mode 100644
index 0000000..b081ac8
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/CredentialsListFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+/** 
+ * A factory that returns a list of credentials which does not contain any {@literal null} elements.
+ * 
+ * <p>Primarily created to support signature credential injection into the {@link BasicSignatureSigningConfiguration}
+ * when the credential list may contain, in its raw state, {@literal null} elements.</p>
+ */
+public class CredentialsListFactory extends AbstractFactoryBean<List<Credential>> {
+    
+    /** The credentials which may contain {@literal null} elements. */
+    @Nonnull private List<Credential> credentials;
+    
+    /**
+     * Constructor.
+     *
+     * @param creds the credentials, which can be {@literal null} and may contain {@literal null} elements.
+     */
+    public CredentialsListFactory(@Nullable final List<Credential> creds){
+        if (creds == null) {
+            credentials = Collections.emptyList();
+        } else {
+            credentials = creds;
+        }
+    }
+
+    @Override
+    public Class<?> getObjectType() {
+        return List.class;
+    }
+
+    @Override
+    protected List<Credential> createInstance() throws Exception {
+        return credentials.stream().filter(Objects::nonNull).collect(Collectors.toList());
+    }
+
+}
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
index 6b1f6b0..6ab3c85 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCAuthorizationConfiguration.java
@@ -36,7 +36,6 @@ import com.google.common.base.Predicates;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
-import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
@@ -102,22 +101,6 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
     /** An override to specify a specific redirect_uri to use over the normally computed one.*/
     @Nonnull private Function<ProfileRequestContext, String> redirectUriOverrideLookupStrategy;
 
-    /** Lookup function to retrieve the client_id from the given profile request context.*/
-    //TODO this is the same as the issuer in the proxy context?
-    @Nonnull private Function<ProfileRequestContext, String> clientIdLookupStrategy;
-
-    /**
-     * Lookup function to retrieve a client credential from the given profile request context.
-     */
-    @Nonnull private Function<ProfileRequestContext, ClientSecretCredential> clientCredentialLookupStrategy;
-
-    /** Lookup function to determine the client_authentication method.  */
-    //TODO same as tokenEndpointAuthMethodsLookupStrategy?
-    @Nonnull private Function<ProfileRequestContext, String> clientAuthenticationMethodLookupStrategy;
-
-    /** Lookup function to override the default response_mode for a given response_type.*/
-    @Nonnull private Function<ProfileRequestContext, String> responseModeLookupStrategy;
-
     /** Lookup function to retrieve the response_type.*/
     @Nonnull private Function<ProfileRequestContext, String> responseTypeLookupStrategy;
 
@@ -165,10 +148,7 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
     public OIDCAuthorizationConfiguration(@Nonnull @NotEmpty final String profileId) {
         super(profileId);
 
-        redirectUriOverrideLookupStrategy = FunctionSupport.constant(null);
-        clientIdLookupStrategy = FunctionSupport.constant(null);
-        clientCredentialLookupStrategy = FunctionSupport.constant(null);
-        responseModeLookupStrategy = FunctionSupport.constant(null);
+        redirectUriOverrideLookupStrategy = FunctionSupport.constant(null);     
         responseTypeLookupStrategy = FunctionSupport.constant("code");
         scopesLookupStrategy = FunctionSupport.constant(Set.of("openid"));
         signRequestObjectPredicate = Predicates.alwaysTrue();
@@ -369,103 +349,6 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
         encryptRequestObjectPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
     }
 
-    /**
-     * Set the strategy to locate a client_id.
-     *
-     * @param strategy the strategy to use
-     */
-    public void setClientIdLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
-        clientIdLookupStrategy = Constraint.isNotNull(strategy, "Client ID lookup strategy can not be null");
-    }
-
-    /**
-     * Set a fixed client_id to use no matter what the context/request.
-     *
-     * @param clientId the static clientId to use
-     */
-    public void setClientId(@Nullable final String clientId) {
-        clientIdLookupStrategy = FunctionSupport.constant(StringSupport.trimOrNull(clientId));
-    }
-
-    /**
-     * Get the client_id appropriate for the given context. Typically that associated
-     * with the chosen downstream OpenID Connect Provider.
-     *
-     * @param profileRequestContext the profile request context
-     *
-     * @return the client_id
-     */
-    public String getClientId(@Nullable final ProfileRequestContext profileRequestContext) {
-        return clientIdLookupStrategy.apply(profileRequestContext);
-    }
-
-     /**
-     * Set the client authentication method lookup strategy which will locate the client_authentication method
-     * for a given client.
-     *
-     * @param strategy the strategy to use
-     */
-    public void setClientAuthenticationMethodLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, String> strategy) {
-        clientAuthenticationMethodLookupStrategy =
-                Constraint.isNotNull(strategy, "Client authentication strategy can not be null");
-    }
-
-    /**
-     * Set the client authentication method.
-     *
-     * @param clientAuthMethod the client_authentication method
-     */
-    public void setClientAuthenticationMethod(@Nullable final String clientAuthMethod) {
-        clientAuthenticationMethodLookupStrategy = FunctionSupport.constant(clientAuthMethod);
-    }
-
-     /**
-      * Get the client_authentication for the given context. Typically that associated with the
-      * current client_id.
-      *
-      * @param profileRequestContext the profile request context
-      *
-      * @return the client_authentication method
-      */
-     public String getClientAuthenticationMethod(
-             @Nullable final ProfileRequestContext profileRequestContext) {
-         return clientAuthenticationMethodLookupStrategy.apply(profileRequestContext);
-     }
-
-    /**
-     * Set the client credential lookup strategy.
-     *
-     * @param strategy the strategy to use
-     */
-    public void setClientCredentialLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext, ClientSecretCredential> strategy) {
-        clientCredentialLookupStrategy =
-                Constraint.isNotNull(strategy, "Client credential lookup strategy can not be null");
-    }
-
-    /**
-     * Set a fixed client credential to use no matter what the context/request.
-     *
-     * @param clientCredential the static client credential to use
-     */
-    public void setClientCredential(@Nullable final ClientSecretCredential clientCredential) {
-        clientCredentialLookupStrategy = FunctionSupport.constant(clientCredential);
-    }
-
-    /**
-     * Get the client credential for the given context. Typically a client_secret
-     * associated with the current client_id.
-     *
-     * @param profileRequestContext the profile request context
-     *
-     * @return the client credential
-     */
-    public ClientSecretCredential getClientCredential(
-            @Nullable final ProfileRequestContext profileRequestContext) {
-        return clientCredentialLookupStrategy.apply(profileRequestContext);
-    }
-
     /**
      * Set the redirect_uri lookup strategy used to locate an overridden redirect.
      *
@@ -672,35 +555,6 @@ public class OIDCAuthorizationConfiguration extends AbstractOIDCSSOConfiguration
             @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
         deniedUserInfoAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
-
-    /**
-     * Set the lookup strategy to determine the response_mode for authentication requests.
-     *
-     * @param strategy the strategy to use
-     */
-    public void setResponseModeLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
-        responseModeLookupStrategy = Constraint.isNotNull(strategy, "ResponseMode lookup strategy can not be null");
-    }
-
-    /**
-     * Get the response_mode to use for authentication requests.
-     *
-     * @param profileRequestContext the profile request context
-     *
-     * @return the response_mode
-     */
-    public String getResponseMode(@Nullable final ProfileRequestContext profileRequestContext) {
-        return responseModeLookupStrategy.apply(profileRequestContext);
-    }
-
-    /**
-     * Set the response_mode to use for authentication requests.
-     *
-     * @param responseMode the response_mode to use
-     */
-    public void setResponseMode(@Nonnull final String responseMode) {
-        responseModeLookupStrategy = FunctionSupport.constant(responseMode);
-    }
     
     /**
      * Get whether to include iss parameter in the authentication response.
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction.java
new file mode 100644
index 0000000..ffded26
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.shibboleth.oidc.profile.config.navigate;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+
+/**
+ * Implements a set of default logic for determining the custom principals to derive the
+ * OIDC ACRs from.
+ * 
+ * <p>This operates for the SAML to OIDC proxy use case. The values returned are empty unless the 
+ * parent context itself contains a child context carrying particular values. The values are either
+ * 'passed through' or mapped by the given principal mappings. All input values are either SAML ACRs or AMRs,
+ * and all output values are OIDC ACRs.</p>
+ */
+public class ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction 
+    implements Function<ProfileRequestContext,Collection<AuthenticationContextClassReferencePrincipal>> {
+    
+    /** Mappings to transform proxied Principals. */
+    @Nonnull @NonnullElements private Map<Principal,Collection<Principal>> principalMappings;
+    
+    /** Constructor. */
+    public ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction() {
+        principalMappings = Collections.emptyMap();
+    }
+    
+   /**
+    * Sets the mappings from input/proxied Principals to zero or more equivalent values to use.
+    * 
+    * <p>Any values not mapped will be assumed to be passed through.</p>
+    * 
+    * @param mappings {@link Principal} mappings
+    */
+   public void setMappings(@Nullable @NonnullElements final Map<Principal,Collection<Principal>> mappings) {
+       if (mappings == null || mappings.isEmpty()) {
+           principalMappings = Collections.emptyMap();
+           return;
+       }
+       
+       principalMappings = new HashMap<>(mappings.size());
+       mappings.forEach((k, v) -> principalMappings.put(k, List.copyOf(v)));
+   }
+
+    @Override
+    public Collection<AuthenticationContextClassReferencePrincipal> apply(final ProfileRequestContext input) {
+        
+        if (input != null && input.getParent() instanceof AuthenticationContext) {
+            
+            final RequestedPrincipalContext rpc = input.getParent().getSubcontext(RequestedPrincipalContext.class);
+            
+            if (rpc != null) {
+                
+                final List<AuthenticationContextClassReferencePrincipal> mappedAndPassedThroughPrincipals =
+                        new ArrayList<>();
+                
+                for (final Principal requestedPrincipal : rpc.getRequestedPrincipals()) {
+                    
+                    // If a mapping exists, use it
+                    if (principalMappings.containsKey(requestedPrincipal)) {
+                        final Collection<Principal> mappedPrinicipals = principalMappings.get(requestedPrincipal);
+                        for (final Principal mappedPrincipal : mappedPrinicipals) {
+                            if (mappedPrincipal instanceof AuthenticationContextClassReferencePrincipal) {
+                                mappedAndPassedThroughPrincipals.add(
+                                        (AuthenticationContextClassReferencePrincipal) mappedPrincipal);
+                            }                               
+                        }
+                    } else {
+                        // If no mapping exists, just convert to correct output type - which might not make sense
+                        // to the upstream OP.
+                        mappedAndPassedThroughPrincipals.add(
+                                new AuthenticationContextClassReferencePrincipal(requestedPrincipal.getName()));
+                    }
+                
+                }
+                return mappedAndPassedThroughPrincipals;
+            }
+        }        
+        return Collections.emptyList();
+    }
+    
+
+}
+
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction.java
new file mode 100644
index 0000000..a122310
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.shibboleth.oidc.profile.config.navigate;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Implements a set of logic for determining the principals to use from OIDC 'amr' or 'acr' claims.
+ * 
+ * <p>This operates for the OIDC to SAML proxy use case, in effect the reverse of the 
+ * {@link ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction} function. 
+ * All input values are either OIDC ACRs or AMRs, and all output values Java {@link Principal}s.
+ * The values are mapped by the given principal mappings. If a mapping does not exist, the AMR or ACR is ignored.
+ * </p>
+ */
+ at ThreadSafe
+public class ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction 
+    implements Function<Collection<String>,Collection<Principal>> {
+    
+    /** Mappings to transform proxied Principals. */
+    @Nonnull @NonnullElements private final Map<String,Collection<Principal>> principalMappings;
+    
+    /**
+     * 
+     * Constructor.
+     *
+     * @param mappings the AMR/ACR value to Principal mappings
+     */
+    public ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction(
+            @Nullable @NonnullElements @ParameterName(name="mappings") 
+            final Map<String,Collection<Principal>> mappings) {
+        
+        if (mappings == null || mappings.isEmpty()) {
+            principalMappings = Collections.emptyMap();
+        } else {        
+            principalMappings = new HashMap<>(mappings.size());
+            mappings.forEach((k, v) -> principalMappings.put(k, List.copyOf(v)));
+        }
+    }
+    
+    @Override
+    public Collection<Principal> apply(final Collection<String> amrOrAcrs) {
+        
+        if (amrOrAcrs != null) {                
+                final List<Principal> principals = new ArrayList<>();                
+                for (final String amrOrAcr : amrOrAcrs) {                    
+                    if (principalMappings.containsKey(amrOrAcr)) {
+                        final Collection<Principal> mappedPrincipals = principalMappings.get(amrOrAcr);
+                        if (!mappedPrincipals.isEmpty()) {
+                            principals.addAll(mappedPrincipals);
+                        }
+                    }                 
+                }
+                return principals;            
+        }        
+        return Collections.emptyList();
+    }   
+    
+    /** A simple lookup function that returns a singleton function.*/
+    public static class LookupFunctionWrapper 
+                implements Function<ProfileRequestContext, Function<Collection<String>,Collection<Principal>>> {
+
+        /** A function used to map OIDC ACR/AMRs to Principals. A single instance is supplied.*/
+        private final Function<Collection<String>,Collection<Principal>> function; 
+        
+        /**
+         * 
+         * Constructor.
+         *
+         * @param wrappedFunction the function to return when requested.          
+         */
+        public LookupFunctionWrapper(@ParameterName(name="wrappedFunction") 
+                final Function<Collection<String>,Collection<Principal>> wrappedFunction) {
+            function = Constraint.isNotNull(wrappedFunction, "Lookup function can not be null");
+        }
+        
+        @Override
+        public Function<Collection<String>, Collection<Principal>> apply(final ProfileRequestContext prc) {
+            return function;
+        }
+        
+    }
+}
+
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/AbstractOAuth2ClientAuthenticableProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
index 86584f4..d6d0f9f 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/AbstractOAuth2ClientAuthenticableProfileConfiguration.java
@@ -37,6 +37,7 @@ import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.profile.config.AbstractConditionalProfileConfiguration;
 import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
 import net.shibboleth.oidc.jwt.claims.ClaimsValidator;
+import net.shibboleth.oidc.security.credential.ClientSecretCredential;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonNegative;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -56,6 +57,9 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
     /** Enabled token endpoint authentication methods. */
     @Nonnull private Function<ProfileRequestContext,Set<String>> tokenEndpointAuthMethodsLookupStrategy;
     
+    /** The token endpoint authentication method to use with an upstream OpenID Provider. */
+    @Nonnull private Function<ProfileRequestContext,String> tokenEndpointAuthMethodLookupStrategy;
+    
     /** Validation of JWT claims for subset of client auth methods. */
     @Nonnull private Function<ProfileRequestContext,ClaimsValidator> claimsValidatorLookupStrategy;
 
@@ -75,6 +79,14 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
     /** Lookup function to supply post authentication flows. */
     @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
     
+    /** Lookup function to retrieve a client credential from the given profile request context. */
+    @Nonnull private Function<ProfileRequestContext, ClientSecretCredential> clientCredentialLookupStrategy;
+    
+    /** Lookup function to retrieve the client_id from the given profile request context.*/
+    //TODO this is the same as the issuer in the proxy context?
+    @Nonnull private Function<ProfileRequestContext, String> clientIdLookupStrategy;
+
+    
     /**
      * Constructor.
      *
@@ -89,13 +101,17 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
                         ClientAuthenticationMethod.CLIENT_SECRET_POST.toString(),
                         ClientAuthenticationMethod.CLIENT_SECRET_JWT.toString(),
                         ClientAuthenticationMethod.PRIVATE_KEY_JWT.toString()));
+        tokenEndpointAuthMethodLookupStrategy = 
+                FunctionSupport.constant(ClientAuthenticationMethod.CLIENT_SECRET_BASIC.toString());
         claimsValidatorLookupStrategy = FunctionSupport.constant(null);
-        
         forceAuthnPredicate = Predicates.alwaysFalse();
         proxyCountLookupStrategy = FunctionSupport.constant(null);
         defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
         authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
         postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+        clientCredentialLookupStrategy = FunctionSupport.constant(null);
+        clientIdLookupStrategy = FunctionSupport.constant(null);   
+        
     }
 
     /**
@@ -141,6 +157,44 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
         tokenEndpointAuthMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
+    /**
+     * Get the token endpoint authentication method to use with an upstream OpenID Provider.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return the token endpoint authentication method to use.
+     * 
+     * @since 2.2.0
+     */
+    @Nonnull public String getTokenEndpointAuthMethod(@Nullable final ProfileRequestContext profileRequestContext) {
+        return tokenEndpointAuthMethodLookupStrategy.apply(profileRequestContext);
+    }
+    
+    /**
+     * Set the enabled token endpoint authentication method to use with an upstream OpenID Provider.
+     * 
+     * @param method the token endpoint authentication method to set.
+     * 
+     * @since 2.2.0
+     */
+    public void setTokenEndpointAuthMethod(@Nonnull @NonnullElements final String method) {
+        tokenEndpointAuthMethodLookupStrategy =
+                FunctionSupport.constant(Constraint.isNotNull(method, "Collection of methods cannot be null"));
+    }
+
+    /**
+     * Set a lookup strategy to find the enabled token endpoint authentication method to use with an 
+     * upstream OpenID Provider.
+     *
+     * @param strategy  lookup strategy
+     * 
+     * @since 2.2.0
+     */
+    public void setTokenEndpointAuthMethodLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, String> strategy) {
+        tokenEndpointAuthMethodLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+    
     /**
      * Get the {@link ClaimsValidator} to apply to JWT-based client authentication.
      * 
@@ -343,4 +397,79 @@ public abstract class AbstractOAuth2ClientAuthenticableProfileConfiguration
         defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
+    /**
+     * Set the client credential lookup strategy.
+     *
+     * @param strategy the strategy to use
+     * 
+     * @since 2.2.0
+     */
+    public void setClientCredentialLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, ClientSecretCredential> strategy) {
+        clientCredentialLookupStrategy =
+                Constraint.isNotNull(strategy, "Client credential lookup strategy can not be null");
+    }
+
+    /**
+     * Set a fixed client credential to use no matter what the context/request.
+     *
+     * @param clientCredential the static client credential to use
+     * 
+     * @since 2.2.0
+     */
+    public void setClientCredential(@Nullable final ClientSecretCredential clientCredential) {
+        clientCredentialLookupStrategy = FunctionSupport.constant(clientCredential);
+    }
+
+    /**
+     * Get the client credential for the given context. Typically a client_secret
+     * associated with the current client_id.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return the client credential
+     * 
+     * @since 2.2.0
+     */
+    public ClientSecretCredential getClientCredential(
+            @Nullable final ProfileRequestContext profileRequestContext) {
+        return clientCredentialLookupStrategy.apply(profileRequestContext);
+    }
+    
+    /**
+     * Set the strategy to locate a client_id.
+     *
+     * @param strategy the strategy to use
+     * 
+     * @since 2.2.0
+     */
+    public void setClientIdLookupStrategy(@Nonnull final Function<ProfileRequestContext, String> strategy) {
+        clientIdLookupStrategy = Constraint.isNotNull(strategy, "Client ID lookup strategy can not be null");
+    }
+
+    /**
+     * Set a fixed client_id to use no matter what the context/request.
+     *
+     * @param clientId the static clientId to use
+     * 
+     * @since 2.2.0
+     */
+    public void setClientId(@Nullable final String clientId) {
+        clientIdLookupStrategy = FunctionSupport.constant(StringSupport.trimOrNull(clientId));
+    }
+
+    /**
+     * Get the client_id appropriate for the given context. Typically that associated
+     * with the chosen downstream OpenID Connect Provider.
+     *
+     * @param profileRequestContext the profile request context
+     *
+     * @return the client_id
+     * 
+     * @since 2.2.0
+     */
+    public String getClientId(@Nullable final ProfileRequestContext profileRequestContext) {
+        return clientIdLookupStrategy.apply(profileRequestContext);
+    }
+    
 }
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/oidc-common-profile-api/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
new file mode 100644
index 0000000..245a048
--- /dev/null
+++ b/oidc-common-profile-api/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <!-- Generic OIDC System beans needed for OIDC based extensions to function, loaded after global.xml.  -->
+    
+    <!-- Credential bean factories -->
+    <bean id="shibboleth.oidc.ClientSecretCredential" abstract="true"
+        class="net.shibboleth.oidc.security.credential.impl.BasicClientSecretCredentialFactoryBean" />    
+        
+    <bean id="shibboleth.oidc.JWKCredential" abstract="true"
+        class="net.shibboleth.oidc.security.credential.impl.BasicJWKCredentialFactoryBean" />
+    
+    <!-- Singleton JWK cache -->
+    <bean id="shibboleth.oidc.RemoteJwkSetCache"
+        class="net.shibboleth.oidc.jwk.RemoteJwkSetCache"
+        p:storage-ref="#{'%{idp.oidc.jwk.StorageService:shibboleth.StorageService}'.trim()}"
+        p:httpClient="#{getObject('shibboleth.oidc.NonBrowser.HttpClient') ?: getObject('shibboleth.InternalHttpClient')}"
+        p:httpClientSecurityParameters="#{getObject('shibboleth.oidc.NonBrowser.HttpClientSecurityParameters')}" />
+
+</beans>
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/attribute/registry/postconfig.xml b/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/attribute/registry/postconfig.xml
new file mode 100644
index 0000000..75ffe22
--- /dev/null
+++ b/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/attribute/registry/postconfig.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util"
+    xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <!-- Necessary for encoder parsing and claims mapping to function. -->
+    
+    <bean id="OIDCByteTranscoder"
+        class="net.shibboleth.oidc.attribute.transcoding.impl.OIDCByteAttributeTranscoder" />
+
+    <bean id="OIDCStringTranscoder"
+        class="net.shibboleth.oidc.attribute.transcoding.impl.OIDCStringAttributeTranscoder" />
+
+    <bean id="OIDCScopedStringTranscoder"
+        class="net.shibboleth.oidc.attribute.transcoding.impl.OIDCScopedStringAttributeTranscoder" />
+    
+</beans>
diff --git a/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml b/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
new file mode 100644
index 0000000..b59c919
--- /dev/null
+++ b/oidc-common-profile-api/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+    default-init-method="initialize" default-destroy-method="destroy">
+        
+   <!-- 
+        Security Configuration Defaults. These settings establish the default security configurations for 
+        signatures and loads the default credentials used. 
+    --> 
+   <bean id="shibboleth.oidc.BasicSignatureValidationConfiguration" abstract="true"
+        class="net.shibboleth.oidc.security.jose.impl.BasicSignatureValidationConfiguration"
+        p:includedAlgorithms="#{getObject('shibboleth.oidc.IncludedSignatureAlgorithms')}"
+        p:excludedAlgorithms="#{getObject('shibboleth.oidc.ExcludedSignatureAlgorithms')}" />
+    
+    <bean id="shibboleth.oidc.BasicSignatureSigningConfiguration" abstract="true"
+        class="net.shibboleth.oidc.security.jose.impl.BasicSignatureSigningConfiguration"
+        p:includedAlgorithms="#{getObject('shibboleth.oidc.IncludedSignatureAlgorithms')}"
+        p:excludedAlgorithms="#{getObject('shibboleth.oidc.ExcludedSignatureAlgorithms')}" />
+    
+    <bean id="shibboleth.oidc.BasicEncryptionConfiguration" abstract="true"
+        class="net.shibboleth.oidc.security.jose.impl.BasicEncryptionConfiguration"
+        p:includedAlgorithms="#{getObject('shibboleth.oidc.IncludedEncryptionAlgorithms')}"
+        p:excludedAlgorithms="#{getObject('shibboleth.oidc.ExcludedEncryptionAlgorithms')}" />
+
+    <bean id="shibboleth.oidc.BasicDecryptionConfiguration" abstract="true"
+        class="net.shibboleth.oidc.security.jose.impl.BasicDecryptionConfiguration"
+        p:includedAlgorithms="#{getObject('shibboleth.oidc.IncludedEncryptionAlgorithms')}"
+        p:excludedAlgorithms="#{getObject('shibboleth.oidc.ExcludedEncryptionAlgorithms')}" />
+        
+    <bean id="AbstractOIDCProfile" abstract="true"
+        p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}" />
+
+<!-- p:claimsValidator-ref="DefaultJWTClaimsValidator" -->
+    <bean id="AbstractOIDCSSOProfile" parent="AbstractOIDCProfile" abstract="true" 
+        p:issuer-ref="issuer"        
+        p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_poster,client_secret_jwt,private_key_jwt}"
+        p:claimsValidator="#{getObject('shibboleth.oidc.DefaultJWTClaimsValidator')}"
+        p:encryptionOptional="%{idp.oidc.encryptionOptional:true}"
+        p:forcePKCE="%{idp.oidc.forcePKCE:false}"
+        p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
+        p:iDTokenLifetime="%{idp.oidc.idToken.defaultLifetime:PT1H}"
+        p:accessTokenType="%{idp.oauth2.accessToken.type:}"
+        p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
+        p:refreshTokenLifetime="%{idp.oidc.refreshToken.defaultLifetime:PT2H}"
+        p:alwaysIncludedAttributes="%{idp.oidc.alwaysIncludedAttributes:}"        
+        p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
+        p:responseMode="%{idp.authn.oidc.rp.client.responseMode:#{null}}"
+        p:clientId="#{%{idp.authn.oidc.rp.provider.discoveryRequired:false} == true ? null : '%{idp.authn.oidc.rp.client.clientId:}'}"
+        p:clientCredential="#{%{idp.authn.oidc.rp.provider.discoveryRequired:false} == true ? {null} : getObject('shibboleth.authn.oidc.rp.DefaultCredential')}"/>
+
+   <bean id="OIDC.SSO" parent="AbstractOIDCSSOProfile" lazy-init="true"
+        class="net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration"        
+        p:authorizeCodeLifetime="%{idp.oidc.authorizeCode.defaultLifetime:PT5M}"
+        p:encodeConsentInTokens="%{idp.oidc.encodeConsentInTokens:false}"
+        p:encodedAttributes="%{idp.oidc.encodedAttributes:%{idp.oidc.embeddedAttributes:}}"
+        p:deniedUserInfoAttributes="%{idp.oidc.deniedUserInfoAttributes:}"        
+        p:httpRequestMethod="%{idp.authn.oidc.rp.httpRequestMethod:GET}"       
+        p:retrieveUserInfoEndpointClaims="%{idp.authn.oidc.rp.client.userinfo.enabled:true}"        
+        p:redirectUriOverride="%{idp.authn.oidc.rp.client.redirectURI:#{null}}"
+        p:encryptRequestObject="%{idp.authn.oidc.rp.client.requestobject.encrypted:false}"
+        p:signRequestObject="%{idp.authn.oidc.rp.client.requestobject.signed:true}"
+        p:useRequestObject="%{idp.authn.oidc.rp.client.requestobject.supported:false}"
+        p:scopes="%{idp.authn.oidc.rp.client.scopes:#{null}}">
+        <property name="forceAuthnPredicate">
+            <bean class="net.shibboleth.idp.saml.profile.config.logic.ProxyAwareForceAuthnPredicate" />
+        </property>
+        <property name="defaultAuthenticationMethodsLookupStrategy">
+            <bean
+                class="net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction"
+                p:mappings="#{getObject('shibboleth.oidc.PrincipalProxyRequestMappings')}" />
+        </property>
+         <property name="authenticationContextClassReferenceTranslationStrategyLookupStrategy">
+            <bean
+                class="net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction$LookupFunctionWrapper">
+                <constructor-arg>
+                    <bean class="net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction"
+                    c:mappings="#{getObject('shibboleth.oidc.PrincipalProxyResponseMappings')}"/>
+                </constructor-arg>
+            </bean>
+        </property>
+         <property name="authenticationMethodsReferencesTranslationStrategyLookupStrategy">
+            <bean
+                class="net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction$LookupFunctionWrapper">
+                <constructor-arg>
+                    <bean class="net.shibboleth.oidc.profile.config.navigate.ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction"
+                    c:mappings="#{getObject('shibboleth.oidc.PrincipalProxyResponseMappings')}"/>
+                </constructor-arg>
+            </bean>
+        </property>
+    </bean>
+    
+    <!-- Keyset profile -->
+    <bean id="OIDC.Keyset" parent="AbstractOIDCProfile" lazy-init="true"
+        class="net.shibboleth.oidc.profile.config.OIDCPublishKeySetConfiguration"
+        p:securityConfiguration-ref="shibboleth.oidc.PublishKeySetSecurityConfiguration" />
+        
+     <!--  Configuration for publishing key set. -->
+    <bean id="shibboleth.oidc.PublishKeySetSecurityConfiguration"
+        class="net.shibboleth.oidc.profile.config.JSONSecurityConfiguration">
+       <property name="jwtSignatureSigningConfiguration">
+            <ref bean="shibboleth.oidc.PublishKeySetSigningConfiguration" />
+        </property>
+        <property name="jwtDecryptionConfiguration">
+            <ref bean="shibboleth.oidc.PublishKeySetDecryptionConfiguration" />
+        </property>
+    </bean>
+    
+    <!--  Signing keys to publish. -->
+    <bean id="shibboleth.oidc.PublishKeySetSigningConfiguration" 
+        parent="shibboleth.oidc.BasicSignatureSigningConfiguration"
+        p:signingCredentials="#{getObject('shibboleth.oidc.SigningCredentialsToPublish') ?: getObject('shibboleth.oidc.SigningCredentialsFactory')}"/>
+    
+    <!--  Encryption keys to publish. -->   
+    <bean id="shibboleth.oidc.PublishKeySetDecryptionConfiguration" 
+        parent="shibboleth.oidc.BasicDecryptionConfiguration">
+        <property name="KEKCredentialResolver">
+            <bean id="defaultOIDCKeyDecryptionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ReturnAllCollectionJOSEObjectCredentialResolver"
+                    c:credentials="#{getObject('shibboleth.oidc.EncryptionCredentialsToPublish') ?: getObject('shibboleth.oidc.EncryptionCredentialsToPublishFactory')}"/>
+        </property>    
+    </bean>
+    
+    <bean id="shibboleth.oidc.EncryptionCredentialsToPublishFactory"
+        class="net.shibboleth.oidc.profile.config.CredentialsListFactory"
+        c:_0="#{getObject('shibboleth.oidc.EncryptionCredentials')}" />
+     
+
+    <bean id="shibboleth.oidc.DefaultSecurityConfiguration"
+        class="net.shibboleth.oidc.profile.config.JSONSecurityConfiguration">
+        <property name="jwtSignatureSigningConfiguration">
+            <ref bean="#{'%{idp.oidc.signing.config:shibboleth.oidc.SigningConfiguration}'.trim()}" />
+        </property>
+        <property name="jwtEncryptionConfiguration">
+            <ref bean="#{'%{idp.oidc.encryption.config:shibboleth.oidc.EncryptionConfiguration}'.trim()}" />
+        </property>
+        <property name="jwtDecryptionConfiguration">
+            <ref bean="#{'%{idp.oidc.decryption.config:shibboleth.oidc.DecryptionConfiguration}'.trim()}" />
+        </property>
+        <property name="jwtSignatureValidationConfiguration">
+            <ref bean="#{'%{idp.oidc.validation.config:shibboleth.oidc.SignatureValidationConfiguration}'.trim()}" />
+        </property>
+    </bean>
+    
+    <bean id="shibboleth.oidc.SigningConfiguration"
+        parent="shibboleth.oidc.BasicSignatureSigningConfiguration"
+        p:signingCredentials-ref="shibboleth.oidc.SigningCredentialsFactory">
+        <property name="signatureAlgorithms">
+            <list>
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_384" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_RS_512" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_384" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.SignatureConstants.ALGO_ID_SIGNATURE_HS_512" />
+            </list>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.oidc.EncryptionConfiguration" parent="shibboleth.oidc.BasicEncryptionConfiguration"
+        p:KEKCredentialResolver-ref="defaultOIDCKeyEncryptionCredentialResolver"
+        p:contentEncryptionKeyCredentialResolver-ref="defaultOIDCContentEncryptionKeyCredentialResolver">
+        <property name="keyTransportEncryptionAlgorithms">
+            <list>
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_RSA_1_5" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_128_KW" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_192_KW" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_256_KW" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_128_GCM_KW" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_192_GCM_KW" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.KeyManagementConstants.ALGO_ID_ALG_AES_256_GCM_KW" />
+            </list>
+        </property>
+        <property name="dataEncryptionAlgorithms">
+            <list>
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A192CBC_HS384" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A128GCM" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A192GCM" />
+                <util:constant
+                    static-field="net.shibboleth.oidc.jwa.support.EncryptionConstants.ALGO_ID_ENC_ALG_A256GCM" />
+            </list>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.oidc.SigningCredentialsFactory"
+        class="net.shibboleth.oidc.profile.config.CredentialsListFactory"
+        c:_0="#{getObject('shibboleth.oidc.SigningCredentials')}" />
+        
+    <bean id="defaultOIDCKeyEncryptionCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
+        <constructor-arg>
+            <list>
+                <!-- Used by the OP -->
+                <bean id="ClientInformationCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientInformationCredentialResolver"
+                    p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" 
+                    p:keyFetchInterval="%{idp.oidc.provider.keyfetch.interval:PT30M}"/>
+                <!--  Used by the RP -->
+                <bean id="OIDCProviderMetadataCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ProviderMetadataCredentialResolver"
+                    p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache"
+                    p:keyFetchInterval="%{idp.oidc.provider.keyfetch.interval:PT30M}" />
+                <bean id="ClientSecretCriterionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>
+    
+     <bean id="defaultOIDCContentEncryptionKeyCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
+        <constructor-arg>
+            <list>
+                <!-- Used by the OP -->
+                <bean id="ClientInformationCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientInformationCredentialResolver"
+                    p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" 
+                    p:keyFetchInterval="%{idp.oidc.provider.keyfetch.interval:PT30M}"/>
+                <!--  Used by the RP -->
+                <bean id="ClientSecretCriterionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>   
+    
+    <bean id="shibboleth.oidc.DecryptionConfiguration"
+        parent="shibboleth.oidc.BasicDecryptionConfiguration"
+        p:KEKCredentialResolver-ref="defaultOIDCKeyDecryptionCredentialResolver"
+        p:contentEncryptionKeyCredentialResolver-ref="defaultOIDCContentDecryptionKeyCredentialResolver">
+    </bean>
+    
+    <!-- 
+        A resolver to public/private key encryption keys global to the RP 
+    -->
+    <bean id="defaultOIDCKeyDecryptionCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
+        <constructor-arg>
+            <list>
+                <bean class="net.shibboleth.oidc.security.credential.impl.LocalJOSEObjectCredentialResolver">
+                    <constructor-arg name="localCredentialResolver">
+                        <bean
+                            class="net.shibboleth.oidc.security.credential.impl.CollectionJOSEObjectCredentialResolver"
+                            c:credentials-ref="shibboleth.oidc.EncryptionCredentials" />
+                    </constructor-arg>
+                </bean>
+                <bean id="CriterionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>
+    
+    <bean id="defaultOIDCContentDecryptionKeyCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
+        <constructor-arg>
+            <list>
+                <bean id="CriterionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>    
+    
+    <bean id="shibboleth.oidc.SignatureValidationConfiguration" 
+        parent="shibboleth.oidc.BasicSignatureValidationConfiguration"
+        p:signatureTrustEngine-ref="ExplicitKeySignedJWTTrustEngine"/>
+        
+        
+    <bean id="ExplicitKeySignedJWTTrustEngine"
+        class="net.shibboleth.oidc.security.impl.ExplicitKeySignedJWTTrustEngine"
+        c:resolver-ref="defaultSignedJWTTrustedCredentialResolver"
+        c:JOSEObjectResolver-ref="defaultSignedJWTJOSEHeaderCredentialResolver" />
+        
+    <!-- A resolver for resolving 'untrusted' credentials out of the JOSE header of JWTs -->
+    <bean id="defaultSignedJWTJOSEHeaderCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.BasicJOSEObjectCredentialResolver" />
+    
+     <!-- A resolver for resolving trusted credentials to match against those resolved from the JWT -->
+    <bean id="defaultSignedJWTTrustedCredentialResolver"
+        class="net.shibboleth.oidc.security.credential.impl.ChainingJOSEObjectCredentialResolver">
+        <constructor-arg>
+            <list>
+                <!-- Used by the OP -->
+                <bean id="ClientInformationCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientInformationCredentialResolver"
+                    p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" 
+                    p:keyFetchInterval="%{idp.oidc.provider.keyfetch.interval:PT30M}"/>
+                <!--  Used by the RP -->
+                <bean id="OIDCProviderMetadataCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ProviderMetadataCredentialResolver"
+                    p:remoteJwkSetCache-ref="shibboleth.oidc.RemoteJwkSetCache" 
+                    p:keyFetchInterval="%{idp.oidc.provider.keyfetch.interval:PT30M}"/>
+                <bean id="CriterionCredentialResolver"
+                    class="net.shibboleth.oidc.security.credential.impl.ClientSecretCriterionCredentialResolver"/>
+            </list>
+        </constructor-arg>
+    </bean>
+
+
+</beans>
diff --git a/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/CredentialsListFactoryTest.java b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/CredentialsListFactoryTest.java
new file mode 100644
index 0000000..3fe818d
--- /dev/null
+++ b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/CredentialsListFactoryTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package net.shibboleth.oidc.profile.config;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.opensaml.security.credential.Credential;
+import org.testng.annotations.Test;
+
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
+
+/** Tests for the {@link CredentialsListFactory}.*/
+public class CredentialsListFactoryTest {
+    
+    /** 
+     * Test with a null input list.
+     * 
+     * @throws Exception on error
+     */
+    @Test
+    public void testNullInputList() throws Exception {
+        final CredentialsListFactory factory = new CredentialsListFactory(null);
+        factory.afterPropertiesSet();
+        final List<Credential> creds = factory.createInstance();
+        assertNotNull(creds);
+        assertTrue(creds.isEmpty());
+    }
+    
+    
+    /** 
+     * Test with an input list with a null element.
+     * 
+     * @throws Exception on error
+     */
+    @Test
+    public void testInputListWithNullElement() throws Exception {
+        final var credsIn = new ArrayList<Credential>();
+        credsIn.add(null);
+        final CredentialsListFactory factory = new CredentialsListFactory(credsIn);
+        factory.afterPropertiesSet();
+        final List<Credential> creds = factory.createInstance();
+        assertNotNull(creds);
+        assertTrue(creds.isEmpty());
+    }
+    
+    /** 
+     * Test with an input list with one null element.
+     * 
+     * @throws Exception on error
+     */
+    @Test
+    public void testInputListWithOneNullElement() throws Exception {
+        final var credsIn = new ArrayList<Credential>();
+        credsIn.add(null);
+        credsIn.add(new BasicJWKCredential());
+        final CredentialsListFactory factory = new CredentialsListFactory(credsIn);
+        factory.afterPropertiesSet();
+        final List<Credential> creds = factory.createInstance();
+        assertNotNull(creds);
+        assertTrue(creds.size()==1);
+    }
+
+}
diff --git a/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunctionTest.java b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunctionTest.java
new file mode 100644
index 0000000..244abf8
--- /dev/null
+++ b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunctionTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.navigate;
+
+import static org.testng.Assert.assertTrue;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+
+/** Tests for ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunction.*/
+public class ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunctionTest {
+    
+    private ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction function;
+    
+    private ProfileRequestContext prc;
+    
+    private ProfileRequestContext nestedPrc;
+    
+    private AuthenticationContext ac;
+    
+    private RequestedPrincipalContext rpc;
+    
+    @BeforeMethod
+    public void setup() {
+        function = new ProxyAwareDefaultOIDCAuthenticationContextClassRequestLookupFunction();
+        prc = new ProfileRequestContext();
+        ac = prc.getSubcontext(AuthenticationContext.class, true);
+        nestedPrc = ac.getSubcontext(ProfileRequestContext.class, true);
+        rpc = ac.getSubcontext(RequestedPrincipalContext.class, true);
+    }
+    
+    @Test
+    public void testSingleMappingSuccess() {
+        
+        
+        final List<Principal> requestedPrincipals = 
+                List.of(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"));
+        rpc.setRequestedPrincipals(requestedPrincipals);
+        rpc.setOperator("exact");
+        
+        final Map<Principal,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"), 
+                List.of(new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa")));
+        function.setMappings(mappings);
+        
+        final Collection<AuthenticationContextClassReferencePrincipal> mapped = function.apply(nestedPrc);
+        System.out.println(mapped);
+        assertTrue(mapped.contains(
+                        new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa")));
+        
+    }
+    
+    @Test
+    public void testMappedAndPassedThroughSuccess() {
+        
+        
+        // The second principal is passed-through as no mapping exists
+        final List<Principal> requestedPrincipals = 
+                List.of(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"),
+                        new AuthnContextClassRefPrincipal("http://example.org/ac/classes/pass-through"));
+        rpc.setRequestedPrincipals(requestedPrincipals);
+        rpc.setOperator("exact");
+        
+        final Map<Principal,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"), 
+                List.of(new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa")));
+        function.setMappings(mappings);
+        
+        final Collection<AuthenticationContextClassReferencePrincipal> mapped = function.apply(nestedPrc);
+        System.out.println(mapped);
+        assertTrue(mapped.contains(
+                        new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa")));
+        assertTrue(mapped.contains(
+                new AuthenticationContextClassReferencePrincipal("http://example.org/ac/classes/pass-through")));
+        
+    }
+    
+    @Test
+    public void testMultipleMappedAndPassedThroughSuccess() {
+        
+        
+        // The second principal is passed-through as no mapping exists
+        final List<Principal> requestedPrincipals = 
+                List.of(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"),
+                        new AuthnContextClassRefPrincipal("http://example.org/ac/classes/pass-through"));
+        rpc.setRequestedPrincipals(requestedPrincipals);
+        rpc.setOperator("exact");
+        
+        final Map<Principal,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put(new AuthnContextClassRefPrincipal("http://example.org/ac/classes/mfa"), 
+                List.of(new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa"),
+                        new AuthenticationContextClassReferencePrincipal(
+                                "http://proxy.two.example.org/ac/classes/mfa")));
+        function.setMappings(mappings);
+        
+        final Collection<AuthenticationContextClassReferencePrincipal> mapped = function.apply(nestedPrc);
+        System.out.println(mapped);
+        assertTrue(mapped.contains(
+                        new AuthenticationContextClassReferencePrincipal("http://proxy.example.org/ac/classes/mfa")));
+        assertTrue(mapped.contains(
+                new AuthenticationContextClassReferencePrincipal("http://proxy.two.example.org/ac/classes/mfa")));
+        assertTrue(mapped.contains(
+                new AuthenticationContextClassReferencePrincipal("http://example.org/ac/classes/pass-through")));
+        
+    }
+
+}
diff --git a/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunctionTest.java b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunctionTest.java
new file mode 100644
index 0000000..401d057
--- /dev/null
+++ b/oidc-common-profile-api/src/test/java/net/shibboleth/oidc/profile/config/navigate/ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunctionTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.profile.config.navigate;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
+
+/** Tests for ProxyAwareDefaultOIDCAuthenticationContextClassLookupFunction.*/
+public class ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunctionTest {
+    
+    private ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction function;
+    
+    private ProfileRequestContext prc;
+    
+    private ProfileRequestContext nestedPrc;
+    
+    private AuthenticationContext ac;
+    
+    private RequestedPrincipalContext rpc;
+    
+    @BeforeMethod
+    public void setup() {        
+        prc = new ProfileRequestContext();
+        ac = prc.getSubcontext(AuthenticationContext.class, true);
+        nestedPrc = ac.getSubcontext(ProfileRequestContext.class, true);
+        rpc = ac.getSubcontext(RequestedPrincipalContext.class, true);
+    }
+    
+    @Test
+    public void testSingleMappingSuccess() {
+        
+        final Map<String,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put(
+                "pwd", 
+                List.of(new AuthenticationMethodPrincipal
+                        ("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")));
+
+        function = new ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction(mappings);
+        
+        final Collection<Principal> mapped = function.apply(List.of("pwd"));
+        assertTrue(mapped.contains(
+                        new AuthenticationMethodPrincipal
+                        ("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")));
+        
+    }
+    
+    @Test
+    public void testSingleMappingSuccess_NotMappedIgnored() {
+        
+        
+        final Map<String,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put(
+                "pwd", 
+                List.of(new AuthenticationMethodPrincipal
+                        ("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")));
+        function = new ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction(mappings);;
+        
+        // OTP should not be in the result
+        final Collection<Principal> mapped = function.apply(List.of("pwd","otp"));
+        assertEquals(mapped.size(), 1);
+        assertTrue(mapped.contains(new AuthenticationMethodPrincipal
+                        ("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")));
+       
+    }
+    
+    @Test
+    public void testSingleMappingSuccess_EmptyInput() {
+        
+        // OTP should not be in the result
+        final Collection<Principal> mapped = function.apply(Collections.emptyList());
+        assertEquals(mapped.size(), 0);
+    }
+    
+    @Test
+    public void testSingleMappingSuccess_NullMappings() {
+        
+        function = new ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction(null);
+        
+        // OTP should not be in the result
+        final Collection<Principal> mapped = function.apply(Collections.emptyList());
+        assertEquals(mapped.size(), 0);
+    }
+    
+    @Test
+    public void testSingleMappingSuccess_EmptyMapping() {
+        
+        final Map<String,Collection<Principal>> mappings = new HashMap<>();
+        mappings.put("pwd", Collections.emptyList());
+        function = new ProxyAwareDefaultOIDCAuthenticationContextClassResponseLookupFunction(mappings);
+        
+        // OTP should not be in the result
+        final Collection<Principal> mapped = function.apply(Collections.emptyList());
+        assertEquals(mapped.size(), 0);
+    }
+
+
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list