/* * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.] * * 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 org.opensaml.saml2.binding; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.opensaml.common.binding.BasicEndpointSelector; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.metadata.Endpoint; import org.opensaml.saml2.metadata.IndexedEndpoint; import org.opensaml.xml.util.DatatypeHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An endpoint selector that implements the additional selection constraints described within the SAML 2.0 AuthnRequest * specification. If an endpoint can not be resolved using either the information within the assertion consumer service * index or the assertion consumer service URL given in the authentication request, or if this information isn't * present, than the rules for the {@link BasicEndpointSelector} are used. */ public class AuthnResponseEndpointSelector extends BasicEndpointSelector { /** Class logger. */ private final Logger log = LoggerFactory.getLogger(AuthnResponseEndpointSelector.class); /** {@inheritDoc} */ @SuppressWarnings("unchecked") public Endpoint selectEndpoint() { if (getEntityRoleMetadata() == null) { log.debug("Unable to select endpoint, no entity role metadata available."); return null; } List<? extends Endpoint> endpoints = getEntityRoleMetadata().getEndpoints(getEndpointType()); if (endpoints == null || endpoints.size() == 0) { return null; } Endpoint endpoint = null; if (getSamlRequest() != null) { AuthnRequest request = (AuthnRequest) getSamlRequest(); endpoints = filterEndpointsByProtocolBinding(endpoints); if (endpoints == null || endpoints.isEmpty()) { return null; } if (request.getAssertionConsumerServiceIndex() != null) { log.debug("Selecting endpoint by ACS index for request {} from entity {}", request.getID(), getEntityMetadata().getEntityID()); endpoint = selectEndpointByACSIndex(request, (List<IndexedEndpoint>) endpoints); } else if (request.getAssertionConsumerServiceURL() != null) { log.debug("Selecting endpoint by ACS URL for request {} from entity {}", request.getID(), getEntityMetadata().getEntityID()); endpoint = selectEndpointByACSURL(request, (List<IndexedEndpoint>) endpoints); } } if (endpoint == null) { if (endpoints.get(0) instanceof IndexedEndpoint) { endpoint = selectIndexedEndpoint((List<IndexedEndpoint>) endpoints); } else { endpoint = selectNonIndexedEndpoint((List<Endpoint>) endpoints); } } return endpoint; } /** * Filters the list of possible endpoints by supported outbound bindings and, if the authentication request contains * a requested binding and not an ACS index, that too is used to filter the list. * * @param endpoints raw list of endpoints * * @return filtered endpoints */ protected List<? extends Endpoint> filterEndpointsByProtocolBinding(List<? extends Endpoint> endpoints) { log.debug("Filtering peer endpoints. Supported peer endpoint bindings: {}", getSupportedIssuerBindings()); AuthnRequest request = (AuthnRequest) getSamlRequest(); boolean filterByRequestBinding = false; String acsBinding = DatatypeHelper.safeTrimOrNullString(request.getProtocolBinding()); if (acsBinding != null && request.getAssertionConsumerServiceIndex() != null) { filterByRequestBinding = true; } List<Endpoint> filteredEndpoints = new ArrayList<Endpoint>(endpoints); Iterator<Endpoint> endpointItr = filteredEndpoints.iterator(); Endpoint endpoint; while (endpointItr.hasNext()) { endpoint = endpointItr.next(); if (!getSupportedIssuerBindings().contains(endpoint.getBinding())) { log.debug("Removing endpoint {} because its binding {} is not supported", endpoint.getLocation(), endpoint.getBinding()); endpointItr.remove(); continue; } if (filterByRequestBinding && !endpoint.getBinding().equals(acsBinding)) { log.debug("Removing endpoint {} because its binding {} does not match request's requested binding", endpoint.getLocation(), endpoint.getBinding()); endpointItr.remove(); } } return filteredEndpoints; } /** * Selects the endpoint by way of the assertion consumer service index given in the AuthnRequest. * * @param request the AuthnRequest * @param endpoints list of endpoints to select from * * @return the selected endpoint */ protected Endpoint selectEndpointByACSIndex(AuthnRequest request, List<IndexedEndpoint> endpoints) { Integer acsIndex = request.getAssertionConsumerServiceIndex(); for (IndexedEndpoint endpoint : endpoints) { if (endpoint == null || !getSupportedIssuerBindings().contains(endpoint.getBinding())) { continue; } if (endpoint.getIndex() != null && endpoint.getIndex().equals(acsIndex)) { return endpoint; } } return null; } /** * Selects the endpoint by way of the assertion consumer service URL given in the AuthnRequest. * * @param request the AuthnRequest * @param endpoints list of endpoints to select from * * @return the selected endpoint */ protected Endpoint selectEndpointByACSURL(AuthnRequest request, List<IndexedEndpoint> endpoints) { String acsBinding = DatatypeHelper.safeTrimOrNullString(request.getProtocolBinding()); if (acsBinding == null) { return null; } for (IndexedEndpoint endpoint : endpoints) { if (!getSupportedIssuerBindings().contains(endpoint.getBinding())) { continue; } if (endpoint.getBinding().equals(acsBinding)) { if ((endpoint.getLocation() != null && endpoint.getLocation().equals(request.getAssertionConsumerServiceURL())) || (endpoint.getResponseLocation() != null && endpoint.getResponseLocation().equals(request.getAssertionConsumerServiceURL()))) { return endpoint; } } } return null; } }