All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nimbusds.openid.connect.sdk.federation.trust.TrustChainResolver Maven / Gradle / Ivy

Go to download

OAuth 2.0 SDK with OpenID Connection extensions for developing client and server applications.

There is a newer version: 11.19.1
Show newest version
/*
 * oauth2-oidc-sdk
 *
 * Copyright 2012-2020, Connect2id Ltd and contributors.
 *
 * 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 com.nimbusds.openid.connect.sdk.federation.trust;


import java.util.*;

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.proc.BadJOSEException;
import com.nimbusds.oauth2.sdk.util.MapUtils;
import com.nimbusds.openid.connect.sdk.federation.entities.EntityID;
import com.nimbusds.openid.connect.sdk.federation.entities.EntityStatement;
import com.nimbusds.openid.connect.sdk.federation.trust.constraints.TrustChainConstraints;


/**
 * Trust chain resolver.
 *
 * 

Related specifications: * *

    *
  • OpenID Connect Federation 1.0, section 9. *
*/ public class TrustChainResolver { /** * The configured trust anchors with their public JWK sets. */ private final Map trustAnchors; /** * The entity statement retriever. */ private final EntityStatementRetriever statementRetriever; /** * The trust chain constraints. */ private final TrustChainConstraints constraints; /** * Creates a new trust chain resolver with a single trust anchor, with * {@link TrustChainConstraints#NO_CONSTRAINTS no trust chain * constraints}. * * @param trustAnchor The trust anchor. Must not be {@code null}. */ public TrustChainResolver(final EntityID trustAnchor) { this(trustAnchor, null); } /** * Creates a new trust chain resolver with a single trust anchor, with * {@link TrustChainConstraints#NO_CONSTRAINTS no trust chain * constraints}. * * @param trustAnchor The trust anchor. Must not be {@code null}. * @param trustAnchorJWKSet The trust anchor public JWK set, * {@code null} if not available. */ public TrustChainResolver(final EntityID trustAnchor, final JWKSet trustAnchorJWKSet) { this( Collections.singletonMap(trustAnchor, trustAnchorJWKSet), TrustChainConstraints.NO_CONSTRAINTS, new DefaultEntityStatementRetriever() ); } /** * Creates a new trust chain resolver with multiple trust anchors, with * {@link TrustChainConstraints#NO_CONSTRAINTS no trust chain * constraints}. * * @param trustAnchors The trust anchors with their public JWK * sets (if available). Must contain at * least one anchor. * @param httpConnectTimeoutMs The HTTP connect timeout in * milliseconds, zero means timeout * determined by the underlying HTTP * client. * @param httpReadTimeoutMs The HTTP read timeout in milliseconds, * zero means timeout determined by the * underlying HTTP client. */ public TrustChainResolver(final Map trustAnchors, final int httpConnectTimeoutMs, final int httpReadTimeoutMs) { this( trustAnchors, TrustChainConstraints.NO_CONSTRAINTS, new DefaultEntityStatementRetriever(httpConnectTimeoutMs, httpReadTimeoutMs) ); } /** * Creates new trust chain resolver. * * @param trustAnchors The trust anchors with their public JWK * sets. Must contain at least one anchor. * @param constraints The constraints to apply during retrieval. * Must not be {@code null}. * @param statementRetriever The entity statement retriever to use. * Must not be {@code null}. */ public TrustChainResolver(final Map trustAnchors, final TrustChainConstraints constraints, final EntityStatementRetriever statementRetriever) { if (MapUtils.isEmpty(trustAnchors)) { throw new IllegalArgumentException("The trust anchors map must not be empty or null"); } this.trustAnchors = trustAnchors; if (constraints == null) { throw new IllegalArgumentException("The trust chain constraints must not be null"); } this.constraints = constraints; if (statementRetriever == null) { throw new IllegalArgumentException("The entity statement retriever must not be null"); } this.statementRetriever = statementRetriever; } /** * Returns the configured trust anchors. * * @return The trust anchors with their public JWK sets (if available). * Contains at least one anchor. */ public Map getTrustAnchors() { return Collections.unmodifiableMap(trustAnchors); } /** * Returns the configured entity statement retriever. * * @return The entity statement retriever. */ public EntityStatementRetriever getEntityStatementRetriever() { return statementRetriever; } /** * Returns the configured trust chain constraints. * * @return The constraints. */ public TrustChainConstraints getConstraints() { return constraints; } /** * Resolves the trust chains for the specified target. * * @param target The target. Must not be {@code null}. * * @return The resolved trust chains, containing at least one valid and * verified chain. * * @throws ResolveException If no trust chain could be resolved. */ public TrustChainSet resolveTrustChains(final EntityID target) throws ResolveException { try { return resolveTrustChains(target, null); } catch (InvalidEntityMetadataException e) { // Should never occur if target metadata validator omitted throw new IllegalStateException("Unexpected exception: " + e.getMessage(), e); } } /** * Resolves the trust chains for the specified target, with optional * validation of the target entity metadata. The validator can for * example check that for an entity which is expected to be an OpenID * relying party the required party metadata is present. * * @param target The target. Must not be {@code null}. * @param targetMetadataValidator To perform optional validation of the * retrieved target entity metadata, * before proceeding with retrieving the * entity statements from the * authorities, {@code null} if not * specified. * * @return The resolved trust chains, containing at least one valid and * verified chain. * * @throws ResolveException If a trust chain could not be * resolved. * @throws InvalidEntityMetadataException If the optional target entity * metadata validation didn't * pass. */ public TrustChainSet resolveTrustChains(final EntityID target, final EntityMetadataValidator targetMetadataValidator) throws ResolveException, InvalidEntityMetadataException { if (trustAnchors.get(target) != null) { throw new ResolveException("Target is trust anchor"); } TrustChainRetriever retriever = new DefaultTrustChainRetriever(statementRetriever, constraints); Set fetchedTrustChains = retriever.retrieve(target, targetMetadataValidator, trustAnchors.keySet()); return verifyTrustChains( fetchedTrustChains, retriever.getAccumulatedTrustAnchorJWKSets(), retriever.getAccumulatedExceptions()); } /** * Resolves the trust chains for the specified target. * * @param targetStatement The target entity statement. Must not be * {@code null}. * * @return The resolved trust chains, containing at least one valid and * verified chain. * * @throws ResolveException If no trust chain could be resolved. */ public TrustChainSet resolveTrustChains(final EntityStatement targetStatement) throws ResolveException { if (trustAnchors.get(targetStatement.getEntityID()) != null) { throw new ResolveException("Target is trust anchor"); } TrustChainRetriever retriever = new DefaultTrustChainRetriever(statementRetriever, constraints); Set fetchedTrustChains = retriever.retrieve(targetStatement, trustAnchors.keySet()); return verifyTrustChains( fetchedTrustChains, retriever.getAccumulatedTrustAnchorJWKSets(), retriever.getAccumulatedExceptions()); } /** * Verifies the specified fetched trust chains. * * @param fetchedTrustChains The fetched trust chains. Must * not be {@code null}, * @param accumulatedTrustAnchorJWKSets The accumulated trust anchor(s) * JWK sets, empty if none. Must * not be {@code null}. * @param accumulatedExceptions The accumulated exceptions, * empty if none. Must not be * {@code null}. * @return The verified trust chain set. * * @throws ResolveException If no trust chain could be verified. */ private TrustChainSet verifyTrustChains(final Set fetchedTrustChains, final Map accumulatedTrustAnchorJWKSets, final List accumulatedExceptions) throws ResolveException { if (fetchedTrustChains.isEmpty()) { if (accumulatedExceptions.isEmpty()) { throw new ResolveException("No trust chain leading up to a trust anchor"); } else if (accumulatedExceptions.size() == 1){ Throwable cause = accumulatedExceptions.get(0); throw new ResolveException("Couldn't resolve trust chain: " + cause.getMessage(), cause); } else { throw new ResolveException("Couldn't resolve trust chain due to multiple causes", accumulatedExceptions); } } List verificationExceptions = new LinkedList<>(); TrustChainSet verifiedTrustChains = new TrustChainSet(); for (TrustChain chain: fetchedTrustChains) { EntityID anchor = chain.getTrustAnchorEntityID(); JWKSet anchorJWKSet = trustAnchors.get(anchor); if (anchorJWKSet == null) { anchorJWKSet = accumulatedTrustAnchorJWKSets.get(anchor); } try { chain.verifySignatures(anchorJWKSet); } catch (BadJOSEException | JOSEException e) { verificationExceptions.add(e); continue; } verifiedTrustChains.add(chain); } if (verifiedTrustChains.isEmpty()) { List moreAccumulatedExceptions = new LinkedList<>(accumulatedExceptions); moreAccumulatedExceptions.addAll(verificationExceptions); if (verificationExceptions.size() == 1) { Throwable cause = verificationExceptions.get(0); throw new ResolveException("Couldn't resolve trust chain: " + cause.getMessage(), moreAccumulatedExceptions); } else { throw new ResolveException("Couldn't resolve trust chain due to multiple causes", moreAccumulatedExceptions); } } return verifiedTrustChains; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy