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