2 * Copyright [2007] [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 java.util.List;
21 import javax.servlet.ServletRequest;
22 import javax.servlet.ServletResponse;
24 import org.apache.log4j.Logger;
25 import org.joda.time.DateTime;
26 import org.opensaml.Configuration;
27 import org.opensaml.common.IdentifierGenerator;
28 import org.opensaml.common.SAMLObjectBuilder;
29 import org.opensaml.common.SAMLVersion;
30 import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
31 import org.opensaml.saml2.core.AuthnContext;
32 import org.opensaml.saml2.core.AuthnContextClassRef;
33 import org.opensaml.saml2.core.AuthnContextDeclRef;
34 import org.opensaml.saml2.core.AuthnStatement;
35 import org.opensaml.saml2.core.Assertion;
36 import org.opensaml.saml2.core.Audience;
37 import org.opensaml.saml2.core.AudienceRestriction;
38 import org.opensaml.saml2.core.AuthnStatement;
39 import org.opensaml.saml2.core.Conditions;
40 import org.opensaml.saml2.core.Issuer;
41 import org.opensaml.saml2.core.Response;
42 import org.opensaml.saml2.core.Status;
43 import org.opensaml.saml2.core.StatusCode;
44 import org.opensaml.saml2.core.StatusMessage;
45 import org.opensaml.saml2.core.Subject;
46 import org.opensaml.xml.XMLObjectBuilderFactory;
48 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
51 * Common implementation details for profile handlers.
53 public abstract class AbstractSAML2ProfileHandler extends
54 AbstractSAMLProfileHandler {
56 /** SAML Version for this profile handler. */
57 public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
59 /** URI for the SAML 2 protocol. */
60 public static final String SAML20_PROTOCOL_URI = "urn:oasis:names:tc:SAML:2.0:protocol";
63 private static Logger log = Logger
64 .getLogger(AbstractSAML2ProfileHandler.class);
66 /** For building XML. */
67 private XMLObjectBuilderFactory builderFactory;
69 /** For generating random ids. */
70 private IdentifierGenerator idGenerator;
72 /** Builder for Response elements. */
73 protected SAMLObjectBuilder<Response> responseBuilder;
75 /** Builder for Status elements. */
76 protected SAMLObjectBuilder<Status> statusBuilder;
78 /** Builder for StatusCode elements. */
79 protected SAMLObjectBuilder<StatusCode> statusCodeBuilder;
81 /** Builder for StatusMessage elements. */
82 protected SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
84 /** Builder for Issuer elements. */
85 protected SAMLObjectBuilder<Issuer> issuerBuilder;
87 /** Builder for Assertion elements. */
88 protected SAMLObjectBuilder<Assertion> assertionBuilder;
90 /** Builder for Condition elements. */
91 protected SAMLObjectBuilder<Conditions> conditionsBuilder;
93 /** Builder for AuthnStatement elements. */
94 protected SAMLObjectBuilder<AuthnStatement> authnStatementBuilder;
96 /** Builder for AuthnContext elements. */
97 protected SAMLObjectBuilder<AuthnContext> authnContextBuilder;
99 /** Builder for AuthnContextClassRef elements. */
100 protected SAMLObjectBuilder<AuthnContextClassRef> authnContextClassRefBuilder;
102 /** Builder for AuthnContextDeclRef elements. */
103 protected SAMLObjectBuilder<AuthnContextDeclRef> authnContextDeclRefBuilder;
105 /** Builder for AudienceRestriction conditions. */
106 protected SAMLObjectBuilder<AudienceRestriction> audienceRestrictionBuilder;
108 /** Builder for Audience elemenets. */
109 protected SAMLObjectBuilder<Audience> audienceBuilder;
112 * Default constructor.
114 public AbstractSAML2ProfileHandler() {
115 builderFactory = Configuration.getBuilderFactory();
116 idGenerator = new SecureRandomIdentifierGenerator();
118 assertionBuilder = (SAMLObjectBuilder<Assertion>) getBuilderFactory()
119 .getBuilder(Assertion.DEFAULT_ELEMENT_NAME);
120 authnStatementBuilder = (SAMLObjectBuilder<AuthnStatement>) getBuilderFactory()
121 .getBuilder(AuthnStatement.DEFAULT_ELEMENT_NAME);
122 authnContextBuilder = (SAMLObjectBuilder<AuthnContext>) getBuilderFactory()
123 .getBuilder(AuthnContext.DEFAULT_ELEMENT_NAME);
124 authnContextClassRefBuilder = (SAMLObjectBuilder<AuthnContextClassRef>) getBuilderFactory()
125 .getBuilder(AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
126 authnContextDeclRefBuilder = (SAMLObjectBuilder<AuthnContextDeclRef>) getBuilderFactory()
127 .getBuilder(AuthnContextDeclRef.DEFAULT_ELEMENT_NAME);
128 audienceRestrictionBuilder = (SAMLObjectBuilder<AudienceRestriction>) getBuilderFactory()
129 .getBuilder(AudienceRestriction.DEFAULT_ELEMENT_NAME);
130 audienceBuilder = (SAMLObjectBuilder<Audience>) getBuilderFactory()
131 .getBuilder(Audience.DEFAULT_ELEMENT_NAME);
132 conditionsBuilder = (SAMLObjectBuilder<Conditions>) getBuilderFactory()
133 .getBuilder(Conditions.DEFAULT_ELEMENT_NAME);
134 responseBuilder = (SAMLObjectBuilder<Response>) builderFactory
135 .getBuilder(Response.DEFAULT_ELEMENT_NAME);
136 statusBuilder = (SAMLObjectBuilder<Status>) builderFactory
137 .getBuilder(Status.DEFAULT_ELEMENT_NAME);
138 statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) builderFactory
139 .getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
140 statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) builderFactory
141 .getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
142 issuerBuilder = (SAMLObjectBuilder<Issuer>) builderFactory
143 .getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
147 * Returns the XML builder factory.
149 * @return Returns the builderFactory.
151 public XMLObjectBuilderFactory getBuilderFactory() {
152 return builderFactory;
156 * Returns the id generator.
158 * @return Returns the idGenerator.
160 public IdentifierGenerator getIdGenerator() {
165 * Build a status message, with an optional second-level failure message.
167 * @param topLevelCode
168 * The top-level status code. Should be from saml-core-2.0-os,
170 * @param secondLevelCode
171 * An optional second-level failure code. Should be from
172 * saml-core-2.0-is, sec 3.2.2.2. If null, no second-level Status
173 * element will be set.
174 * @param secondLevelFailureMessage
175 * An optional second-level failure message.
177 * @return a Status object.
179 protected Status buildStatus(String topLevelCode, String secondLevelCode,
180 String secondLevelFailureMessage) {
182 Status status = statusBuilder.buildObject();
183 StatusCode statusCode = statusCodeBuilder.buildObject();
185 statusCode.setValue(topLevelCode);
186 if (secondLevelCode != null) {
187 StatusCode secondLevelStatusCode = statusCodeBuilder.buildObject();
188 secondLevelStatusCode.setValue(secondLevelCode);
189 statusCode.setStatusCode(secondLevelStatusCode);
192 if (secondLevelFailureMessage != null) {
193 StatusMessage msg = statusMessageBuilder.buildObject();
194 msg.setMessage(secondLevelFailureMessage);
195 status.setStatusMessage(msg);
202 * Build a status message, with an optional second-level failure message.
204 * @param topLevelCode
205 * The top-level status code. Should be from saml-core-2.0-os,
207 * @param secondLevelCode
208 * An optional second-level failure code. Should be from
209 * saml-core-2.0-is, sec 3.2.2.2. If null, no second-level Status
210 * element will be set.
212 * @return a Status object.
214 protected Status buildStatus(String topLevelCode,
215 final StatusCode secondLevelCode) {
217 Status status = statusBuilder.buildObject();
218 StatusCode statusCode = statusCodeBuilder.buildObject();
220 statusCode.setValue(topLevelCode);
221 if (secondLevelCode != null) {
222 statusCode.setStatusCode(secondLevelCode);
229 * Build a StatusCode.
232 * The URI status code.
234 * The message; may be <code>null</code.
236 * @return a StatusCode object.
238 protected StatusCode buildStatusCode(String statusCode) {
243 * Build a SAML 2 Response element with basic fields populated.
245 * Failure handlers can send the returned response element to the RP.
246 * Success handlers should add the assertions before sending it.
248 * @param inResponseTo
249 * The ID of the request this is in response to.
250 * @param issueInstant
251 * The timestamp of this response.
253 * The URI of the RP issuing the response.
255 * The response's status code.
257 * @return The populated Response object.
259 protected Response buildResponse(String inResponseTo,
260 final DateTime issueInstant, String issuer, final Status status) {
262 Response response = responseBuilder.buildObject();
264 Issuer i = issuerBuilder.buildObject();
267 response.setVersion(SAML_VERSION);
268 response.setID(getIdGenerator().generateIdentifier());
269 response.setInResponseTo(inResponseTo);
270 response.setIssueInstant(issueInstant);
271 response.setIssuer(i);
272 response.setStatus(status);
278 * Build a skeletal SAML 2 assertion.
280 * Note, the caller may either set the audiences in the conditions argument,
281 * or pass a list of URIs to this method. If the latter option is chosen,
282 * this method will create the appropriate AudienceRestriction element.
285 * The Subject of the assertion.
287 * The conditions object.
289 * The URI of the RP issuing the assertion.
291 * A possibly null array of audience URIs for the assertion.
293 * @return The assertion object.
295 protected Assertion buildAssertion(final Subject subject,
296 final Conditions conditions, final Issuer issuer,
297 final String[] audiences) {
299 Assertion assertion = assertionBuilder.buildObject();
300 assertion.setID(getIdGenerator().generateIdentifier());
301 assertion.setVersion(SAML_VERSION);
302 assertion.setIssueInstant(new DateTime());
303 assertion.setConditions(conditions);
304 assertion.setSubject(subject);
306 Issuer i = issuerBuilder.buildObject();
307 i.setValue(issuer.getValue());
308 assertion.setIssuer(i);
310 // if audiences were specified, set an AudienceRestriction condition
311 if (audiences != null && audiences.length > 0) {
313 List<AudienceRestriction> audienceRestrictionConditions = assertion
314 .getConditions().getAudienceRestrictions();
316 AudienceRestriction audienceRestriction = audienceRestrictionBuilder
318 audienceRestrictionConditions.add(audienceRestriction);
320 List<Audience> audienceList = audienceRestriction.getAudiences();
322 for (String audienceURI : audiences) {
323 Audience audience = audienceBuilder.buildObject();
324 audience.setAudienceURI(audienceURI);
325 audienceList.add(audience);