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.SAMLObject;
29 import org.opensaml.common.SAMLVersion;
30 import org.opensaml.common.binding.BindingException;
31 import org.opensaml.common.binding.MessageDecoder;
32 import org.opensaml.common.binding.MessageEncoder;
33 import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
34 import org.opensaml.saml2.core.Assertion;
35 import org.opensaml.saml2.core.Audience;
36 import org.opensaml.saml2.core.AudienceRestriction;
37 import org.opensaml.saml2.core.Conditions;
38 import org.opensaml.saml2.core.Issuer;
39 import org.opensaml.saml2.core.Response;
40 import org.opensaml.saml2.core.Status;
41 import org.opensaml.saml2.core.StatusCode;
42 import org.opensaml.saml2.core.StatusMessage;
43 import org.opensaml.saml2.core.Subject;
44 import org.opensaml.xml.XMLObjectBuilder;
45 import org.opensaml.xml.XMLObjectBuilderFactory;
47 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
50 * Common implementation details for profile handlers.
52 public abstract class AbstractSAML2ProfileHandler extends AbstractSAMLProfileHandler {
54 /** SAML Version for this profile handler. */
55 public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_20;
58 private static Logger log = Logger.getLogger(AbstractSAML2ProfileHandler.class);
60 /** For building XML. */
61 private XMLObjectBuilderFactory builderFactory;
63 /** For generating random ids. */
64 private IdentifierGenerator idGenerator;
66 /** Builder for Response elements. */
67 protected XMLObjectBuilder responseBuilder;
69 /** Builder for Status elements. */
70 private XMLObjectBuilder statusBuilder;
72 /** Builder for StatusCode elements. */
73 private XMLObjectBuilder statusCodeBuilder;
75 /** Builder for StatusMessage elements. */
76 private XMLObjectBuilder statusMessageBuilder;
78 /** Builder for Issuer elements. */
79 protected XMLObjectBuilder issuerBuilder;
82 * Default constructor.
84 public AbstractSAML2ProfileHandler() {
85 builderFactory = Configuration.getBuilderFactory();
86 idGenerator = new SecureRandomIdentifierGenerator();
88 responseBuilder = builderFactory.getBuilder(Response.DEFAULT_ELEMENT_NAME);
89 statusBuilder = builderFactory.getBuilder(Status.DEFAULT_ELEMENT_NAME);
90 statusCodeBuilder = builderFactory.getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
91 statusMessageBuilder = builderFactory.getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
92 issuerBuilder = builderFactory.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
96 * Returns the XML builder factory.
98 * @return Returns the builderFactory.
100 public XMLObjectBuilderFactory getBuilderFactory() {
101 return builderFactory;
105 * Returns the id generator.
107 * @return Returns the idGenerator.
109 public IdentifierGenerator getIdGenerator() {
114 * Build a status message, with an optional second-level failure message.
116 * @param topLevelCode The top-level status code. Should be from saml-core-2.0-os, sec. 3.2.2.2
117 * @param secondLevelCode An optional second-level failure code. Should be from saml-core-2.0-is, sec 3.2.2.2. If
118 * null, no second-level Status element will be set.
119 * @param secondLevelFailureMessage An optional second-level failure message.
121 * @return a Status object.
123 protected Status buildStatus(String topLevelCode, String secondLevelCode, String secondLevelFailureMessage) {
125 Status status = (Status) statusBuilder.buildObject(Status.DEFAULT_ELEMENT_NAME);
126 StatusCode statusCode = (StatusCode) statusCodeBuilder.buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
128 statusCode.setValue(topLevelCode);
129 if (secondLevelCode != null) {
130 StatusCode secondLevelStatusCode = (StatusCode) statusCodeBuilder
131 .buildObject(StatusCode.DEFAULT_ELEMENT_NAME);
132 secondLevelStatusCode.setValue(secondLevelCode);
133 statusCode.setStatusCode(secondLevelStatusCode);
136 if (secondLevelFailureMessage != null) {
137 StatusMessage msg = (StatusMessage) statusMessageBuilder.buildObject(StatusMessage.DEFAULT_ELEMENT_NAME);
138 msg.setMessage(secondLevelFailureMessage);
139 status.setMessage(msg);
146 * Build a SAML 2 Response element with basic fields populated.
148 * Failure handlers can send the returned response element to the RP. Success handlers should add the assertions
151 * @param inResponseTo The ID of the request this is in response to.
152 * @param issuer The URI of the RP issuing the response.
153 * @param status The response's status code.
155 * @return The populated Response object.
157 protected Response buildResponse(String inResponseTo, String issuer, final Status status) {
159 Response response = (Response) responseBuilder.buildObject(Response.DEFAULT_ELEMENT_NAME);
161 Issuer i = (Issuer) issuerBuilder.buildObject(Issuer.DEFAULT_ELEMENT_NAME);
164 response.setVersion(SAML_VERSION);
165 response.setId(getIdGenerator().generateIdentifier());
166 response.setInResponseto(inResponseTo);
167 response.setIssueInstance(new DateTime());
168 response.setIssuer(i);
169 response.setStatus(status);
174 protected Assertion buildAssertion(final Subject subject, final Conditions conditions, String issuer,
175 final String[] audiences) {
177 Assertion assertion = (Assertion) assertionBuilder.buildObject(Assertion.DEFAULT_ELEMENT_NAME);
178 assertion.setID(getIdGenerator().generateIdentifier());
179 assertion.setVersion(SAML_VERSION);
180 assertion.setIssueInstant(new DateTime());
181 assertion.setConditions(conditions);
182 assertion.setSubject(subject);
184 Issuer i = (Issuer) issuerBuilder.buildObject(Issuer.DEFAULT_ELEMENT_NAME);
186 assertion.setIssuer(i);
188 // if audiences were specified, set an AudienceRestriction condition
189 if (audiences != null && audiences.length > 0) {
191 Conditions conditions = assertion.getConditions();
192 List<AudienceRestriction> audienceRestrictionConditions = conditions.getAudienceRestrictions();
194 for (String audienceURI : audiences) {
196 Audience audience = (Audience) audienceBuilder.buildObject(Audience.DEFAULT_ELEMENT_NAME);
197 audience.setAudienceURI(audienceURI);
199 AudienceRestriction audienceRestriction = (AudienceRestriction) audienceRestrictionBuilder
200 .buildObject(AudienceRestriction.DEFAULT_ELEMENT_NAME);
201 List<Audience> audienceList = audienceRestriction.getAudiences();
202 audienceList.add(audience);
204 audienceRestrictionConditions.add(audienceRestriction);