[java-oidc-common] branch main updated: JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from oidc-op-impl into commons
Phil Smart
philip.smart at jisc.ac.uk
Fri Nov 26 14:05:53 UTC 2021
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-oidc-common.
View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=aa7f1a1f60ad722b33f27282676e4469ba76e432
The following commit(s) were added to refs/heads/main by this push:
new aa7f1a1 JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from oidc-op-impl into commons
aa7f1a1 is described below
commit aa7f1a1f60ad722b33f27282676e4469ba76e432
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Nov 26 14:05:46 2021 +0000
JCOMOIDC-21 - Move net.shibboleth.idp.plugin.oidc.op.config from
oidc-op-impl into commons
- Added profile impl and api modules
- Updated distribution and assembly.
- Moved the core OIDC protocol config.
- Moved the oauth2 config.
- Had to move AuthnContextClassReference principal as well.
https://shibboleth.atlassian.net/browse/JCOMOIDC-21
---
.../src/main/assembly/plugin-assembly-tgz.xml | 40 +
.../src/main/assembly/plugin-assembly-zip.xml | 40 +
oidc-common-profile-api/pom.xml | 67 ++
...thenticationContextClassReferencePrincipal.java | 98 +++
.../oidc/authn/principal/package-info.java | 21 +
...IDCClientAuthenticableProfileConfiguration.java | 109 +++
.../AbstractOIDCFlowAwareProfileConfiguration.java | 183 +++++
.../config/OIDCCoreProtocolConfiguration.java | 839 +++++++++++++++++++++
.../profile/config/OIDCProfileConfiguration.java | 27 +
.../oidc/profile/config/package-info.java | 21 +
.../OAuth2TokenIntrospectionConfiguration.java | 52 ++
.../config/OAuth2TokenRevocationConfiguration.java | 53 ++
.../oidc/profile/oauth2/config/package-info.java | 21 +
oidc-common-profile-impl/pom.xml | 52 ++
pom.xml | 2 +
15 files changed, 1625 insertions(+)
diff --git a/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml b/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
index 47cbe9a..9b7ce21 100644
--- a/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
+++ b/oidc-common-dist/src/main/assembly/plugin-assembly-tgz.xml
@@ -123,6 +123,46 @@
<include>*.jar</include>
</includes>
</fileSet>
+
+ <!-- profile -->
+ <fileSet>
+ <directory>../oidc-common-profile-api/target</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>oidc-common-profile-api-*.jar</include>
+ </includes>
+ <excludes>
+ <exclude>*test*.jar</exclude>
+ <exclude>*javadoc.jar</exclude>
+ <exclude>*sources.jar</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-api/target/dependency</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-impl/target</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>oidc-common-profile-impl-*.jar</include>
+ </includes>
+ <excludes>
+ <exclude>*test*.jar</exclude>
+ <exclude>*javadoc.jar</exclude>
+ <exclude>*sources.jar</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-impl/target/dependency</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
<!-- saml -->
<fileSet>
diff --git a/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml b/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
index 9853d48..52c37c3 100644
--- a/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
+++ b/oidc-common-dist/src/main/assembly/plugin-assembly-zip.xml
@@ -123,6 +123,46 @@
<include>*.jar</include>
</includes>
</fileSet>
+
+ <!-- profile -->
+ <fileSet>
+ <directory>../oidc-common-profile-api/target</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>oidc-common-profile-api-*.jar</include>
+ </includes>
+ <excludes>
+ <exclude>*test*.jar</exclude>
+ <exclude>*javadoc.jar</exclude>
+ <exclude>*sources.jar</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-api/target/dependency</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-impl/target</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>oidc-common-profile-impl-*.jar</include>
+ </includes>
+ <excludes>
+ <exclude>*test*.jar</exclude>
+ <exclude>*javadoc.jar</exclude>
+ <exclude>*sources.jar</exclude>
+ </excludes>
+ </fileSet>
+ <fileSet>
+ <directory>../oidc-common-profile-impl/target/dependency</directory>
+ <outputDirectory>webapp/WEB-INF/lib</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
<!-- saml -->
<fileSet>
diff --git a/oidc-common-profile-api/pom.xml b/oidc-common-profile-api/pom.xml
new file mode 100644
index 0000000..a73230d
--- /dev/null
+++ b/oidc-common-profile-api/pom.xml
@@ -0,0 +1,67 @@
+<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 https://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>1.1.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>oidc-common-profile-api</artifactId>
+ <packaging>jar</packaging>
+ <name>Shibboleth IdP :: Plugins :: OIDC Common :: Profile Configuration API</name>
+ <description>Interfaces for common OIDC RP profile configuration functions/features.</description>
+
+ <properties>
+ <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
+ <automatic.module.name>net.shibboleth.oidc.profile.api</automatic.module.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>net.shibboleth.idp</groupId>
+ <artifactId>idp-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.shibboleth.idp</groupId>
+ <artifactId>idp-profile-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.shibboleth.idp</groupId>
+ <artifactId>idp-authn-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.nimbusds</groupId>
+ <artifactId>oauth2-oidc-sdk</artifactId>
+ <scope>provided</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>
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java
new file mode 100644
index 0000000..26962c7
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/AuthenticationContextClassReferencePrincipal.java
@@ -0,0 +1,98 @@
+/*
+ * 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.authn.principal;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.authn.principal.CloneablePrincipal;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+import com.google.common.base.MoreObjects;
+
+/** Principal based on a OIDC Authentication Context Class Reference. */
+public final class AuthenticationContextClassReferencePrincipal implements CloneablePrincipal {
+
+ /** unspecified auth ctx class. */
+ public static final String UNSPECIFIED = "net.shibboleth.idp.oidc.authn.principal.string.unspecified";
+
+ /** The class ref. */
+ @Nonnull
+ @NotEmpty
+ private String authnContextClassReference;
+
+ /**
+ * Constructor.
+ *
+ * @param classRef the class reference URI
+ */
+ public AuthenticationContextClassReferencePrincipal(
+ @Nonnull @NotEmpty @ParameterName(name = "classRef") final String classRef) {
+ authnContextClassReference = Constraint.isNotNull(StringSupport.trimOrNull(classRef),
+ "AuthnContextClassRef cannot be null or empty");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nonnull
+ @NotEmpty
+ public String getName() {
+ return authnContextClassReference;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ return authnContextClassReference.hashCode();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(final Object other) {
+ if (other == null) {
+ return false;
+ }
+
+ if (this == other) {
+ return true;
+ }
+
+ if (other instanceof AuthenticationContextClassReferencePrincipal) {
+ return authnContextClassReference.equals(((AuthenticationContextClassReferencePrincipal) other).getName());
+ }
+
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("authnContextClassReference", authnContextClassReference)
+ .toString();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public AuthenticationContextClassReferencePrincipal clone() throws CloneNotSupportedException {
+ final AuthenticationContextClassReferencePrincipal copy =
+ (AuthenticationContextClassReferencePrincipal) super.clone();
+ copy.authnContextClassReference = authnContextClassReference;
+ return copy;
+ }
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java
new file mode 100644
index 0000000..fb924d8
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/authn/principal/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * OIDC-specific classes for integration with idp-authn-api packages.
+ */
+package net.shibboleth.oidc.authn.principal;
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java
new file mode 100644
index 0000000..88abf13
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCClientAuthenticableProfileConfiguration.java
@@ -0,0 +1,109 @@
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
+
+import net.shibboleth.idp.profile.config.AbstractConditionalProfileConfiguration;
+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;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Base class for OIDC protocol configuration, containing configuration bit for setting client authentication methods.
+ */
+public abstract class AbstractOIDCClientAuthenticableProfileConfiguration
+ extends AbstractConditionalProfileConfiguration implements OIDCProfileConfiguration {
+
+ /** Enabled token endpoint authentication methods. */
+ @Nonnull private Function<ProfileRequestContext,Collection<String>> tokenEndpointAuthMethodsLookupStrategy;
+
+ /**
+ * Constructor.
+ *
+ * @param profileId Unique profile identifier
+ */
+ protected AbstractOIDCClientAuthenticableProfileConfiguration(@Nonnull @NotEmpty final String profileId) {
+ super(profileId);
+
+ setTokenEndpointAuthMethods(
+ List.of(
+ ClientAuthenticationMethod.CLIENT_SECRET_BASIC.toString(),
+ ClientAuthenticationMethod.CLIENT_SECRET_POST.toString(),
+ ClientAuthenticationMethod.CLIENT_SECRET_JWT.toString(),
+ ClientAuthenticationMethod.PRIVATE_KEY_JWT.toString()));
+ }
+
+ /**
+ * Get the enabled token endpoint authentication methods.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return enabled token endpoint authentication methods
+ */
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getTokenEndpointAuthMethods(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Collection<String> methods = tokenEndpointAuthMethodsLookupStrategy.apply(profileRequestContext);
+ if (methods != null) {
+ return List.copyOf(methods);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Set the enabled token endpoint authentication methods.
+ *
+ * @param methods What to set.
+ */
+ public void setTokenEndpointAuthMethods(@Nonnull @NonnullElements final Collection<String> methods) {
+ Constraint.isNotNull(methods, "Collection of methods cannot be null");
+
+ if (methods != null) {
+ tokenEndpointAuthMethodsLookupStrategy =
+ FunctionSupport.constant(List.copyOf(StringSupport.normalizeStringCollection(methods)));
+ } else {
+ tokenEndpointAuthMethodsLookupStrategy = FunctionSupport.constant(null);
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the enabled token endpoint authentication methods.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setTokenEndpointAuthMethodsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+ tokenEndpointAuthMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java
new file mode 100644
index 0000000..858f551
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/AbstractOIDCFlowAwareProfileConfiguration.java
@@ -0,0 +1,183 @@
+/*
+ * 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.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.google.common.base.Predicates;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Base class for OIDC protocol configuration, containing configuration bits shared by all flow aware OIDC protocol
+ * configurations.
+ */
+public abstract class AbstractOIDCFlowAwareProfileConfiguration
+ extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+ /** Predicate used to indicate whether authorization code flow is supported by this profile. Default true. */
+ @Nonnull private Predicate<ProfileRequestContext> authorizationCodeFlowPredicate;
+
+ /** Predicate used to indicate whether implicit flow is supported by this profile. Default true. */
+ @Nonnull private Predicate<ProfileRequestContext> implicitFlowPredicate;
+
+ /** Predicate used to indicate whether hybrid flow is supported by this profile. Default true. */
+ @Nonnull private Predicate<ProfileRequestContext> hybridFlowPredicate;
+
+ /** Predicate used to indicate whether refresh tokens are supported by this profile. Default true. */
+ @Nonnull private Predicate<ProfileRequestContext> refreshTokensPredicate;
+
+ /**
+ * Constructor.
+ *
+ * @param profileId Unique profile identifier.
+ */
+ protected AbstractOIDCFlowAwareProfileConfiguration(final String profileId) {
+ super(profileId);
+ authorizationCodeFlowPredicate = Predicates.alwaysTrue();
+ implicitFlowPredicate = Predicates.alwaysTrue();
+ hybridFlowPredicate = Predicates.alwaysTrue();
+ refreshTokensPredicate = Predicates.alwaysTrue();
+ }
+
+ /**
+ * Get whether authorization code flow is supported by this profile.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether authorization code flow is supported by this profile
+ */
+ public boolean isAuthorizationCodeFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+ return authorizationCodeFlowPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether authorization code flow is supported by this profile.
+ *
+ * @param flag flag to set
+ */
+ public void setAuthorizationCodeFlowEnabled(final boolean flag) {
+ authorizationCodeFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition used to indicate whether authorization code flow is supported by this profile.
+ *
+ * @param condition condition to set
+ */
+ public void setAuthorizationCodeFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ authorizationCodeFlowPredicate = Constraint.isNotNull(condition,
+ "Condition used to indicate whether authorization code flow is supported cannot be null");
+ }
+
+ /**
+ * Get whether implicit flow is supported by this profile.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether implicit flow is supported by this profile
+ */
+ public boolean isHybridFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+ return hybridFlowPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether implicit flow is supported by this profile.
+ *
+ * @param flag flag to set
+ */
+ public void setHybridFlowEnabled(final boolean flag) {
+ hybridFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition used to indicate whether implicit flow is supported by this profile.
+ *
+ * @param condition condition to set
+ */
+ public void setHybridFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ hybridFlowPredicate = Constraint.isNotNull(condition,
+ "Condition used to indicate whether implicit flow is supported cannot be null");
+ }
+
+ /**
+ * Get whether hybrid flow is supported by this profile.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether hybrid flow is supported by this profile
+ */
+ public boolean isImplicitFlowEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+ return implicitFlowPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether hybrid flow is supported by this profile.
+ *
+ * @param flag flag to set
+ */
+ public void setImplicitFlowEnabled(final boolean flag) {
+ implicitFlowPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition used to indicate whether hybrid flow is supported by this profile.
+ *
+ * @param condition condition to set.
+ */
+ public void setImplicitFlowEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ implicitFlowPredicate = Constraint.isNotNull(condition,
+ "Condition used to indicate whether hybrid flow is supported cannot be null");
+ }
+
+ /**
+ * Get whether refresh tokens are supported by this profile.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether refresh tokens are supported by this profile
+ */
+ public boolean isRefreshTokensEnabled(@Nullable final ProfileRequestContext profileRequestContext) {
+ return refreshTokensPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether refresh tokens are supported by this profile.
+ *
+ * @param flag flag to set
+ */
+ public void setRefreshTokensEnabled(final boolean flag) {
+ refreshTokensPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition used to indicate whether refresh tokens are supported by this profile.
+ *
+ * @param condition condition to set
+ */
+ public void setRefreshTokensEnabledPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ refreshTokensPredicate = Constraint.isNotNull(condition,
+ "Condition used to indicate whether refresh tokens are supported cannot be null");
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java
new file mode 100644
index 0000000..253df3b
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCCoreProtocolConfiguration.java
@@ -0,0 +1,839 @@
+/*
+ * 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.security.Principal;
+import java.time.Duration;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import com.google.common.base.Predicates;
+
+import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
+import net.shibboleth.idp.profile.config.OverriddenIssuerProfileConfiguration;
+import net.shibboleth.oidc.authn.principal.AuthenticationContextClassReferencePrincipal;
+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;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Profile configuration for the OpenID Connect authorization and token endpoints.
+ */
+public class OIDCCoreProtocolConfiguration extends AbstractOIDCFlowAwareProfileConfiguration
+ implements AuthenticationProfileConfiguration, OverriddenIssuerProfileConfiguration {
+
+ /** OIDC base protocol URI. */
+ @Nonnull @NotEmpty public static final String PROTOCOL_URI = "http://openid.net/specs/openid-connect-core-1_0.html";
+
+ /** ID for this profile configuration. */
+ @Nonnull @NotEmpty public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oidc/sso/browser";
+
+ /** Whether attributes should be resolved in the course of the profile. */
+ @Nonnull private Predicate<ProfileRequestContext> resolveAttributesPredicate;
+
+ /** Whether to mandate forced authentication for the request. */
+ @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
+
+ /** Whether all acr claim requests should be treated as Essential. */
+ @Nonnull private Predicate<ProfileRequestContext> acrRequestAlwaysEssentialPredicate;
+
+ /** Whether client is required to use PKCE. */
+ @Nonnull private Predicate<ProfileRequestContext> forcePKCEPredicate;
+
+ /** Whether client is allowed to use PKCE code challenge method plain. */
+ @Nonnull private Predicate<ProfileRequestContext> allowPKCEPlainPredicate;
+
+ /** Whether to encode consent in authorization code and access/refresh tokens. */
+ @Nonnull private Predicate<ProfileRequestContext> encodeConsentInTokensPredicate;
+
+ /** Lookup function to override issuer value. */
+ @Nonnull private Function<ProfileRequestContext,String> issuerLookupStrategy;
+
+ /** Lookup function to supply proxyCount property. */
+ @Nonnull private Function<ProfileRequestContext,Integer> proxyCountLookupStrategy;
+
+ /** Lookup function to supply default authentication methods. */
+ @Nonnull private Function<ProfileRequestContext,Collection<AuthenticationContextClassReferencePrincipal>>
+ defaultAuthenticationContextsLookupStrategy;
+
+ /** Lookup function to supply authentication flows. */
+ @Nonnull private Function<ProfileRequestContext,Set<String>> authenticationFlowsLookupStrategy;
+
+ /** Lookup function to supply post authentication flows. */
+ @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
+
+ /** Lookup function to supply ID token lifetime. */
+ @Nonnull private Function<ProfileRequestContext,Duration> idTokenLifetimeLookupStrategy;
+
+ /** Lookup function to supply lifetime of authz code. */
+ @Nonnull private Function<ProfileRequestContext,Duration> authorizeCodeLifetimeLookupStrategy;
+
+ /** Lookup function to supply access token lifetime. */
+ @Nonnull private Function<ProfileRequestContext,Duration> accessTokenLifetimeLookupStrategy;
+
+ /** Lookup function to supply refresh token lifetime. */
+ @Nonnull private Function<ProfileRequestContext,Duration> refreshTokenLifetimeLookupStrategy;
+
+ /** Lookup function to supply additional audiences for ID token. */
+ @Nonnull private Function<ProfileRequestContext,Set<String>> assertionAudiencesLookupStrategy;
+
+ /** Lookup function to supply attribute IDs to embed in authorization code or access token. */
+ @Nonnull private Function<ProfileRequestContext,Set<String>> encodedAttributesLookupStrategy;
+
+ /** Lookup function to supply attribute IDs to include in ID token regardless of response_type. */
+ @Nonnull private Function<ProfileRequestContext,Set<String>> alwaysIncludedAttributesLookupStrategy;
+
+ /** Lookup function to supply attribute IDs to omit from UserInfo token. */
+ @Nonnull private Function<ProfileRequestContext,Set<String>> deniedUserInfoAttributesLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public OIDCCoreProtocolConfiguration() {
+ this(PROFILE_ID);
+ }
+
+ /**
+ * Creates a new configuration instance.
+ *
+ * @param profileId Unique profile identifier.
+ */
+ public OIDCCoreProtocolConfiguration(@Nonnull @NotEmpty final String profileId) {
+ super(profileId);
+ forceAuthnPredicate = Predicates.alwaysFalse();
+ resolveAttributesPredicate = Predicates.alwaysTrue();
+ issuerLookupStrategy = FunctionSupport.constant(null);
+ proxyCountLookupStrategy = FunctionSupport.constant(null);
+ assertionAudiencesLookupStrategy = FunctionSupport.constant(null);
+
+ idTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofHours(1));
+ authorizeCodeLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(5));
+ accessTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(10));
+ refreshTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofHours(2));
+
+ acrRequestAlwaysEssentialPredicate = Predicates.alwaysFalse();
+ forcePKCEPredicate = Predicates.alwaysFalse();
+ allowPKCEPlainPredicate = Predicates.alwaysFalse();
+ encodeConsentInTokensPredicate = Predicates.alwaysFalse();
+
+ defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+ authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+ postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+
+ encodedAttributesLookupStrategy = FunctionSupport.constant(null);
+ alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+ deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+ }
+
+ /** {@inheritDoc} */
+ @Nullable @NotEmpty public String getIssuer(@Nullable final ProfileRequestContext profileRequestContext) {
+ return issuerLookupStrategy.apply(profileRequestContext);
+ }
+
+ /**
+ * Set overridden issuer value.
+ *
+ * @param issuer issuer value
+ */
+ public void setIssuer(@Nullable @NotEmpty final String issuer) {
+ issuerLookupStrategy = FunctionSupport.constant(issuer);
+ }
+
+ /**
+ * Sets lookup strategy for overridden issuer value.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setIssuerLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+ issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
+ }
+
+ /**
+ * Get whether attributes should be resolved during the profile.
+ *
+ * <p>Default is true</p>
+ *
+ * @param profileRequestContext current profile request context
+ *
+ * @return true iff attributes should be resolved
+ */
+ public boolean isResolveAttributes(@Nullable final ProfileRequestContext profileRequestContext) {
+ return resolveAttributesPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether attributes should be resolved during the profile.
+ *
+ * @param flag flag to set
+ */
+ public void setResolveAttributes(final boolean flag) {
+ resolveAttributesPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set a condition to determine whether attributes should be resolved during the profile.
+ *
+ * @param condition condition to set
+ */
+ public void setResolveAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ resolveAttributesPredicate = Constraint.isNotNull(condition, "Resolve attributes predicate cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ public boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext) {
+ return forceAuthnPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether a fresh user presence proof should be required for this request.
+ *
+ * @param flag flag to set
+ */
+ public void setForceAuthn(final boolean flag) {
+ forceAuthnPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set a condition to determine whether a fresh user presence proof should be required for this request.
+ *
+ * @param condition condition to set
+ */
+ public void setForceAuthnPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ forceAuthnPredicate = Constraint.isNotNull(condition, "Forced authentication predicate cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public Integer getProxyCount(@Nullable final ProfileRequestContext profileRequestContext) {
+ final Integer count = proxyCountLookupStrategy.apply(profileRequestContext);
+ if (count != null) {
+ Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+ }
+ return count;
+ }
+
+ /**
+ * Sets the maximum number of times an assertion may be proxied outbound and/or
+ * the maximum number of hops between the relying party and a proxied authentication
+ * authority inbound.
+ *
+ * @param count proxy count
+ */
+ public void setProxyCount(@Nullable @NonNegative final Integer count) {
+ if (count != null) {
+ Constraint.isGreaterThanOrEqual(0, count, "Proxy count must be greater than or equal to 0");
+ }
+ proxyCountLookupStrategy = FunctionSupport.constant(count);
+ }
+
+ /**
+ * Set a lookup strategy for the maximum number of times an assertion may be proxied outbound and/or
+ * the maximum number of hops between the relying party and a proxied authentication authority inbound.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setProxyCountLookupStrategy(@Nonnull final Function<ProfileRequestContext,Integer> strategy) {
+ proxyCountLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public Set<String> getAuthenticationFlows(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+ final Set<String> flows = authenticationFlowsLookupStrategy.apply(profileRequestContext);
+ if (flows != null) {
+ return Set.copyOf(flows);
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Set the authentication flows to use.
+ *
+ * @param flows flow identifiers to use
+ */
+ public void setAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
+ if (flows != null) {
+ authenticationFlowsLookupStrategy =
+ FunctionSupport.constant(Set.copyOf(StringSupport.normalizeStringCollection(flows)));
+ } else {
+ authenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the authentication flows to use.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAuthenticationFlowsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+ authenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public List<String> getPostAuthenticationFlows(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+ final Collection<String> flows = postAuthenticationFlowsLookupStrategy.apply(profileRequestContext);
+ if (flows != null) {
+ return List.copyOf(flows);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Set the ordered collection of post-authentication interceptor flows to enable.
+ *
+ * @param flows flow identifiers to enable
+ */
+ public void setPostAuthenticationFlows(@Nullable @NonnullElements final Collection<String> flows) {
+ if (flows != null) {
+ postAuthenticationFlowsLookupStrategy =
+ FunctionSupport.constant(List.copyOf(StringSupport.normalizeStringCollection(flows)));
+ } else {
+ postAuthenticationFlowsLookupStrategy = FunctionSupport.constant(null);
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the post-authentication interceptor flows to enable.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setPostAuthenticationFlowsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Collection<String>> strategy) {
+ postAuthenticationFlowsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @NonnullElements @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+ final Collection<AuthenticationContextClassReferencePrincipal> methods =
+ defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext);
+ if (methods != null) {
+ return List.copyOf(methods);
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Set the default authentication contexts to use, expressed as custom principals.
+ *
+ * @param contexts default authentication contexts to use
+ */
+ public void setDefaultAuthenticationMethods(
+ @Nullable @NonnullElements final Collection<AuthenticationContextClassReferencePrincipal> contexts) {
+ if (contexts != null) {
+ defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(List.copyOf(contexts));
+ } else {
+ defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the authentication contexts to use, expressed as custom principals.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setDefaultAuthenticationMethodsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Collection<AuthenticationContextClassReferencePrincipal>>
+ strategy) {
+ defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get ID token lifetime.
+ *
+ * <p>Defaults to 1 hour.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return ID token lifetime
+ */
+ @Positive @Nonnull public Duration getIDTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Duration lifetime = idTokenLifetimeLookupStrategy.apply(profileRequestContext);
+
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "ID token lifetime must be greater than 0");
+ return lifetime;
+ }
+
+ /**
+ * Set the lifetime of an id token.
+ *
+ * @param lifetime lifetime of an id token in milliseconds
+ */
+ public void setIDTokenLifetime(@Positive @Nonnull final Duration lifetime) {
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "ID token lifetime must be greater than 0");
+
+ idTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+ }
+
+ /**
+ * Set a lookup strategy for the ID token lifetime.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setIDTokenLifetimeLookupStrategy(@Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+ idTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get access token lifetime.
+ *
+ * <p>Defaults to 10 minutes.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return access token lifetime
+ */
+ @Positive @Nonnull
+ public Duration getAccessTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+ final Duration lifetime = accessTokenLifetimeLookupStrategy.apply(profileRequestContext);
+
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Access token lifetime must be greater than 0");
+ return lifetime;
+ }
+
+ /**
+ * Set the lifetime of an access token.
+ *
+ * @param lifetime lifetime of an access token in milliseconds
+ */
+ public void setAccessTokenLifetime(@Positive @Nonnull final Duration lifetime) {
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Access token lifetime must be greater than 0");
+
+ accessTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+ }
+
+
+ /**
+ * Set a lookup strategy for the access token lifetime.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAccessTokenLifetimeLookupStrategy(
+ @Nullable final Function<ProfileRequestContext,Duration> strategy) {
+ accessTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get authz code lifetime.
+ *
+ * <p>Defaults to 5 minutes.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return authz code lifetime
+ */
+ @Positive @Nonnull
+ public Duration getAuthorizeCodeLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+ final Duration lifetime = authorizeCodeLifetimeLookupStrategy.apply(profileRequestContext);
+
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Authorization code lifetime must be greater than 0");
+ return lifetime;
+ }
+
+ /**
+ * Set the lifetime of authz code.
+ *
+ * @param lifetime lifetime of authz code
+ */
+ public void setAuthorizeCodeLifetime(@Positive @Nonnull final Duration lifetime) {
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Authorization code lifetime must be greater than 0");
+
+ authorizeCodeLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+ }
+
+ /**
+ * Set a lookup strategy for the authz code lifetime.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAuthorizeCodeLifetimeLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Duration> strategy) {
+ authorizeCodeLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get refresh token lifetime.
+ *
+ * <p>Defaults to 2 hours.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return refresh token lifetime
+ */
+ @Nonnull @Positive
+ public Duration getRefreshTokenLifetime(@Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Duration lifetime = refreshTokenLifetimeLookupStrategy.apply(profileRequestContext);
+
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Refresh token lifetime must be greater than 0");
+ return lifetime;
+ }
+
+ /**
+ * Set the lifetime of refresh token.
+ *
+ * @param lifetime lifetime of an refresh token
+ */
+ public void setRefreshTokenLifetime(@Nonnull @Positive final Duration lifetime) {
+ Constraint.isTrue(lifetime != null && !lifetime.isZero() && !lifetime.isNegative(),
+ "Refresh token lifetime must be greater than 0");
+
+ refreshTokenLifetimeLookupStrategy = FunctionSupport.constant(lifetime);
+ }
+
+ /**
+ * Set a lookup strategy for the refresh token lifetime.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setRefreshTokenLifetimeLookupStrategy(
+ @Nullable final Function<ProfileRequestContext,Duration> strategy) {
+ refreshTokenLifetimeLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get the set of audiences, in addition to the relying party(ies) to which the IdP is issuing the ID Token, with
+ * which the token may be shared.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return the additional audiences
+ */
+ @Nonnull @NonnullElements @NotLive public Set<String> getAdditionalAudiencesForIdToken(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Set<String> audiences = assertionAudiencesLookupStrategy.apply(profileRequestContext);
+ if (audiences != null) {
+ return Set.copyOf(audiences);
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Set the set of audiences, in addition to the relying party(ies) to which the IdP is issuing the ID Token, with
+ * which the token may be shared.
+ *
+ * @param audiences the additional audiences
+ */
+ public void setAdditionalAudiencesForIdToken(@Nullable @NonnullElements final Collection<String> audiences) {
+
+ if (audiences == null || audiences.isEmpty()) {
+ assertionAudiencesLookupStrategy = FunctionSupport.constant(null);
+ } else {
+ assertionAudiencesLookupStrategy = FunctionSupport.constant(
+ Set.copyOf(StringSupport.normalizeStringCollection(audiences)));
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the set of audiences, in addition to the relying party(ies) to which the IdP
+ * is issuing the ID Token, with which the token may be shared.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAdditionalAudiencesForIdTokenLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+ assertionAudiencesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get whether all acr claim requests should be treated as Essential.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether all acr claim requests should be treated as Essential
+ */
+ public boolean isAcrRequestAlwaysEssential(@Nullable final ProfileRequestContext profileRequestContext) {
+ return acrRequestAlwaysEssentialPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether all acr claim requests should be treated as Essential.
+ *
+ * @param flag flag to set
+ */
+ public void setAcrRequestAlwaysEssential(final boolean flag) {
+ acrRequestAlwaysEssentialPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition for whether all acr claim requests should be treated as Essential.
+ *
+ * @param condition condition to set
+ */
+ public void setAcrRequestAlwaysEssentialPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ acrRequestAlwaysEssentialPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+ /**
+ * Get whether client is required to use PKCE.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether client is required to use PKCE
+ */
+ public boolean isForcePKCE(@Nullable final ProfileRequestContext profileRequestContext) {
+ return forcePKCEPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether client is required to use PKCE.
+ *
+ * @param flag flag to set
+ */
+ public void setForcePKCE(final boolean flag) {
+ forcePKCEPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition for whether client is required to use PKCE.
+ *
+ * @param condition condition to set
+ */
+ public void setForcePKCEPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ forcePKCEPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+ /**
+ * Get whether client is allowed to use PKCE code challenge method plain.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether client is allowed to use PKCE code challenge method plain
+ */
+ public boolean isAllowPKCEPlain(@Nullable final ProfileRequestContext profileRequestContext) {
+ return allowPKCEPlainPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether client is allowed to use PKCE code challenge method plain.
+ *
+ * @param flag flag to set
+ */
+ public void setAllowPKCEPlain(final boolean flag) {
+ allowPKCEPlainPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition for whether client is allowed to use PKCE code challenge method plain.
+ *
+ * @param condition condition to set
+ */
+ public void setAllowPKCEPlainPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ allowPKCEPlainPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+
+ /**
+ * Get whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return whether to encode consent in authorization code and access/refresh tokens
+ */
+ public boolean isEncodeConsentInTokens(@Nullable final ProfileRequestContext profileRequestContext) {
+ return encodeConsentInTokensPredicate.test(profileRequestContext);
+ }
+
+ /**
+ * Set whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param flag flag to set
+ */
+ public void setEncodeConsentInTokens(final boolean flag) {
+ encodeConsentInTokensPredicate = flag ? Predicates.alwaysTrue() : Predicates.alwaysFalse();
+ }
+
+ /**
+ * Set condition for whether to encode consent in authorization code and access/refresh tokens.
+ *
+ * @param condition condition to set
+ */
+ public void setEncodeConsentInTokensPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+ encodeConsentInTokensPredicate = Constraint.isNotNull(condition, "Condition cannot be null");
+ }
+
+ /**
+ * Get the set of attribute IDs which should be encoded in encrypted form into the authorization code
+ * and/or access/refresh tokens to enable recovery on the back-channel.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return the attribute IDs to encode
+ */
+ @Nonnull @NonnullElements @NotLive public Set<String> getEncodedAttributes(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Set<String> attributes = encodedAttributesLookupStrategy.apply(profileRequestContext);
+ if (attributes != null) {
+ return Set.copyOf(attributes);
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Set the set of attribute IDs which should be encoded in encrypted form into the authorization code
+ * and/or access/refresh tokens to enable recovery on the back-channel.
+ *
+ * @param attributes the attribute IDs to encode
+ */
+ public void setEncodedAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+ if (attributes == null || attributes.isEmpty()) {
+ encodedAttributesLookupStrategy = FunctionSupport.constant(null);
+ } else {
+ encodedAttributesLookupStrategy = FunctionSupport.constant(
+ Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the attribute IDs which should be encoded in encrypted form into the
+ * authorization code and/or access/refresh tokens to enable recovery on the back-channel.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setEncodedAttributesLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+ encodedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get the set of attribute IDs which should be included in the ID token regardless of response_type.
+ *
+ * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+ * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+ * attributes to be added to the ID token regardless of flow.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return the attribute IDs to include in all cases
+ */
+ @Nonnull @NonnullElements @NotLive public Set<String> getAlwaysIncludedAttributes(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Set<String> attributes = alwaysIncludedAttributesLookupStrategy.apply(profileRequestContext);
+ if (attributes != null) {
+ return Set.copyOf(attributes);
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Set the set of attribute IDs which should be included in the ID token regardless of response_type.
+ *
+ * <p>Default behavior is to include claims only with the implicit id_token type only, while any use
+ * of a back-channel relies on the user_info endpoint to get the claims. This setting forces certain
+ * attributes to be added to the ID token regardless of flow.</p>
+ *
+ * @param attributes the attribute IDs to include in all cases
+ */
+ public void setAlwaysIncludedAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+ if (attributes == null || attributes.isEmpty()) {
+ alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(null);
+ } else {
+ alwaysIncludedAttributesLookupStrategy = FunctionSupport.constant(
+ Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the attribute IDs which should be included in the ID token regardless of
+ * response_type.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAlwaysIncludedAttributesLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+ alwaysIncludedAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+ /**
+ * Get the set of attribute IDs which should be omitted from the UserInfo token.
+ *
+ * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+ * may need to be embedded for recovery into the access/refresh tokens.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return the attribute IDs to omit from UserInfo token
+ */
+ @Nonnull @NonnullElements @NotLive public Set<String> getDeniedUserInfoAttributes(
+ @Nullable final ProfileRequestContext profileRequestContext) {
+
+ final Set<String> attributes = deniedUserInfoAttributesLookupStrategy.apply(profileRequestContext);
+ if (attributes != null) {
+ return Set.copyOf(attributes);
+ }
+ return Collections.emptySet();
+ }
+
+ /**
+ * Set the set of attribute IDs which should be omitted from the UserInfo token.
+ *
+ * <p>Default behavior is to include all claims, but omiited claims also affect the set that
+ * may need to be embedded for recovery into the access/refresh tokens.</p>
+ *
+ * @param attributes the attribute IDs to omit from UserInfo token
+ */
+ public void setDeniedUserInfoAttributes(@Nullable @NonnullElements final Collection<String> attributes) {
+
+ if (attributes == null || attributes.isEmpty()) {
+ deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(null);
+ } else {
+ deniedUserInfoAttributesLookupStrategy = FunctionSupport.constant(
+ Set.copyOf(StringSupport.normalizeStringCollection(attributes)));
+ }
+ }
+
+ /**
+ * Set a lookup strategy for the set of attribute IDs which should be omitted from the UserInfo token.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setDeniedUserInfoAttributesLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,Set<String>> strategy) {
+ deniedUserInfoAttributesLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java
new file mode 100644
index 0000000..b396dc9
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCProfileConfiguration.java
@@ -0,0 +1,27 @@
+/*
+ * 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 net.shibboleth.idp.profile.config.ProfileConfiguration;
+
+/**
+ * Marker interface for OIDC profile configurations.
+ */
+public interface OIDCProfileConfiguration extends ProfileConfiguration {
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java
new file mode 100644
index 0000000..1ff4ed1
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Profile configurations related to OIDC functionality.
+ */
+package net.shibboleth.oidc.profile.config;
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java
new file mode 100644
index 0000000..2ba5d8f
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenIntrospectionConfiguration.java
@@ -0,0 +1,52 @@
+/*
+ * 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.oauth2.config;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.profile.config.AbstractOIDCClientAuthenticableProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * Profile configuration for the OAuth2 Token Introspection.
+ */
+public class OAuth2TokenIntrospectionConfiguration extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+ /** OAuth2 Token Revocation URI. */
+ public static final String PROTOCOL_URI = "https://tools.ietf.org/html/rfc7662";
+
+ /** ID for this profile configuration. */
+ public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oauth2/introspection";
+
+ /**
+ * Constructor.
+ */
+ public OAuth2TokenIntrospectionConfiguration() {
+ this(PROFILE_ID);
+ }
+
+ /**
+ * Creates a new configuration instance.
+ *
+ * @param profileId Unique profile identifier.
+ */
+ public OAuth2TokenIntrospectionConfiguration(@Nonnull @NotEmpty final String profileId) {
+ super(profileId);
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java
new file mode 100644
index 0000000..0786ceb
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/OAuth2TokenRevocationConfiguration.java
@@ -0,0 +1,53 @@
+/*
+ * 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.oauth2.config;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.oidc.profile.config.AbstractOIDCClientAuthenticableProfileConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * Profile configuration for the OAuth2 Token Revocation. The profile is required to define client authentication
+ * methods.
+ */
+public class OAuth2TokenRevocationConfiguration extends AbstractOIDCClientAuthenticableProfileConfiguration {
+
+ /** OAuth2 Token Revocation URI. */
+ public static final String PROTOCOL_URI = "https://tools.ietf.org/html/rfc7009";
+
+ /** ID for this profile configuration. */
+ public static final String PROFILE_ID = "http://shibboleth.net/ns/profiles/oauth2/revocation";
+
+ /**
+ * Constructor.
+ */
+ public OAuth2TokenRevocationConfiguration() {
+ this(PROFILE_ID);
+ }
+
+ /**
+ * Creates a new configuration instance.
+ *
+ * @param profileId Unique profile identifier.
+ */
+ public OAuth2TokenRevocationConfiguration(@Nonnull @NotEmpty final String profileId) {
+ super(profileId);
+ }
+
+}
\ No newline at end of file
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java
new file mode 100644
index 0000000..8931423
--- /dev/null
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/oauth2/config/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * OAuth2 profile configurations.
+ */
+package net.shibboleth.oidc.profile.oauth2.config;
\ No newline at end of file
diff --git a/oidc-common-profile-impl/pom.xml b/oidc-common-profile-impl/pom.xml
new file mode 100644
index 0000000..a0df674
--- /dev/null
+++ b/oidc-common-profile-impl/pom.xml
@@ -0,0 +1,52 @@
+<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 https://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>1.1.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>oidc-common-profile-impl</artifactId>
+ <packaging>jar</packaging>
+ <name>Shibboleth IdP :: Plugins :: OIDC Common :: Profile Configuration Implementation</name>
+ <description>Implementation for common OIDC RP profile configuration functions/features.</description>
+
+ <properties>
+ <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
+ <automatic.module.name>net.shibboleth.oidc.profile.impl</automatic.module.name>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>net.shibboleth.idp</groupId>
+ <artifactId>idp-core</artifactId>
+ <scope>provided</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>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index bba6bda..8458ca3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -209,6 +209,8 @@
<module>oidc-common-plugin</module>
<module>oidc-common-bom</module>
<module>oidc-common-dist</module>
+ <module>oidc-common-profile-api</module>
+ <module>oidc-common-profile-impl</module>
</modules>
<build>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list