View Javadoc

1   /*
2    * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.opensaml.common.binding;
18  
19  import java.util.ArrayList;
20  import java.util.Iterator;
21  import java.util.List;
22  
23  import org.opensaml.saml2.metadata.Endpoint;
24  import org.opensaml.saml2.metadata.IndexedEndpoint;
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  /**
29   * This endpoint selector retrieves all the endpoints for a given role. A first filter pass removes those endpoints that
30   * use bindings which are not supported by the issuer. If the remaining endpoints are not {@link IndexedEndpoint}s the
31   * first endpoint in the list is returned. If the remaining endpoints are {@link IndexedEndpoint}s the first endpoint
32   * with the isDefault attribute set to true is returned, if no isDefault attribute is set to true the first endpoint to
33   * omit this attribute is returned, and if all the endpoints have the isDefault attribute set to false then the first
34   * endpoint in the list is returned.
35   * 
36   * Prior to selecting the endpoint the following fields <strong>must</strong> have had values set: entity role,
37   * endpoint type, issuer supported bindings.
38   * 
39   * While this algorithm with work for selecting the endpoint for responses to AuthnRequests the SAML
40   * specification does stipulate additional endpoint selection criteria and as such the use of an endpoint selector
41   * specifically meant to handler this situation should be used, for example: AuthnResponseEndpointSelector.
42   */
43  public class BasicEndpointSelector extends AbstractEndpointSelector {
44      
45      /** Class logger. */
46      private Logger log = LoggerFactory.getLogger(BasicEndpointSelector.class);
47  
48      /** {@inheritDoc} */
49      @SuppressWarnings("unchecked")
50      public Endpoint selectEndpoint() {
51          if(getEntityRoleMetadata() == null){
52              return null;
53          }
54          
55          List<? extends Endpoint> endpoints = getEntityRoleMetadata().getEndpoints(getEndpointType());
56          if (endpoints == null || endpoints.size() == 0) {
57              return null;
58          }
59  
60          Endpoint selectedEndpoint;
61          endpoints = filterEndpointsByProtocolBinding(endpoints);
62          if (endpoints == null || endpoints.size() == 0) {
63              return null;
64          }
65          if (endpoints.get(0) instanceof IndexedEndpoint) {
66              selectedEndpoint = selectIndexedEndpoint((List<IndexedEndpoint>) endpoints);
67          } else {
68              selectedEndpoint = selectNonIndexedEndpoint((List<Endpoint>) endpoints);
69          }
70          
71          log.debug("Selected endpoint {} for request", selectedEndpoint.getLocation());
72          return selectedEndpoint;
73      }
74      
75      /**
76       * Filters the list of possible endpoints by supported outbound bindings.
77       * 
78       * @param endpoints raw list of endpoints
79       * 
80       * @return filtered endpoints
81       */
82      protected List<? extends Endpoint> filterEndpointsByProtocolBinding(List<? extends Endpoint> endpoints) {
83          List<Endpoint> filteredEndpoints = new ArrayList<Endpoint>(endpoints);
84          Iterator<Endpoint> endpointItr = filteredEndpoints.iterator();
85          Endpoint endpoint;
86          while (endpointItr.hasNext()) {
87              endpoint = endpointItr.next();
88              if (!getSupportedIssuerBindings().contains(endpoint.getBinding())) {
89                  endpointItr.remove();
90                  continue;
91              }
92          }
93  
94          return filteredEndpoints;
95      }
96  
97      /**
98       * Selects an appropriate endpoint from a list of indexed endpoints.
99       * 
100      * @param endpoints list of indexed endpoints
101      * 
102      * @return appropriate endpoint from a list of indexed endpoints or null
103      */
104     protected Endpoint selectIndexedEndpoint(List<IndexedEndpoint> endpoints) {
105         List<IndexedEndpoint> endpointsCopy = new ArrayList<IndexedEndpoint>(endpoints);
106         Iterator<IndexedEndpoint> endpointItr = endpointsCopy.iterator();
107         IndexedEndpoint firstNoDefaultEndpoint = null;
108         IndexedEndpoint currentEndpoint;
109         while (endpointItr.hasNext()) {
110             currentEndpoint = endpointItr.next();
111 
112             // endpoint is the default endpoint
113             if (currentEndpoint.isDefault() != null) {
114                 if (currentEndpoint.isDefault()) {
115                     return currentEndpoint;
116                 }
117 
118                 if (firstNoDefaultEndpoint == null) {
119                     firstNoDefaultEndpoint = currentEndpoint;
120                 }
121             }
122         }
123 
124         if (firstNoDefaultEndpoint != null) {
125             // no endpoint was marked as the default, return first unmarked endpoint
126             return firstNoDefaultEndpoint;
127         } else {
128             if (endpointsCopy.size() > 0) {
129                 // no endpoint had an index so return the first one
130                 return endpointsCopy.get(0);
131             } else {
132                 // no endpoints made it through the supported binding filter
133                 return null;
134             }
135         }
136     }
137 
138     /**
139      * Selects an appropriate endpoint from a list of non-indexed endpoints.
140      * 
141      * @param endpoints list of non-indexed endpoints
142      * 
143      * @return appropriate endpoint from a list of non-indexed endpoints or null
144      */
145     protected Endpoint selectNonIndexedEndpoint(List<Endpoint> endpoints) {
146         Iterator<Endpoint> endpointItr = endpoints.iterator();
147         Endpoint endpoint;
148         while (endpointItr.hasNext()) {
149             endpoint = endpointItr.next();
150 
151             // Endpoint is first one of acceptable binding, return it.
152             return endpoint;
153         }
154 
155         // No endpoints had acceptable binding
156         return null;
157     }
158 }