View Javadoc

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