1
2
3
4
5
6
7
8
9
10
11
12
13
14
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.SAMLObjectBuilder;
28 import org.opensaml.common.xml.SAMLConstants;
29 import org.opensaml.saml2.core.Attribute;
30 import org.opensaml.saml2.core.AttributeQuery;
31 import org.opensaml.saml2.core.AttributeStatement;
32 import org.opensaml.saml2.core.NameID;
33 import org.opensaml.saml2.core.RequestAbstractType;
34 import org.opensaml.saml2.core.StatusResponseType;
35 import org.opensaml.saml2.metadata.AttributeAuthorityDescriptor;
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.SAML2AttributeEncoder;
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.saml2.AbstractSAML2ProfileConfiguration;
52 import edu.internet2.middleware.shibboleth.common.service.ServiceException;
53
54
55
56
57 public class ShibbolethSAML2AttributeAuthority extends BaseService implements SAML2AttributeAuthority {
58
59
60 private final Logger log = LoggerFactory.getLogger(ShibbolethSAML2AttributeAuthority.class);
61
62
63 private SAMLObjectBuilder<AttributeStatement> statementBuilder;
64
65
66 private ShibbolethAttributeResolver attributeResolver;
67
68
69 private ShibbolethAttributeFilteringEngine filteringEngine;
70
71
72
73
74
75
76 @SuppressWarnings("unchecked")
77 public ShibbolethSAML2AttributeAuthority(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
88
89
90
91 public ShibbolethAttributeResolver getAttributeResolver() {
92 return attributeResolver;
93 }
94
95
96
97
98
99
100 public ShibbolethAttributeFilteringEngine getFilteringEngine() {
101 return filteringEngine;
102 }
103
104
105
106
107
108
109 public void setFilteringEngine(ShibbolethAttributeFilteringEngine engine) {
110 filteringEngine = engine;
111 }
112
113
114 public AttributeStatement buildAttributeStatement(AttributeQuery query, Collection<BaseAttribute> attributes)
115 throws AttributeEncodingException {
116
117 Collection<Attribute> encodedAttributes = encodeAttributes(attributes);
118
119 filterAttributesByValue(query, encodedAttributes);
120
121 if (!encodedAttributes.isEmpty()) {
122 AttributeStatement statement = statementBuilder.buildObject();
123 List<org.opensaml.saml2.core.Attribute> samlAttributes = statement.getAttributes();
124 samlAttributes.addAll(encodedAttributes);
125 return statement;
126 } else {
127 log.debug("No attributes remained after encoding and filtering by value, no attribute statement built");
128 return null;
129 }
130 }
131
132
133 public String getAttributeIDBySAMLAttribute(Attribute attribute) {
134
135 return null;
136 }
137
138
139 public Attribute getSAMLAttributeByAttributeID(String id) {
140
141 return null;
142 }
143
144
145 public String getPrincipal(
146 SAMLProfileRequestContext<? extends RequestAbstractType, ? extends StatusResponseType, NameID, ? extends AbstractSAML2ProfileConfiguration> requestContext)
147 throws AttributeRequestException {
148 if (requestContext.getInboundMessageIssuer() == null || requestContext.getSubjectNameIdentifier() == null) {
149 throw new AttributeRequestException(
150 "Unable to resolve principal, attribute request ID and subject name identifier may not be null");
151 }
152
153 return attributeResolver.resolvePrincipalName(requestContext);
154 }
155
156
157 public Map<String, BaseAttribute> getAttributes(
158 SAMLProfileRequestContext<? extends RequestAbstractType, ? extends StatusResponseType, NameID, ? extends AbstractSAML2ProfileConfiguration> requestContext)
159 throws AttributeRequestException {
160 HashSet<String> requestedAttributes = new HashSet<String>();
161
162
163 Set<String> queryAttributeIds = getAttributeIds(requestContext.getInboundSAMLMessage());
164 requestedAttributes.addAll(queryAttributeIds);
165
166
167 Set<String> metadataAttributeIds = getAttribtueIds(requestContext.getPeerEntityMetadata());
168 requestedAttributes.addAll(metadataAttributeIds);
169
170 requestContext.setRequestedAttributes(requestedAttributes);
171
172
173 Map<String, BaseAttribute> attributes = attributeResolver.resolveAttributes(requestContext);
174
175
176 if (filteringEngine != null) {
177 attributes = filteringEngine.filterAttributes(attributes, requestContext);
178 }
179
180 return attributes;
181 }
182
183
184
185
186
187
188
189
190
191
192 @SuppressWarnings("unchecked")
193 protected Collection<Attribute> encodeAttributes(Collection<BaseAttribute> attributes)
194 throws AttributeEncodingException {
195 Collection<Attribute> encodedAttributes = new ArrayList<Attribute>();
196
197 boolean attributeEncoded;
198
199 for (BaseAttribute<?> shibbolethAttribute : attributes) {
200 attributeEncoded = false;
201
202 if (shibbolethAttribute.getValues() == null || shibbolethAttribute.getValues().size() == 0) {
203 continue;
204 }
205
206 Attribute attribute;
207 for (AttributeEncoder encoder : shibbolethAttribute.getEncoders()) {
208 if (encoder instanceof SAML2AttributeEncoder) {
209 try {
210 attribute = (Attribute) encoder.encode(shibbolethAttribute);
211 if (attribute != null) {
212 encodedAttributes.add(attribute);
213 attributeEncoded = true;
214 log.debug("Encoded attribute {} with encoder of type {}", shibbolethAttribute.getId(),
215 encoder.getClass().getName());
216 }
217 } catch (AttributeEncodingException e) {
218 log.warn("unable to encode attribute: " + shibbolethAttribute.getId(), e);
219 }
220 }
221 }
222
223
224 if (!attributeEncoded) {
225 log.debug("Attribute {} was not encoded because no SAML2AttributeEncoder was attached to it.",
226 shibbolethAttribute.getId());
227 }
228 }
229
230 return encodedAttributes;
231 }
232
233
234
235
236
237
238
239
240
241
242 protected void filterAttributesByValue(AttributeQuery query, Collection<Attribute> attributes) {
243 if (query == null) {
244 return;
245 }
246
247
248 }
249
250
251
252
253
254
255
256
257 protected Set<String> getAttributeIds(RequestAbstractType samlRequest) {
258 Set<String> queryAttributeIds = new HashSet<String>();
259 if (!(samlRequest instanceof AttributeQuery)) {
260 return queryAttributeIds;
261 }
262
263 AttributeQuery query = (AttributeQuery) samlRequest;
264 if (query != null) {
265 List<org.opensaml.saml2.core.Attribute> queryAttributes = query.getAttributes();
266 queryAttributeIds = getAttributeIds(queryAttributes);
267 log.debug("query message contains the following attributes: {}", queryAttributeIds);
268 }
269
270 return queryAttributeIds;
271 }
272
273
274
275
276
277
278
279
280 protected Set<String> getAttribtueIds(EntityDescriptor metadata) {
281 Set<String> metadataAttributeIds = new HashSet<String>();
282 AttributeAuthorityDescriptor aaDescriptor;
283 if (metadata != null) {
284 aaDescriptor = metadata.getAttributeAuthorityDescriptor(SAMLConstants.SAML20P_NS);
285 if (aaDescriptor != null) {
286 List<org.opensaml.saml2.core.Attribute> metadataAttributes = aaDescriptor.getAttributes();
287 metadataAttributeIds = getAttributeIds(metadataAttributes);
288 log.debug("metadata contains the following attributes: {}", metadataAttributeIds);
289 }
290 }
291
292 return metadataAttributeIds;
293 }
294
295
296
297
298
299
300
301 protected Set<String> getAttributeIds(List<org.opensaml.saml2.core.Attribute> attributes) {
302 final Set<String> attributeIds = new HashSet<String>();
303 for (org.opensaml.saml2.core.Attribute a : attributes) {
304 String attrId = getAttributeIDBySAMLAttribute(a);
305 if (attrId != null) {
306 attributeIds.add(attrId);
307 }
308 }
309 return attributeIds;
310 }
311
312
313 protected void onNewContextCreated(ApplicationContext newServiceContext) throws ServiceException {
314
315 }
316 }