[java-shib-profile] branch main updated: JSATTR-6: SAML AttributeQuery DataConnector
Brent Putman
putmanb at georgetown.edu
Sat May 31 22:59:16 UTC 2025
This is an automated email from the git hooks/post-receive script.
putmanb pushed a commit to branch main
in repository java-shib-profile.
View the commit online:
http://git.shibboleth.net/view/?p=java-shib-profile.git;a=commit;h=21924dd76c85dc043a88c6eb679e178e44aee654
The following commit(s) were added to refs/heads/main by this push:
new 21924dd JSATTR-6: SAML AttributeQuery DataConnector
21924dd is described below
commit 21924dd76c85dc043a88c6eb679e178e44aee654
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Sat May 31 00:33:27 2025 -0400
JSATTR-6: SAML AttributeQuery DataConnector
Add a CriteriaSet-based resolver for DecryptionConfiguration.
Refactor most of the existing CriteriaSelfEntityIDResolver into
a base class for code reuse.
---
...riteriaRelyingPartyConfiigurationResolver.java} | 45 +++--
.../CriteriaDecryptionConfigurationResolver.java | 116 +++++++++++++
.../impl/CriteriaSelfEntityIDResolver.java | 189 +--------------------
3 files changed, 145 insertions(+), 205 deletions(-)
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/BaseCriteriaRelyingPartyConfiigurationResolver.java
similarity index 85%
copy from shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java
copy to shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/BaseCriteriaRelyingPartyConfiigurationResolver.java
index 1a5db71..5533814 100644
--- a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/BaseCriteriaRelyingPartyConfiigurationResolver.java
@@ -32,7 +32,7 @@ import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
import net.shibboleth.profile.relyingparty.RelyingPartyConfigurationResolver;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
-import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.component.AbstractIdentifiedInitializableComponent;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.component.IdentifiableComponent;
@@ -45,19 +45,21 @@ import net.shibboleth.shared.service.ServiceException;
import net.shibboleth.shared.service.ServiceableComponent;
/**
- * Resolver which uses an instance of {@link RelyingPartyConfigurationResolver} to
- * resolve our own entityID.
+ * Abstract base resolver which uses an instance of {@link RelyingPartyConfigurationResolver} to
+ * resolve a {@link RelyingPartyConfiguration} using an input {@link CriteriaSet} only.
*
* <p>
* The required and allowed criteria are the same as the {@link RelyingPartyConfigurationResolver}
* implementation in use.
* </p>
+ *
+ * @param <ReturnType> The type of data returned by the resolver
*/
-public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializableComponent
- implements Resolver<String, CriteriaSet>, IdentifiableComponent {
+public abstract class BaseCriteriaRelyingPartyConfiigurationResolver<ReturnType> extends AbstractIdentifiedInitializableComponent
+ implements Resolver<ReturnType, CriteriaSet>, IdentifiableComponent {
/** Logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(CriteriaSelfEntityIDResolver.class);
+ @Nonnull private Logger log = LoggerFactory.getLogger(BaseCriteriaRelyingPartyConfiigurationResolver.class);
/** The RelyingPartyConfigurationResolver to which to delegate. */
@NonnullAfterInit private ReloadableService<RelyingPartyConfigurationResolver> rpcResolver;
@@ -94,18 +96,18 @@ public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializabl
super.doDestroy();
}
- /** {@inheritDoc} */
- @Nonnull public Iterable<String> resolve(@Nullable final CriteriaSet criteria) throws ResolverException {
- checkComponentActive();
- final String entityID = resolveSingle(criteria);
- if (entityID != null) {
- return CollectionSupport.singletonList(entityID);
- }
- return CollectionSupport.emptyList();
- }
-
- /** {@inheritDoc} */
- @Nullable public String resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
+ /**
+ * Resolve the {@link RelyingPartyConfiguration} based on the input {@link CriteriaSet}.
+ *
+ * @param criteria the criteria for resolution
+ *
+ * @return the relying party configuration along with the internal synthetic profile request context
+ * (often necessary for further data fetching from the configuration), or null if resolution fails
+ *
+ * @throws ResolverException if there is a fatal error resolving the configuration
+ */
+ @Nullable protected Pair<RelyingPartyConfiguration, ProfileRequestContext> resolveRelyingPartyConfiguration(
+ @Nullable final CriteriaSet criteria) throws ResolverException {
checkComponentActive();
final ProfileRequestContext prc = buildContext(criteria);
@@ -118,12 +120,7 @@ public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializabl
try (final ServiceableComponent<RelyingPartyConfigurationResolver> resolver =
rpcResolver.getServiceableComponent()) {
- final RelyingPartyConfiguration rpc = resolver.getComponent().resolveSingle(prcSet);
- if (rpc != null) {
- return rpc.getIssuer(prc);
- } else {
- log.error("RelyingPartyConfigurationResolver returned null configuration");
- }
+ return new Pair<>(resolver.getComponent().resolveSingle(prcSet), prc);
} catch (final ResolverException e) {
log.error("RelyingPartyConfigurationResolver did not resolve a RelyingPartyConfiguration: {}", e.getMessage());
} catch (final ServiceException e) {
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaDecryptionConfigurationResolver.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaDecryptionConfigurationResolver.java
new file mode 100644
index 0000000..a63a57f
--- /dev/null
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaDecryptionConfigurationResolver.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed 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.profile.relyingparty.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileIDCriterion;
+import org.opensaml.security.config.SecurityConfiguration;
+import org.opensaml.xmlsec.DecryptionConfiguration;
+import org.opensaml.xmlsec.SecurityConfigurationSupport;
+import org.opensaml.xmlsec.config.XMLSecurityConfiguration;
+
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfigurationResolver;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
+
+/**
+ * Resolver which uses an instance of {@link RelyingPartyConfigurationResolver} to
+ * resolve a list of {@link DecryptionConfiguration} applicable for a peer entity.
+ *
+ * <p>
+ * The required and allowed criteria are the same as the {@link RelyingPartyConfigurationResolver}
+ * implementation in use. Also supports an optional {@link ProfileIDCriterion}, which if supplied is used
+ * to resolve the profile-specific configuration.
+ * </p>
+ */
+public class CriteriaDecryptionConfigurationResolver
+ extends BaseCriteriaRelyingPartyConfiigurationResolver<List<DecryptionConfiguration>> {
+
+ /** {@inheritDoc} */
+ @Nonnull public Iterable<List<DecryptionConfiguration>> resolve(@Nullable final CriteriaSet criteria) throws ResolverException {
+ checkComponentActive();
+ final List<DecryptionConfiguration> config = resolveSingle(criteria);
+ if (config != null) {
+ return CollectionSupport.singletonList(config);
+ }
+ return CollectionSupport.emptyList();
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public List<DecryptionConfiguration> resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
+ checkComponentActive();
+
+ final Pair<RelyingPartyConfiguration, ProfileRequestContext> rpcData = resolveRelyingPartyConfiguration(criteria);
+ if (rpcData != null) {
+ final RelyingPartyConfiguration rpc = rpcData.getFirst();
+ final ProfileRequestContext prc = rpcData.getSecond();
+ assert rpc != null && prc != null;
+
+ return buildConfigList(rpc, prc, criteria);
+ }
+ return null;
+ }
+
+ /**
+ * Build the list of configurations.
+ *
+ * @param rpc the relying party configuration
+ * @param prc the synthetic profile request context
+ * @param criteria the input criteria
+ *
+ * @return the list of configurations
+ */
+ @Nonnull private List<DecryptionConfiguration> buildConfigList(@Nonnull final RelyingPartyConfiguration rpc,
+ @Nonnull final ProfileRequestContext prc, CriteriaSet criteria) {
+
+ final List<DecryptionConfiguration> configs = new ArrayList<>();
+
+ String profileID = null;
+ final ProfileIDCriterion profileIDCriterion = criteria.get(ProfileIDCriterion.class);
+ if (profileIDCriterion != null) {
+ profileID = profileIDCriterion.getProfileId();
+ }
+
+ if (profileID != null) {
+ final ProfileConfiguration pc = rpc.getProfileConfiguration(prc, profileID);
+ if (pc != null) {
+ final SecurityConfiguration sc = pc.getSecurityConfiguration(prc);
+ if (sc instanceof XMLSecurityConfiguration xsc && xsc.getDecryptionConfiguration() != null) {
+ configs.add(xsc.getDecryptionConfiguration());
+ }
+ }
+ }
+
+ final SecurityConfiguration defaultConfig = rpc.getSecurityConfiguration(prc);
+ if (defaultConfig instanceof XMLSecurityConfiguration xsc && xsc.getDecryptionConfiguration() != null) {
+ configs.add(xsc.getDecryptionConfiguration());
+ }
+
+ configs.add(SecurityConfigurationSupport.getGlobalDecryptionConfiguration());
+
+ return configs;
+ }
+
+}
\ No newline at end of file
diff --git a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java
index 1a5db71..1ac4716 100644
--- a/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java
+++ b/shib-profile-impl/src/main/java/net/shibboleth/profile/relyingparty/impl/CriteriaSelfEntityIDResolver.java
@@ -17,32 +17,14 @@ package net.shibboleth.profile.relyingparty.impl;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.opensaml.core.criterion.EntityIdCriterion;
import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
-import org.opensaml.saml.common.messaging.context.SAMLMetadataContext;
-import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
-import org.opensaml.saml.criterion.RoleDescriptorCriterion;
-import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-import org.opensaml.saml.saml2.metadata.RoleDescriptor;
-import org.slf4j.Logger;
-import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
import net.shibboleth.profile.relyingparty.RelyingPartyConfigurationResolver;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.collection.CollectionSupport;
-import net.shibboleth.shared.component.AbstractIdentifiedInitializableComponent;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.component.IdentifiableComponent;
-import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.resolver.CriteriaSet;
-import net.shibboleth.shared.resolver.Resolver;
import net.shibboleth.shared.resolver.ResolverException;
-import net.shibboleth.shared.service.ReloadableService;
-import net.shibboleth.shared.service.ServiceException;
-import net.shibboleth.shared.service.ServiceableComponent;
/**
* Resolver which uses an instance of {@link RelyingPartyConfigurationResolver} to
@@ -53,47 +35,8 @@ import net.shibboleth.shared.service.ServiceableComponent;
* implementation in use.
* </p>
*/
-public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializableComponent
- implements Resolver<String, CriteriaSet>, IdentifiableComponent {
+public class CriteriaSelfEntityIDResolver extends BaseCriteriaRelyingPartyConfiigurationResolver<String> {
- /** Logger. */
- @Nonnull private Logger log = LoggerFactory.getLogger(CriteriaSelfEntityIDResolver.class);
-
- /** The RelyingPartyConfigurationResolver to which to delegate. */
- @NonnullAfterInit private ReloadableService<RelyingPartyConfigurationResolver> rpcResolver;
-
- /**
- * Set the {@link RelyingPartyConfigurationResolver} instance to which to delegate.
- *
- * @param resolver the relying party resolver
- */
- public void setRelyingPartyConfigurationResolver(
- @Nullable final ReloadableService<RelyingPartyConfigurationResolver> resolver) {
- checkSetterPreconditions();
-
- rpcResolver = resolver;
- }
-
- /** {@inheritDoc} */
- @Override public void setId(@Nonnull @NotEmpty final String componentId) {
- super.setId(componentId);
- }
-
- /** {@inheritDoc} */
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (rpcResolver == null) {
- throw new ComponentInitializationException("RelyingPartyConfigurationResolver cannot be null");
- }
- }
-
- /** {@inheritDoc} */
- protected void doDestroy() {
- rpcResolver = null;
- super.doDestroy();
- }
-
/** {@inheritDoc} */
@Nonnull public Iterable<String> resolve(@Nullable final CriteriaSet criteria) throws ResolverException {
checkComponentActive();
@@ -107,131 +50,15 @@ public class CriteriaSelfEntityIDResolver extends AbstractIdentifiedInitializabl
/** {@inheritDoc} */
@Nullable public String resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException {
checkComponentActive();
-
- final ProfileRequestContext prc = buildContext(criteria);
- if (prc == null) {
- log.error("Unable to extract or build ProfileRequestContext for resolution");
- return null;
- }
-
- final CriteriaSet prcSet = new CriteriaSet(new ProfileRequestContextCriterion(prc));
-
- try (final ServiceableComponent<RelyingPartyConfigurationResolver> resolver =
- rpcResolver.getServiceableComponent()) {
- final RelyingPartyConfiguration rpc = resolver.getComponent().resolveSingle(prcSet);
- if (rpc != null) {
- return rpc.getIssuer(prc);
- } else {
- log.error("RelyingPartyConfigurationResolver returned null configuration");
- }
- } catch (final ResolverException e) {
- log.error("RelyingPartyConfigurationResolver did not resolve a RelyingPartyConfiguration: {}", e.getMessage());
- } catch (final ServiceException e) {
- log.error("RelyingPartyConfiguration resolver unvailable: {}", e.getMessage());
- }
- return null;
- }
-
- /**
- * Build and populate the synthetic instance of {@link ProfileRequestContext} which will be used
- * in the resolution call to the delegate as well as to resolve the entityID setting.
- *
- * @param criteria the input criteria
- * @return the synthetic context instance, or null if required data is not supplied
- */
- @Nullable private ProfileRequestContext buildContext(@Nullable final CriteriaSet criteria) {
- if (criteria == null) {
- return null;
- }
-
- final ProfileRequestContextCriterion prcCriterion = criteria.get(ProfileRequestContextCriterion.class);
- if (prcCriterion != null) {
- return prcCriterion.getProfileRequestContext();
- }
-
- final String entityID = resolveEntityID(criteria);
- log.debug("Resolved effective entityID from criteria: {}", entityID);
-
- final EntityDescriptor entityDescriptor = resolveEntityDescriptor(criteria);
- log.debug("Resolved effective entity descriptor from criteria: {}", entityDescriptor);
- final RoleDescriptor roleDescriptor = resolveRoleDescriptor(criteria);
- log.debug("Resolved effective role descriptor from criteria: {}", roleDescriptor);
+ final Pair<RelyingPartyConfiguration, ProfileRequestContext> rpcData = resolveRelyingPartyConfiguration(criteria);
+ if (rpcData != null) {
+ final RelyingPartyConfiguration rpc = rpcData.getFirst();
+ final ProfileRequestContext prc = rpcData.getSecond();
+ assert rpc != null && prc != null;
- if (entityID != null || entityDescriptor != null || roleDescriptor != null) {
- final ProfileRequestContext prc = new ProfileRequestContext();
- final RelyingPartyContext rpc = prc.ensureSubcontext(RelyingPartyContext.class);
- rpc.setVerified(true);
-
- rpc.setRelyingPartyId(entityID);
-
- if (entityDescriptor != null || roleDescriptor != null) {
- final SAMLPeerEntityContext peerContext = prc.ensureSubcontext(SAMLPeerEntityContext.class);
- rpc.setRelyingPartyIdContextTree(peerContext);
-
- peerContext.setEntityId(entityID);
-
- if (roleDescriptor != null) {
- peerContext.setRole(roleDescriptor.getSchemaType() != null
- ? roleDescriptor.getSchemaType() : roleDescriptor.getElementQName());
- }
-
- final SAMLMetadataContext metadataContext = peerContext.ensureSubcontext(SAMLMetadataContext.class);
- metadataContext.setEntityDescriptor(entityDescriptor);
- metadataContext.setRoleDescriptor(roleDescriptor);
- }
- return prc;
- }
- return null;
- }
-
- /**
- * Resolve the entityID from the criteria.
- *
- * @param criteria the input criteria
- * @return the input entityID criterion or null if could not be resolved
- */
- @Nullable private String resolveEntityID(@Nonnull final CriteriaSet criteria) {
- final EntityIdCriterion eic = criteria.get(EntityIdCriterion.class);
- if (eic != null) {
- return eic.getEntityId();
- }
-
- final EntityDescriptor ed = resolveEntityDescriptor(criteria);
- if (ed != null) {
- return ed.getEntityID();
+ return rpc.getIssuer(prc);
}
-
- return null;
- }
-
- /**
- * Resolve the EntityDescriptor from the criteria.
- *
- * @param criteria the input criteria
- * @return the input entity descriptor criterion, or null if could not be resolved
- */
- @Nullable private EntityDescriptor resolveEntityDescriptor(@Nonnull final CriteriaSet criteria) {
- final RoleDescriptor rd = resolveRoleDescriptor(criteria);
- if (rd != null && rd.getParent() != null && rd.getParent() instanceof EntityDescriptor) {
- return (EntityDescriptor)rd.getParent();
- }
-
- return null;
- }
-
- /**
- * Resolve the RoleDescriptor from the criteria.
- *
- * @param criteria the input criteria
- * @return the input role descriptor criterion or null if could not be resolved
- */
- @Nullable private RoleDescriptor resolveRoleDescriptor(@Nonnull final CriteriaSet criteria) {
- final RoleDescriptorCriterion rdc = criteria.get(RoleDescriptorCriterion.class);
- if (rdc != null) {
- return rdc.getRole();
- }
-
return null;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list