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.saml1;
19 import javax.servlet.ServletResponse;
21 import org.apache.log4j.Logger;
22 import org.opensaml.Configuration;
23 import org.opensaml.common.SAMLObjectBuilder;
24 import org.opensaml.common.SAMLVersion;
25 import org.opensaml.common.binding.BindingException;
26 import org.opensaml.common.binding.encoding.MessageEncoder;
27 import org.opensaml.common.impl.SAMLObjectContentReference;
28 import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
29 import org.opensaml.saml1.core.Assertion;
30 import org.opensaml.saml1.core.Status;
31 import org.opensaml.saml1.core.StatusCode;
32 import org.opensaml.saml1.core.StatusMessage;
33 import org.opensaml.saml1.core.Response;
34 import org.opensaml.saml2.metadata.AssertionConsumerService;
35 import org.opensaml.saml2.metadata.Endpoint;
36 import org.opensaml.saml2.metadata.RoleDescriptor;
37 import org.opensaml.saml2.metadata.provider.MetadataProvider;
38 import org.opensaml.xml.XMLObjectBuilder;
39 import org.opensaml.xml.XMLObjectBuilderFactory;
40 import org.opensaml.xml.security.credential.Credential;
41 import org.opensaml.xml.signature.Signature;
42 import org.opensaml.xml.signature.Signer;
44 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
45 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
46 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
47 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
48 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
52 * Common implementation details for profile handlers.
54 public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
56 /** SAML Version for this profile handler. */
57 public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
60 private static Logger log = Logger.getLogger(AbstractSAML1ProfileHandler.class);
62 /** For generating random ids. */
63 private SecureRandomIdentifierGenerator idGenerator;
65 /** Builder for Status objects. */
66 protected SAMLObjectBuilder<Status> statusBuilder;
68 /** Builder for StatusCode objects. */
69 protected SAMLObjectBuilder<StatusCode> statusCodeBuilder;
71 /** Builder for StatusMessage objects. */
72 protected SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
74 /** For building signature. */
75 private XMLObjectBuilder<Signature> signatureBuilder;
78 * Default constructor.
80 public AbstractSAML1ProfileHandler() {
81 idGenerator = new SecureRandomIdentifierGenerator();
83 statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
84 statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
85 statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
86 signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
90 * Returns the id generator.
92 * @return Returns the idGenerator.
94 public SecureRandomIdentifierGenerator getIdGenerator() {
99 * Build a SAML 1 Status element.
101 * @param statusCode The status code - see oasis-sstc-saml-core-1.1, section 3.4.3.1.
102 * @param statusMessage The status message, or <code>null</code> if none is to be set.
104 * @return The Status object, or <code>null</code> on error.
106 protected Status buildStatus(String statusCode, String statusMessage) {
108 if (statusCode == null || statusCode.equals("")) {
112 Status status = statusBuilder.buildObject();
113 StatusCode sc = statusCodeBuilder.buildObject();
114 sc.setValue(statusCode);
115 status.setStatusCode(sc);
117 if (statusMessage != null || !(statusMessage.equals(""))) {
119 StatusMessage sm = statusMessageBuilder.buildObject();
120 sm.setMessage(statusMessage);
121 status.setStatusMessage(sm);
128 * Signs the given assertion if either the current profile configuration or the relying party configuration contains
129 * signing credentials.
131 * @param assertion assertion to sign
132 * @param rpConfig relying party configuration
133 * @param profileConfig current profile configuration
135 protected void signAssertion(Assertion assertion, RelyingPartyConfiguration rpConfig,
136 AbstractSAML1ProfileConfiguration profileConfig) {
137 if (!profileConfig.getSignAssertions()) {
141 Credential signatureCredential = profileConfig.getSigningCredential();
142 if (signatureCredential == null) {
143 signatureCredential = rpConfig.getDefaultSigningCredential();
146 if (signatureCredential == null) {
150 SAMLObjectContentReference contentRef = new SAMLObjectContentReference(assertion);
151 Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
152 signature.getContentReferences().add(contentRef);
153 assertion.setSignature(signature);
155 Signer.signObject(signature);
159 * Encode a SAML Response.
161 * @param binding The SAML protocol binding to use.
162 * @param profileResponse The Raw output stream to send the message to.
163 * @param samlResponse The SAML Response to send.
164 * @param relyingParty The relying party to send the message to.
165 * @param roleDescriptor The role of the message sender.
166 * @param endpoint The endpoint to which the message should be send.
168 * @throws ProfileException On error.
170 protected void encodeResponse(String binding,final ProfileResponse<ServletResponse> profileResponse,
171 final Response samlResponse, final RelyingPartyConfiguration relyingParty,
172 final RoleDescriptor roleDescriptor, final Endpoint endpoint) throws ProfileException {
174 MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(binding);
175 if (encoder == null) {
176 log.error("No MessageEncoder registered for " + binding);
177 throw new ProfileException("No MessageEncoder registered for " + binding);
180 encoder.setResponse(profileResponse.getRawResponse());
181 encoder.setIssuer(relyingParty.getProviderId());
182 encoder.setMetadataProvider(getRelyingPartyConfigurationManager().getMetadataProvider());
183 encoder.setRelyingPartyRole(roleDescriptor);
184 encoder.setSigningCredential(relyingParty.getDefaultSigningCredential());
185 encoder.setSamlMessage(samlResponse);
186 encoder.setRelyingPartyEndpoint(endpoint);
190 } catch (BindingException ex) {
191 log.error("Unable to encode response the relying party: " + relyingParty.getRelyingPartyId(), ex);
192 throw new ProfileException("Unable to encode response the relying party: "
193 + relyingParty.getRelyingPartyId(), ex);