2 * Copyright [2006] [University Corporation for Advanced Internet Development, Inc.]
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package edu.internet2.middleware.shibboleth.idp.profile.saml2;
19 import org.apache.log4j.Logger;
20 import org.opensaml.common.SAMLObjectBuilder;
21 import org.opensaml.saml2.core.Advice;
22 import org.opensaml.saml2.core.Assertion;
23 import org.opensaml.saml2.core.Audience;
24 import org.opensaml.saml2.core.AudienceRestriction;
25 import org.opensaml.saml2.core.Conditions;
26 import org.opensaml.saml2.core.Issuer;
27 import org.opensaml.saml2.core.ProxyRestriction;
28 import org.opensaml.saml2.core.Response;
29 import org.opensaml.saml2.core.Status;
30 import org.opensaml.saml2.core.StatusCode;
31 import org.opensaml.saml2.core.Subject;
32 import org.opensaml.saml2.encryption.Encrypter;
33 import org.opensaml.saml2.metadata.provider.MetadataProvider;
34 import org.opensaml.xml.XMLObjectBuilder;
35 import org.opensaml.xml.encryption.EncryptionException;
36 import org.opensaml.xml.signature.Signature;
37 import org.opensaml.xml.signature.Signer;
39 import edu.internet2.middleware.shibboleth.common.attribute.SAML2AttributeAuthority;
40 import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethAttributeRequestContext;
41 import edu.internet2.middleware.shibboleth.common.attribute.provider.ShibbolethSAML2AttributeAuthority;
42 import edu.internet2.middleware.shibboleth.common.attribute.resolver.AttributeResolver;
43 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
44 import edu.internet2.middleware.shibboleth.common.relyingparty.saml2.AttributeQueryConfiguration;
47 * SAML 2.0 Attribute Query profile handler.
49 public abstract class AbstractAttributeQuery extends AbstractSAML2ProfileHandler {
52 private static Logger log = Logger.getLogger(AbstractAttributeQuery.class);
54 /** For building response. */
55 private SAMLObjectBuilder<Response> responseBuilder;
57 /** For building status. */
58 private SAMLObjectBuilder<Status> statusBuilder;
60 /** For building statuscode. */
61 private SAMLObjectBuilder<StatusCode> statusCodeBuilder;
63 /** For building assertion. */
64 private SAMLObjectBuilder<Assertion> assertionBuilder;
66 /** For building issuer. */
67 private SAMLObjectBuilder<Issuer> issuerBuilder;
69 /** For building subject. */
70 private SAMLObjectBuilder<Subject> subjectBuilder;
72 /** For building conditions. */
73 private SAMLObjectBuilder<Conditions> conditionsBuilder;
75 /** For building audience restriction. */
76 private SAMLObjectBuilder<AudienceRestriction> audienceRestrictionBuilder;
78 /** For building audience. */
79 private SAMLObjectBuilder<Audience> audienceBuilder;
81 /** For building advice. */
82 private SAMLObjectBuilder<Advice> adviceBuilder;
84 /** For building signature. */
85 private XMLObjectBuilder<Signature> signatureBuilder;
87 /** Attribute authority. */
88 private SAML2AttributeAuthority attributeAuthority;
91 * This creates a new attribute query.
93 * @param ar <code>AttributeResolver</code>
95 public AbstractAttributeQuery(AttributeResolver<ShibbolethAttributeRequestContext> ar) {
96 // instantiate attribute authority
97 attributeAuthority = new ShibbolethSAML2AttributeAuthority(ar);
99 // instantiate XML builders
100 responseBuilder = (SAMLObjectBuilder<Response>) getBuilderFactory().getBuilder(Response.DEFAULT_ELEMENT_NAME);
101 statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
102 statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(
103 StatusCode.DEFAULT_ELEMENT_NAME);
104 issuerBuilder = (SAMLObjectBuilder<Issuer>) getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
105 assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
106 .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
107 subjectBuilder = (SAMLObjectBuilder<Subject>) getBuilderFactory().getBuilder(Subject.DEFAULT_ELEMENT_NAME);
108 conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory().getBuilder(
109 Conditions.DEFAULT_ELEMENT_NAME);
110 audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) getBuilderFactory().getBuilder(
111 AudienceRestriction.DEFAULT_ELEMENT_NAME);
112 audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory().getBuilder(Audience.DEFAULT_ELEMENT_NAME);
113 adviceBuilder = (SAMLObjectBuilder<Advice>) getBuilderFactory().getBuilder(Advice.DEFAULT_ELEMENT_NAME);
114 signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
118 * This returns the <code>RelyingPartyConfiguration</code> for the supplied provider id.
120 * @param providerId <code>String</code>
121 * @return <code>RelyingPartyConfiguration</code>
123 protected RelyingPartyConfiguration getRelyingPartyConfiguration(String providerId) {
124 return getRelyingPartyConfigurationManager().getRelyingPartyConfiguration(providerId);
128 * This returns the <code>AttributeQueryConfiguration</code> for the supplied provider id.
130 * @param providerId <code>String</code>
131 * @return <code>AttributeQueryConfiguration</code>
133 protected AttributeQueryConfiguration getAttributeQueryConfiguration(String providerId) {
134 return (AttributeQueryConfiguration) getRelyingPartyConfiguration(providerId).getProfileConfigurations().get(
135 AttributeQueryConfiguration.PROFILE_ID);
139 * This returns the <code>MetadataProvider</code> for this attribute query.
141 * @return <code>MetadataProvider</code>
143 protected MetadataProvider getMetadataProvider() {
144 return getRelyingPartyConfigurationManager().getMetadataProvider();
148 * This returns the <code>AttributeAuthority</code> for this attribute query.
150 * @return <code>SAML2AttributeAuthority</code>
152 protected SAML2AttributeAuthority getAttributeAuthority() {
153 return attributeAuthority;
157 * This builds the response for this SAML request.
159 * @param responseContext <code>ProfileResponseContext</code>
160 * @param issuer <code>String</code>
161 * @param destination <code>String</code>
162 * @return <code>Response</code>
163 * @throws EncryptionException if an error occurs attempting to encrypt data
165 protected Response buildResponse(ProfileResponseContext responseContext, String issuer, String destination)
166 throws EncryptionException {
167 AttributeQueryConfiguration config = getAttributeQueryConfiguration(responseContext.getProviderId());
170 * required: samlp:Status, ID, Version, IssueInstant
172 Response response = responseBuilder.buildObject();
173 response.setVersion(SAML_VERSION);
174 response.setID(getIdGenerator().generateIdentifier());
175 response.setInResponseTo(issuer);
176 response.setIssueInstant(responseContext.getIssueInstant());
177 response.setDestination(destination);
179 response.setIssuer(buildIssuer(responseContext.getProviderId()));
182 * Will be hard coded in the future: if (consent != null) { response.setConsent(consent); }
187 * No extensions currently exist, will be hardcorded in the future: if (extensions != null) {
188 * response.setExtensions(extensions); }
192 if (config.getSignAssertions()) {
193 Signature s = buildSignature();
194 s.setSigningKey(config.getSigningCredential().getPrivateKey());
195 if (config.getEncryptAssertion()) {
196 // TODO load encryption parameters
197 Encrypter encrypter = null;
198 Assertion a = buildAssertion(responseContext);
200 Signer.signObject(s);
201 response.getEncryptedAssertions().add(encrypter.encrypt(a));
203 Assertion a = buildAssertion(responseContext);
205 Signer.signObject(s);
206 response.getAssertions().add(a);
209 if (config.getEncryptAssertion()) {
210 // TODO load encryption parameters
211 Encrypter encrypter = null;
212 response.getEncryptedAssertions().add(encrypter.encrypt(buildAssertion(responseContext)));
214 response.getAssertions().add(buildAssertion(responseContext));
217 response.setStatus(buildStatus(StatusCode.SUCCESS_URI));
222 * This builds the status response for this SAML request.
224 * @param statusCodeUri <code>String</code> to set
225 * @return <code>Status</code>
227 private Status buildStatus(String statusCodeUri) {
228 Status status = statusBuilder.buildObject();
229 StatusCode statusCode = statusCodeBuilder.buildObject();
230 statusCode.setValue(statusCodeUri);
231 status.setStatusCode(statusCode);
236 * This builds the assertion for this SAML request.
238 * @param responseContext <code>ProfileResponseContext</code>
239 * @return <code>Assertion</code>
240 * @throws EncryptionException if an error occurs attempting to encrypt data
242 private Assertion buildAssertion(ProfileResponseContext responseContext) throws EncryptionException {
243 AttributeQueryConfiguration config = getAttributeQueryConfiguration(responseContext.getProviderId());
246 * required: saml:Issuer, ID, Version, IssueInstant
248 Assertion assertion = assertionBuilder.buildObject();
249 assertion.setID(getIdGenerator().generateIdentifier());
250 assertion.setIssueInstant(responseContext.getIssueInstant());
251 assertion.setVersion(SAML_VERSION);
252 assertion.setIssuer(buildIssuer(responseContext.getProviderId()));
255 assertion.setSubject(buildSubject(responseContext.getMessage().getSubject(), config.getEncryptNameID()));
257 assertion.setConditions(buildConditions(responseContext));
259 assertion.setAdvice(buildAdvice());
260 // add attribute statement
261 assertion.getAttributeStatements().add(responseContext.getAttributeStatement());
266 * This builds the issuer response for this SAML request.
268 * @param providerId <code>String</code>
269 * @return <code>Issuer</code>
271 private Issuer buildIssuer(String providerId) {
272 RelyingPartyConfiguration relyingPartyConfiguration = getRelyingPartyConfiguration(providerId);
273 Issuer issuer = issuerBuilder.buildObject();
274 issuer.setValue(relyingPartyConfiguration.getProviderId());
279 * This builds the subject for this SAML request.
281 * @param messageSubject <code>Subject</code>
282 * @param encryptNameId <code>boolean</code>
283 * @return <code>Subject</code>
284 * @throws EncryptionException if encryption of the name id fails
286 private Subject buildSubject(Subject messageSubject, boolean encryptNameId) throws EncryptionException {
287 Subject subject = subjectBuilder.buildObject();
289 // TODO load encryption parameters
290 Encrypter encrypter = null;
291 subject.setEncryptedID(encrypter.encrypt(messageSubject.getNameID()));
293 subject.setNameID(messageSubject.getNameID());
294 // TODO when is subject.setBaseID(newBaseID) called, if ever?
300 * This builds the conditions for this SAML request.
302 * @param responseContext <code>ProfileResponseContext</code>
303 * @return <code>Conditions</code>
305 private Conditions buildConditions(ProfileResponseContext responseContext) {
306 AttributeQueryConfiguration config = getAttributeQueryConfiguration(responseContext.getProviderId());
308 Conditions conditions = conditionsBuilder.buildObject();
309 conditions.setNotBefore(responseContext.getIssueInstant());
310 conditions.setNotOnOrAfter(responseContext.getIssueInstant().plus(config.getAssertionLifetime()));
312 // add audience restrictions
313 AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject();
314 for (String s : config.getAssertionAudiences()) {
315 Audience audience = audienceBuilder.buildObject();
316 audience.setAudienceURI(s);
317 audienceRestriction.getAudiences().add(audience);
319 conditions.getAudienceRestrictions().add(audienceRestriction);
321 // add proxy restrictions
322 ProxyRestriction proxyRestriction = conditions.getProxyRestriction();
323 for (String s : config.getProxyAudiences()) {
324 Audience audience = audienceBuilder.buildObject();
325 audience.setAudienceURI(s);
326 proxyRestriction.getAudiences().add(audience);
328 proxyRestriction.setProxyCount(new Integer(config.getProxyCount()));
331 * OneTimeUse and additional conditions not supported yet
338 * This builds the advice for this SAML request.
340 * @return <code>Advice</code>
342 private Advice buildAdvice() {
344 * Advice not supported at this time
346 Advice advice = adviceBuilder.buildObject();
351 * This builds a signature for this SAML request.
353 * @return <code>Signature</code>
355 private Signature buildSignature() {
356 Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);