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 edu.internet2.middleware.shibboleth.common.attribute.provider;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import org.opensaml.Configuration;
27  import org.opensaml.common.SAMLObject;
28  import org.opensaml.common.SAMLObjectBuilder;
29  import org.opensaml.saml1.core.Attribute;
30  import org.opensaml.saml1.core.AttributeDesignator;
31  import org.opensaml.saml1.core.AttributeQuery;
32  import org.opensaml.saml1.core.AttributeStatement;
33  import org.opensaml.saml1.core.NameIdentifier;
34  import org.opensaml.saml1.core.ResponseAbstractType;
35  import org.opensaml.saml2.metadata.EntityDescriptor;
36  import org.opensaml.xml.XMLObjectBuilderFactory;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  import org.springframework.context.ApplicationContext;
40  
41  import edu.internet2.middleware.shibboleth.common.attribute.AttributeRequestException;
42  import edu.internet2.middleware.shibboleth.common.attribute.BaseAttribute;
43  import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncoder;
44  import edu.internet2.middleware.shibboleth.common.attribute.encoding.AttributeEncodingException;
45  import edu.internet2.middleware.shibboleth.common.attribute.encoding.SAML1AttributeEncoder;
46  import edu.internet2.middleware.shibboleth.common.attribute.filtering.provider.ShibbolethAttributeFilteringEngine;
47  import edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.ShibbolethAttributeResolver;
48  import edu.internet2.middleware.shibboleth.common.config.BaseService;
49  import edu.internet2.middleware.shibboleth.common.profile.provider.SAMLProfileRequestContext;
50  import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
51  import edu.internet2.middleware.shibboleth.common.service.ServiceException;
52  
53  /**
54   * SAML 1 Attribute Authority.
55   */
56  public class ShibbolethSAML1AttributeAuthority extends BaseService implements SAML1AttributeAuthority {
57  
58      /** Class logger. */
59      private final Logger log = LoggerFactory.getLogger(ShibbolethSAML1AttributeAuthority.class);
60  
61      /** For building attribute statements. */
62      private SAMLObjectBuilder<AttributeStatement> statementBuilder;
63  
64      /** Attribute resolver. */
65      private ShibbolethAttributeResolver attributeResolver;
66  
67      /** To determine releasable attributes. */
68      private ShibbolethAttributeFilteringEngine filteringEngine;
69  
70      /**
71       * This creates a new attribute authority.
72       * 
73       * @param resolver The attribute resolver to set
74       */
75      @SuppressWarnings("unchecked")
76      public ShibbolethSAML1AttributeAuthority(ShibbolethAttributeResolver resolver) {
77  
78          XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
79          statementBuilder = (SAMLObjectBuilder<AttributeStatement>) builderFactory
80                  .getBuilder(AttributeStatement.DEFAULT_ELEMENT_NAME);
81  
82          attributeResolver = resolver;
83      }
84  
85      /**
86       * Gets the attribute resolver.
87       * 
88       * @return Returns the attributeResolver.
89       */
90      public ShibbolethAttributeResolver getAttributeResolver() {
91          return attributeResolver;
92      }
93  
94      /**
95       * Gets the filtering engine.
96       * 
97       * @return Returns the filteringEngine.
98       */
99      public ShibbolethAttributeFilteringEngine getFilteringEngine() {
100         return filteringEngine;
101     }
102 
103     /**
104      * Sets the attribute filtering engine.
105      * 
106      * @param engine attribute filtering engine
107      */
108     public void setFilteringEngine(ShibbolethAttributeFilteringEngine engine) {
109         filteringEngine = engine;
110     }
111 
112     /** {@inheritDoc} */
113     public AttributeStatement buildAttributeStatement(AttributeQuery query, Collection<BaseAttribute> attributes)
114             throws AttributeEncodingException {
115 
116         Collection<Attribute> encodedAttributes = encodeAttributes(attributes);
117         if (encodedAttributes != null && !encodedAttributes.isEmpty()) {
118             AttributeStatement statement = statementBuilder.buildObject();
119             statement.getAttributes().addAll(encodedAttributes);
120             return statement;
121         } else {
122             log.debug("No attributes were encoded, no attribute statement created.");
123             return null;
124         }
125     }
126 
127     /** {@inheritDoc} */
128     public String getAttributeIDBySAMLAttribute(AttributeDesignator attribute) {
129         // TODO Auto-generated method stub
130         return null;
131     }
132 
133     /** {@inheritDoc} */
134     public String getPrincipal(
135             SAMLProfileRequestContext<? extends SAMLObject, ? extends ResponseAbstractType, NameIdentifier, ? extends AbstractSAML1ProfileConfiguration> requestContext)
136             throws AttributeRequestException {
137         if (requestContext.getInboundMessageIssuer() == null || requestContext.getSubjectNameIdentifier() == null) {
138             throw new AttributeRequestException(
139                     "Unable to resolve principal, attribute requester ID and subject name identifier may not be null");
140         }
141         return attributeResolver.resolvePrincipalName(requestContext);
142     }
143 
144     /** {@inheritDoc} */
145     public AttributeDesignator getSAMLAttributeByAttributeID(String id) {
146         // TODO Auto-generated method stub
147         return null;
148     }
149 
150     /** {@inheritDoc} */
151     public Map<String, BaseAttribute> getAttributes(
152             SAMLProfileRequestContext<? extends SAMLObject, ? extends ResponseAbstractType, NameIdentifier, ? extends AbstractSAML1ProfileConfiguration> requestContext)
153             throws AttributeRequestException {
154         HashSet<String> requestedAttributes = new HashSet<String>();
155 
156         // get attributes from the message
157         Set<String> queryAttributeIds = getAttributeIds(requestContext.getInboundSAMLMessage());
158         requestedAttributes.addAll(queryAttributeIds);
159 
160         // get attributes from metadata
161         Set<String> metadataAttributeIds = getAttribtueIds(requestContext.getPeerEntityMetadata());
162         requestedAttributes.addAll(metadataAttributeIds);
163 
164         requestContext.setRequestedAttributes(requestedAttributes);
165 
166         Map<String, BaseAttribute> attributes = attributeResolver.resolveAttributes(requestContext);
167 
168         if (filteringEngine != null) {
169             attributes = filteringEngine.filterAttributes(attributes, requestContext);
170         }
171 
172         return attributes;
173     }
174 
175     /**
176      * Gets the attribute IDs for those attributes requested in the attribute query.
177      * 
178      * @param samlRequest the attribute query
179      * 
180      * @return attribute IDs for those attributes requested in the attribute query
181      */
182     protected Set<String> getAttributeIds(SAMLObject samlRequest) {
183         Set<String> queryAttributeIds = new HashSet<String>();
184         if (!(samlRequest instanceof AttributeQuery)) {
185             return queryAttributeIds;
186         }
187 
188         AttributeQuery query = (AttributeQuery) samlRequest;
189         if (query != null) {
190             List<AttributeDesignator> queryAttributes = query.getAttributeDesignators();
191             queryAttributeIds = getAttributeIds(queryAttributes);
192             log.debug("query message contains the following attributes: {}", queryAttributeIds);
193         }
194 
195         return queryAttributeIds;
196     }
197 
198     /**
199      * Gets the attribute IDs for those attributes requested in the entity metadata.
200      * 
201      * @param metadata the entity metadata
202      * 
203      * @return attribute IDs for those attributes requested in the entity metadata
204      */
205     protected Set<String> getAttribtueIds(EntityDescriptor metadata) {
206         Set<String> metadataAttributeIds = new HashSet<String>();
207         // TODO
208         return metadataAttributeIds;
209     }
210 
211     /**
212      * This parses the attribute ids from the supplied list of attributes.
213      * 
214      * @param attributes <code>List</code>
215      * @return <code>Set</code> of attribute ids
216      */
217     protected Set<String> getAttributeIds(List<AttributeDesignator> attributes) {
218         final Set<String> attributeIds = new HashSet<String>();
219         for (AttributeDesignator a : attributes) {
220             String attrId = getAttributeIDBySAMLAttribute(a);
221             attributeIds.add(attrId);
222         }
223         return attributeIds;
224     }
225 
226     /**
227      * This encodes the supplied attributes with that attribute's SAML1 encoder.
228      * 
229      * @param attributes shibboleth attributes to be encoded into SAML attributes
230      * 
231      * @return collection of encoded SAML attributes
232      */
233     @SuppressWarnings("unchecked")
234     protected Collection<Attribute> encodeAttributes(Collection<BaseAttribute> attributes) {
235         Collection<Attribute> encodedAttributes = new ArrayList<Attribute>();
236 
237         boolean attributeEncoded = false;
238 
239         for (BaseAttribute<?> shibbolethAttribute : attributes) {
240             if (shibbolethAttribute.getValues() == null || shibbolethAttribute.getValues().size() == 0) {
241                 continue;
242             }
243 
244             // first try to encode with an SAML 1 attribute encoders
245             Attribute attribute;
246             for (AttributeEncoder encoder : shibbolethAttribute.getEncoders()) {
247                 if (encoder instanceof SAML1AttributeEncoder) {
248                     try {
249                         attribute = (Attribute) encoder.encode(shibbolethAttribute);
250                         if (attribute != null) {
251                             encodedAttributes.add(attribute);
252                             attributeEncoded = true;
253                             if (log.isDebugEnabled()) {
254                                 log.debug("Encoded attribute {} with encoder of type {}", shibbolethAttribute.getId(),
255                                         encoder.getClass().getName());
256                             }
257                         }
258                     } catch (AttributeEncodingException e) {
259                         log.warn("Unable to encode attribute: {}", shibbolethAttribute.getId(), e);
260                     }
261                 }
262             }
263 
264             // if it couldn't be encoded log it
265             if (!attributeEncoded) {
266                 log.debug("Attribute {} was not encoded because no SAML1AttributeEncoder was attached to it.",
267                         shibbolethAttribute.getId());
268             }
269         }
270 
271         return encodedAttributes;
272     }
273 
274     /** {@inheritDoc} */
275     protected void onNewContextCreated(ApplicationContext newServiceContext) throws ServiceException {
276 
277     }
278 }