[java-oidc-common] branch main updated: JCOMOIDC-184 - Move OAuth2Client authentication flow from OP to oidc-common

Codeberg noreply at shibboleth.net
Tue Sep 22 14:39:23 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-oidc-common.

View the commit online:
https://codeberg.org/Shibboleth/java-oidc-common/commit/ad4a01b358a6b9e9bb5335f615a1dc40e4c7e8dd

The following commit(s) were added to refs/heads/main by this push:
     new ad4a01b3 JCOMOIDC-184 - Move OAuth2Client authentication flow from OP to oidc-common
ad4a01b3 is described below

commit ad4a01b358a6b9e9bb5335f615a1dc40e4c7e8dd
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Tue Sep 22 17:38:03 2026 +0300

    JCOMOIDC-184 - Move OAuth2Client authentication flow from OP to oidc-common
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-184
    
    OAuth2Client authentication flow and its descriptor in a new oidc-common-conf-impl module
---
 oidc-common-bom/pom.xml                            |   5 +
 oidc-common-conf-impl/pom.xml                      | 193 ++++++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  32 +++
 .../authn/OAuth2Client/OAuth2Client-beans.xml      | 292 +++++++++++++++++++++
 .../flows/authn/OAuth2Client/OAuth2Client-flow.xml |  43 +++
 pom.xml                                            |   1 +
 6 files changed, 566 insertions(+)

diff --git a/oidc-common-bom/pom.xml b/oidc-common-bom/pom.xml
index 182bca02..5648cb92 100644
--- a/oidc-common-bom/pom.xml
+++ b/oidc-common-bom/pom.xml
@@ -66,6 +66,11 @@
                 <artifactId>oidc-common-saml-impl</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>oidc-common-conf-impl</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>com.nimbusds</groupId>
                 <artifactId>oauth2-oidc-sdk</artifactId>
diff --git a/oidc-common-conf-impl/pom.xml b/oidc-common-conf-impl/pom.xml
new file mode 100644
index 00000000..6d525acb
--- /dev/null
+++ b/oidc-common-conf-impl/pom.xml
@@ -0,0 +1,193 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>net.shibboleth.oidc</groupId>
+        <artifactId>oidc-common-parent</artifactId>
+        <version>3.4.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>oidc-common-conf-impl</artifactId>
+    <packaging>jar</packaging>
+    <name>Shibboleth IdP :: Plugins :: OIDC Common :: Configuration</name>
+    <description>Configuration for the Shibboleth OIDC Java common library.</description>
+
+    <properties>
+        <checkstyle.configLocation>${project.basedir}/../resources/checkstyle/checkstyle.xml</checkstyle.configLocation>
+        <automatic.module.name>net.shibboleth.oidc.conf.impl</automatic.module.name>
+    </properties>
+
+    <dependencies>
+        <!-- Compile Dependencies -->
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+        </dependency>
+        
+        <!-- Provided Dependencies -->
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>oidc-common-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>oidc-common-profile-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>oidc-common-crypto-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>oidc-common-metadata-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-authn-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-authn-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${shib-profile.groupId}</groupId>
+            <artifactId>shib-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-core-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-messaging-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-profile-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-security-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-security-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-storage-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-xmlsec-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-xmlsec-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${shib-shared.groupId}</groupId>
+            <artifactId>shib-support</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${spring.groupId}</groupId>
+            <artifactId>spring-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${spring-webflow.groupId}</groupId>
+            <artifactId>spring-webflow</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${httpclient.groupId}</groupId>
+            <artifactId>${httpclient.artifactId}</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${httpclient.httpcore.groupId}</groupId>
+            <artifactId>${httpclient.httpcore.artifactId}</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>oauth2-oidc-sdk</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Test scope -->
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-storage-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-authn-impl</artifactId>
+            <version>${idp.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies-test</id>
+                        <phase>prepare-package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.target.directory}</outputDirectory>
+                            <includeScope>runtime</includeScope>
+                            <excludeTransitive>true</excludeTransitive>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/oidc-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/oidc-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
new file mode 100644
index 00000000..282b85c1
--- /dev/null
+++ b/oidc-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -0,0 +1,32 @@
+<?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">
+
+    <!-- OAuth2 login flow -->
+    <bean p:id="authn/OAuth2Client" parent="shibboleth.AuthenticationFlow"
+            p:order="%{idp.authn.OAuth2Client.order:1000}"
+            p:nonBrowserSupported="true"
+            p:passiveAuthenticationSupported="true"
+            p:forcedAuthenticationSupported="true"
+            p:proxyRestrictionsEnforced="true"
+            p:proxyScopingEnforced="false"
+            p:discoveryRequired="false"
+            p:lifetime="PT60S"
+            p:inactivityTimeout="PT60S"
+            p:reuseCondition-ref="shibboleth.Conditions.FALSE"
+            p:activationCondition-ref="#{'%{idp.authn.OAuth2Client.activationCondition:shibboleth.Conditions.TRUE}'.trim()}"
+            p:subjectDecorator="#{getObject('%{idp.authn.OAuth2Client.subjectDecorator:}'.trim())}">
+        <property name="supportedPrincipalsByString">
+            <bean parent="shibboleth.CommaDelimStringArray"
+                c:_0="#{'%{idp.authn.OAuth2Client.supportedPrincipals:}'.trim()}" />
+        </property>
+    </bean>
+
+</beans>
diff --git a/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml b/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml
new file mode 100644
index 00000000..1a1449a4
--- /dev/null
+++ b/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-beans.xml
@@ -0,0 +1,292 @@
+<?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">
+       
+    <!-- Default message map. -->
+    <util:map id="shibboleth.authn.OAuth2Client.ClassifiedMessageMap">
+        <entry key="RequestUnsupported">
+            <list>
+                <value>RequestUnsupported</value>
+            </list>
+        </entry>
+    </util:map>
+
+    <import resource="conditional:%{idp.home}/conf/authn/oauth2client-authn-config.xml" />
+
+    <bean id="ExtractClientAuthenticationFromRequest"
+        class="net.shibboleth.oidc.authn.impl.ExtractClientAuthenticationFromRequest" scope="prototype"
+        p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
+
+    <bean id="PopulateTokenEndpointJwtSignatureValidationParameters"
+            class="net.shibboleth.oidc.profile.impl.PopulateJWTSignatureValidationParameters"
+            scope="prototype"
+            c:strategy-ref="shibboleth.MessageContextLookup.Inbound">
+        <property name="configurationLookupStrategy">
+            <bean class="net.shibboleth.oidc.profile.config.navigate.JWTSignatureValidationConfigurationLookupFunction" />
+       </property>
+        <property name="signatureValidationParametersResolver">
+            <bean class="net.shibboleth.oidc.security.jose.impl.BasicSignatureValidationParametersResolver" />
+        </property>
+<!--         <property name="securityParametersContextLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose"
+                c:g-ref="shibboleth.ChildLookupOrCreate.SecurityParameters"
+                c:f-ref="shibboleth.ChildLookup.RelyingParty" />
+        </property>
+        <property name="existingParametersContextLookupStrategy">
+            <bean parent="shibboleth.Functions.Compose"
+                c:g-ref="shibboleth.ChildLookup.SecurityParameters"
+                c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+        </property>-->
+    </bean>
+
+    <bean id="JWTAuthenticationCondition" parent="shibboleth.Conditions.Expression"
+        c:expression="#input.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).ensureSubcontext(T(net.shibboleth.oidc.authn.context.OAuth2ClientAuthenticationContext)).getClientAuthentication() instanceof T(com.nimbusds.oauth2.sdk.auth.JWTAuthentication)" />
+
+    <bean id="ValidateJWTSignature" class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor"
+        scope="prototype" c:executionDirection="INBOUND" p:activationCondition-ref="JWTAuthenticationCondition"
+        p:errorEvent="#{T(net.shibboleth.idp.authn.AuthnEventIds).AUTHN_EXCEPTION}">
+        <constructor-arg>
+            <bean class="org.opensaml.messaging.handler.impl.BasicMessageHandlerChain">
+                <property name="handlers">
+                    <list>
+                        <bean class="net.shibboleth.oidc.security.impl.CheckClientJWTSignatureAlgorithmHandler"
+                            scope="prototype" p:defaultAlgorithmValue="">
+                            <property name="jwtTokenLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.profile.context.navigate.SpringExpressionContextLookupFunction"
+                                    c:_0="#{ T(org.opensaml.messaging.context.MessageContext) }"
+                                    c:outputType="#{T(com.nimbusds.jwt.SignedJWT)}"
+                                    c:expression="#input.getParent().ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).ensureSubcontext(T(net.shibboleth.oidc.authn.context.OAuth2ClientAuthenticationContext)).getClientAuthentication().getClientAssertion()" />
+                            </property>
+                            <property name="clientInformationLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.profile.context.navigate.SpringExpressionContextLookupFunction"
+                                    c:_0="#{ T(org.opensaml.messaging.context.MessageContext) }"
+                                    c:expression="#input.ensureSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext)).getClientInformation()" />
+                            </property>
+                            <property name="signatureAlgorithmLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.oidc.profile.config.navigate.ClientInformationStringValueLookupFunction"
+                                    c:keyName="token_endpoint_auth_signing_alg" />
+                            </property>
+                        </bean>
+                        <bean class="net.shibboleth.oidc.security.impl.JWTMessageSignatureSecurityHandler"
+                            scope="prototype">
+                            <property name="jwtTokenLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.profile.context.navigate.SpringExpressionContextLookupFunction"
+                                    c:_0="#{ T(org.opensaml.messaging.context.MessageContext) }"
+                                    c:outputType="#{T(com.nimbusds.jwt.SignedJWT)}"
+                                    c:expression="#input.getParent().ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).ensureSubcontext(T(net.shibboleth.oidc.authn.context.OAuth2ClientAuthenticationContext)).getClientAuthentication().getClientAssertion()" />
+                            </property>
+                            <property name="clientInformationLookupStrategy">
+                                <bean
+                                    class="net.shibboleth.profile.context.navigate.SpringExpressionContextLookupFunction"
+                                    c:_0="#{ T(org.opensaml.messaging.context.MessageContext) }"
+                                    c:expression="#input.ensureSubcontext(T(net.shibboleth.oidc.metadata.context.OIDCMetadataContext)).getClientInformation()" />
+                            </property>
+                        </bean>
+                    </list>
+                </property>
+            </bean>
+        </constructor-arg>
+    </bean>
+
+
+    <bean id="ValidateClientAuthenticationType"
+        class="net.shibboleth.oidc.authn.impl.ValidateClientAuthenticationType" scope="prototype" />
+
+    <bean id="DefaultCleanupHook"
+        class="net.shibboleth.idp.authn.impl.ValidateCredentials.UsernamePasswordCleanupHook" />
+    
+    <bean id="ValidateCredentials"
+        class="net.shibboleth.idp.authn.impl.ValidateCredentials" scope="prototype"
+        p:requireAll="%{idp.authn.OAuth2Client.requireAll:false}"
+        p:validators="#{getObject('shibboleth.authn.OAuth2Client.Validators') ?: getObject('DefaultOAuth2ClientValidators')}"
+        p:addDefaultPrincipals="%{idp.authn.OAuth2Client.addDefaultPrincipals:true}"
+        p:supportedPrincipals="#{getObject('shibboleth.authn.OAuth2Client.PrincipalOverride')}"
+        p:classifiedMessages="#{getObject('shibboleth.authn.OAuth2Client.ClassifiedMessageMap')}"
+        p:cleanupHook="#{T(java.lang.Boolean).valueOf('%{idp.authn.OAuth2Client.removeAfterValidation:true}') ? getObject('DefaultCleanupHook') : null}"
+        p:lockoutManager="#{getObject('shibboleth.authn.OAuth2Client.AccountLockoutManager')}"
+        p:populateAuditContextAction="#{%{idp.authn.OAuth2Client.audit.enabled:%{idp.authn.audit.enabled:false}} ? getObject('shibboleth.authn.OAuth2Client.PopulateAuditContext') : null}"
+        p:writeAuditLogAction="#{%{idp.authn.OAuth2Client.audit.enabled:%{idp.authn.audit.enabled:false}} ? getObject('WriteAuthnAuditLog') : null}" />
+    
+    <bean id="PopulateSubjectCanonicalizationContext"
+        class="net.shibboleth.idp.authn.impl.PopulateSubjectCanonicalizationContext" scope="prototype"
+        p:availableFlows-ref="%{idp.authn.OAuth2Client.c14n.postLoginFlows:shibboleth.PostLoginSubjectCanonicalizationFlows}" />
+        
+    <!-- Default validators equivalent to previous versions. -->
+    
+    <util:list id="DefaultOAuth2ClientValidators">
+        <ref bean="shibboleth.OIDCClientInfoValidator" />
+        <ref bean="shibboleth.JWTValidator" />
+    </util:list>
+        
+    <!-- Validator parent beans -->
+
+    <bean id="shibboleth.CredentialValidator" abstract="true"
+        p:savePasswordToCredentialSet="%{idp.authn.OAuth2Client.retainAsPrivateCredential:false}" />
+
+    <bean id="shibboleth.OIDCClientInfoValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.oidc.authn.impl.OIDCClientInfoCredentialValidator"
+        p:id="oauth2-clientinfo" />
+        
+    <bean id="shibboleth.JWTValidator" class="net.shibboleth.oidc.authn.impl.JWTCredentialValidator"
+        p:id="oauth2-jwt" />
+    
+    <bean id="shibboleth.JAASValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.idp.authn.impl.JAASCredentialValidator" abstract="true"
+        p:id="oauth2-jaas" />
+
+    <bean id="shibboleth.KerberosValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.idp.authn.impl.KerberosCredentialValidator" abstract="true"
+        p:id="oauth2-krb5" />
+
+    <bean id="shibboleth.LDAPValidator" parent="shibboleth.CredentialValidator" lazy-init="true"
+        class="net.shibboleth.idp.authn.impl.LDAPCredentialValidator"
+        p:id="oauth2-ldap"
+        p:authenticator-ref="shibboleth.authn.OAuth2Client.LDAP.authenticator" />
+
+    <bean id="shibboleth.HTPasswdValidator" abstract="true"
+        class="net.shibboleth.idp.authn.impl.HTPasswdCredentialValidator"
+        p:id="oauth2-htpasswd" />
+
+    <bean id="shibboleth.X509Validator" abstract="true"
+        class="net.shibboleth.idp.authn.impl.X509CertificateCredentialValidator"
+        p:id="oauth2-x509" />
+
+    <!-- Parent beans for custom ldaptive types. -->
+    
+    <bean id="shibboleth.authn.OAuth2Client.LDAP.authenticator" parent="shibboleth.LDAPAuthenticationFactory"
+        lazy-init="true" />
+
+    <bean id="shibboleth.X509ResourceCredentialConfig"
+        class="net.shibboleth.idp.authn.impl.X509ResourceCredentialConfig" abstract="true" /> 
+    <bean id="shibboleth.KeystoreResourceCredentialConfig"
+        class="net.shibboleth.idp.authn.impl.KeystoreResourceCredentialConfig" abstract="true" /> 
+    
+    <bean id="shibboleth.authn.OAuth2Client.LDAP.trustCertificates" parent="shibboleth.X509ResourceCredentialConfig"
+        p:trustCertificates="%{idp.authn.OAuth2Client.LDAP.trustCertificates:undefined}" />
+    <bean id="shibboleth.authn.OAuth2Client.LDAP.truststore" parent="shibboleth.KeystoreResourceCredentialConfig"
+        p:truststore="%{idp.authn.OAuth2Client.LDAP.trustStore:undefined}" />
+
+    <bean id="shibboleth.LDAPAuthenticationFactory" abstract="true"
+        class="net.shibboleth.idp.authn.config.LDAPAuthenticationFactoryBean"
+        p:authenticatorType="#{'%{idp.authn.OAuth2Client.LDAP.authenticator:anonSearchAuthenticator}'.trim()}"
+        p:trustType="#{'%{idp.authn.OAuth2Client.LDAP.sslConfig:certificateTrust}'.trim()}"
+        p:connectionStrategyType="#{'%{idp.authn.OAuth2Client.LDAP.connectionStrategy:ACTIVE_PASSIVE}'.trim()}"
+        p:ldapUrl="%{idp.authn.OAuth2Client.LDAP.ldapURL:ldap://localhost:10389}"
+        p:useStartTLS="%{idp.authn.OAuth2Client.LDAP.useStartTLS:true}"
+        p:startTLSTimeout="%{idp.authn.OAuth2Client.LDAP.startTLSTimeout:PT3S}"
+        p:connectTimeout="%{idp.authn.OAuth2Client.LDAP.connectTimeout:PT3S}"
+        p:responseTimeout="%{idp.authn.OAuth2Client.LDAP.responseTimeout:PT3S}"
+        p:autoReconnect="%{idp.authn.OAuth2Client.LDAP.autoReconnect:true}"
+        p:reconnectTimeout="%{idp.authn.OAuth2Client.LDAP.reconnectTimeout:PT10S}"
+        p:trustCertificatesCredentialConfig-ref="shibboleth.authn.OAuth2Client.LDAP.trustCertificates"
+        p:truststoreCredentialConfig-ref="shibboleth.authn.OAuth2Client.LDAP.truststore"
+        p:disablePooling="%{idp.authn.OAuth2Client.LDAP.disablePooling:false}"
+        p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
+        p:minPoolSize="%{idp.pool.LDAP.minSize:3}"
+        p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}"
+        p:validateOnCheckout="%{idp.pool.LDAP.validateOnCheckout:false}"
+        p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
+        p:validatePeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
+        p:validateDn="#{'%{idp.pool.LDAP.validateDN:}'.trim()}"
+        p:validateFilter="#{'%{idp.pool.LDAP.validateFilter:(objectClass=*)}'.trim()}"
+        p:bindPoolPassivatorType="#{'%{idp.authn.OAuth2Client.LDAP.bindPoolPassivator:none}'.trim()}"
+        p:prunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
+        p:idleTime="%{idp.pool.LDAP.idleTime:PT10M}"
+        p:dnFormat="%{idp.authn.OAuth2Client.LDAP.dnFormat:undefined}"
+        p:baseDn="#{'%{idp.authn.OAuth2Client.LDAP.baseDN:undefined}'.trim()}"
+        p:userFilter="#{'%{idp.authn.OAuth2Client.LDAP.userFilter:undefined}'.trim()}"
+        p:subtreeSearch="%{idp.authn.OAuth2Client.LDAP.subtreeSearch:false}"
+        p:resolveEntryOnFailure="%{idp.authn.OAuth2Client.LDAP.resolveEntryOnFailure:false}"
+        p:resolveEntryWithBindDn="%{idp.authn.OAuth2Client.LDAP.resolveEntryWithBindDN:false}"
+        p:velocityEngine-ref="shibboleth.VelocityEngine"
+        p:bindDn="#{'%{idp.authn.OAuth2Client.LDAP.bindDN:undefined}'.trim()}"
+        p:bindDnCredential="%{idp.authn.OAuth2Client.LDAP.bindDNCredential:undefined}"
+        p:usePasswordPolicy="%{idp.authn.OAuth2Client.LDAP.usePasswordPolicy:false}"
+        p:usePasswordExpiration="%{idp.authn.OAuth2Client.LDAP.usePasswordExpiration:false}"
+        p:activeDirectory="%{idp.authn.OAuth2Client.LDAP.activeDirectory:false}"
+        p:freeIPA="%{idp.authn.OAuth2Client.LDAP.freeIPADirectory:false}"
+        p:EDirectory="%{idp.authn.OAuth2Client.LDAP.eDirectory:false}"
+        p:accountStateExpirationPeriod="%{idp.authn.OAuth2Client.LDAP.accountStateExpirationPeriod:#{null}}"
+        p:accountStateWarningPeriod="%{idp.authn.OAuth2Client.LDAP.accountStateWarningPeriod:#{null}}"
+        p:accountStateLoginFailures="%{idp.authn.OAuth2Client.LDAP.accountStateLoginFailures:0}" />
+
+    <util:map id="shibboleth.authn.AuditFormattingMap">
+        <entry key="#{'%{idp.authn.OAuth2Client.audit.category:Shibboleth-Audit.OAuth2Client}'.trim()}"
+            value="#{'%{idp.authn.OAuth2Client.audit.format:%a|%T|%SP|%I|%s|%AF|%CV|%u|%tu|%AR|%UA}'.trim()}" />
+    </util:map>
+
+    <bean id="shibboleth.authn.OAuth2Client.PopulateAuditContext" parent="shibboleth.authn.AbstractPopulateAuditContext" lazy-init="true"
+        p:fieldExtractors="#{getObject('shibboleth.authn.OAuth2Client.AuditExtractors') ?: getObject('shibboleth.authn.OAuth2Client.DefaultAuditExtractors')}"/>
+
+     <bean id="shibboleth.authn.OAuth2Client.DefaultAuditExtractors" parent="shibboleth.authn.DefaultAuditExtractors" lazy-init="true"
+            class="org.springframework.beans.factory.config.MapFactoryBean">
+        <property name="sourceMap">
+             <map merge="true">
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.profile.IdPAuditFields.USERNAME"/>
+                    </key>
+                    <bean class="net.shibboleth.idp.authn.audit.impl.AttemptedUsernameAuditExtractor" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.authn.AuthnAuditFields.TRANSFORMED_USERNAME"/>
+                    </key>
+                    <bean class="net.shibboleth.idp.authn.audit.impl.TransformedUsernameAuditExtractor" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.saml.profile.SAMLAuditFields.REQUEST_ID"/>
+                    </key>
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="jti" />
+                </entry>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.saml.profile.SAMLAuditFields.REQUEST_ISSUE_INSTANT"/>
+                    </key>
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="iat" />
+                </entry>
+                <entry key="aud">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="aud" />
+                </entry>
+                <entry key="iss">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="iss" />
+                </entry>
+                <entry key="sub">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="sub" />
+                </entry>
+                <entry key="exp">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="exp" />
+                </entry>
+                <entry key="iat">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTPayloadClaimsAuditExtractor"
+                        c:key="iat" />
+                </entry>
+                <entry key="typ">
+                    <bean class="net.shibboleth.oidc.authn.audit.impl.ClientAuthenticationJWTTypeHeaderAuditExtractor" />
+                </entry>
+             </map>
+        </property>
+    </bean>
+ 
+</beans>
diff --git a/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-flow.xml b/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-flow.xml
new file mode 100644
index 00000000..a75eb608
--- /dev/null
+++ b/oidc-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OAuth2Client/OAuth2Client-flow.xml
@@ -0,0 +1,43 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+      parent="authn.abstract">
+
+    <!--
+    This is a login flow for handling OAuth2-defined client authentication mechanisms.
+    The current implementation relies on Nimbus APIs but could be replaced in the future if necessary.
+    -->
+
+    <action-state id="OAuth2Client">
+        <evaluate expression="PopulateTokenEndpointJwtSignatureValidationParameters"/>
+        <evaluate expression="ExtractClientAuthenticationFromRequest" />
+        <evaluate expression="ValidateClientAuthenticationType" />
+        <evaluate expression="ValidateJWTSignature"/>
+        <evaluate expression="ValidateCredentials" />
+        <evaluate expression="PopulateSubjectCanonicalizationContext" />
+        <evaluate expression="'proceed'" />
+        
+        <transition on="proceed" to="CallSubjectCanonicalization" />
+    </action-state>
+    
+    <!-- This runs a c14n step on the result of the authentication. -->
+    <subflow-state id="CallSubjectCanonicalization" subflow="c14n">
+        <input name="calledAsSubflow" value="true" />
+        <transition on="proceed" to="proceed" />
+        
+        <!-- This shouldn't generally happen, but if c14n fails, it's allowable to fall through. -->
+        <transition on="SubjectCanonicalizationError" to="ReselectFlow" />
+    </subflow-state>
+
+    <!-- As a "fall-through" method, remap selected events to select a different flow. -->
+    <global-transitions>
+        <transition on="NoCredentials" to="ReselectFlow" />
+        <transition on="InvalidCredentials" to="ReselectFlow" />
+        <transition on="RequestUnsupported" to="ReselectFlow" />
+        <transition on="UnknownUsername" to="ReselectFlow" />
+        <transition on="AccessDenied" to="ReselectFlow" />
+    </global-transitions>
+
+    <bean-import resource="OAuth2Client-beans.xml" />
+
+</flow>
diff --git a/pom.xml b/pom.xml
index 47a1ac7b..0000af82 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,6 +28,7 @@
         <module>oidc-common-profile-impl</module>
         <module>oidc-common-saml-api</module>
         <module>oidc-common-saml-impl</module>
+        <module>oidc-common-conf-impl</module>
         <module>oidc-common-plugin</module>
         <module>oidc-common-bom</module>
         <module>oidc-common-dist</module>

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


More information about the commits mailing list