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 java.security.NoSuchAlgorithmException;
21 import javax.servlet.ServletResponse;
23 import org.apache.log4j.Logger;
24 import org.opensaml.common.SAMLObjectBuilder;
25 import org.opensaml.common.SAMLVersion;
26 import org.opensaml.common.binding.BindingException;
27 import org.opensaml.common.binding.encoding.MessageEncoder;
28 import org.opensaml.common.impl.SAMLObjectContentReference;
29 import org.opensaml.saml1.core.Assertion;
30 import org.opensaml.saml1.core.Response;
31 import org.opensaml.saml1.core.Status;
32 import org.opensaml.saml1.core.StatusCode;
33 import org.opensaml.saml1.core.StatusMessage;
34 import org.opensaml.saml2.metadata.Endpoint;
35 import org.opensaml.saml2.metadata.RoleDescriptor;
36 import org.opensaml.xml.XMLObjectBuilder;
37 import org.opensaml.xml.security.credential.Credential;
38 import org.opensaml.xml.signature.Signature;
39 import org.opensaml.xml.signature.Signer;
41 import edu.internet2.middleware.shibboleth.common.profile.ProfileException;
42 import edu.internet2.middleware.shibboleth.common.profile.ProfileResponse;
43 import edu.internet2.middleware.shibboleth.common.relyingparty.RelyingPartyConfiguration;
44 import edu.internet2.middleware.shibboleth.common.relyingparty.provider.saml1.AbstractSAML1ProfileConfiguration;
45 import edu.internet2.middleware.shibboleth.idp.profile.AbstractSAMLProfileHandler;
49 * Common implementation details for profile handlers.
51 public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
53 /** SAML Version for this profile handler. */
54 public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
57 private static Logger log = Logger.getLogger(AbstractSAML1ProfileHandler.class);
59 /** Builder for Status objects. */
60 protected SAMLObjectBuilder<Status> statusBuilder;
62 /** Builder for StatusCode objects. */
63 protected SAMLObjectBuilder<StatusCode> statusCodeBuilder;
65 /** Builder for StatusMessage objects. */
66 protected SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
68 /** For building signature. */
69 private XMLObjectBuilder<Signature> signatureBuilder;
72 * Default constructor.
74 @SuppressWarnings("unchecked")
75 public AbstractSAML1ProfileHandler(){
77 statusBuilder = (SAMLObjectBuilder<Status>) getBuilderFactory().getBuilder(Status.DEFAULT_ELEMENT_NAME);
78 statusCodeBuilder = (SAMLObjectBuilder<StatusCode>) getBuilderFactory().getBuilder(StatusCode.DEFAULT_ELEMENT_NAME);
79 statusMessageBuilder = (SAMLObjectBuilder<StatusMessage>) getBuilderFactory().getBuilder(StatusMessage.DEFAULT_ELEMENT_NAME);
80 signatureBuilder = (XMLObjectBuilder<Signature>) getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME);
84 * Build a SAML 1 Status element.
86 * @param statusCode The status code - see oasis-sstc-saml-core-1.1, section 3.4.3.1.
87 * @param statusMessage The status message, or <code>null</code> if none is to be set.
89 * @return The Status object, or <code>null</code> on error.
91 protected Status buildStatus(String statusCode, String statusMessage) {
93 if (statusCode == null || statusCode.equals("")) {
97 Status status = statusBuilder.buildObject();
98 StatusCode sc = statusCodeBuilder.buildObject();
99 sc.setValue(statusCode);
100 status.setStatusCode(sc);
102 if (statusMessage != null || !(statusMessage.equals(""))) {
104 StatusMessage sm = statusMessageBuilder.buildObject();
105 sm.setMessage(statusMessage);
106 status.setStatusMessage(sm);
113 * Signs the given assertion if either the current profile configuration or the relying party configuration contains
114 * signing credentials.
116 * @param assertion assertion to sign
117 * @param rpConfig relying party configuration
118 * @param profileConfig current profile configuration
120 protected void signAssertion(Assertion assertion, RelyingPartyConfiguration rpConfig,
121 AbstractSAML1ProfileConfiguration profileConfig) {
122 if (!profileConfig.getSignAssertions()) {
126 Credential signatureCredential = profileConfig.getSigningCredential();
127 if (signatureCredential == null) {
128 signatureCredential = rpConfig.getDefaultSigningCredential();
131 if (signatureCredential == null) {
135 SAMLObjectContentReference contentRef = new SAMLObjectContentReference(assertion);
136 Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
137 signature.getContentReferences().add(contentRef);
138 assertion.setSignature(signature);
140 Signer.signObject(signature);
144 * Encode a SAML Response.
146 * @param binding The SAML protocol binding to use.
147 * @param profileResponse The Raw output stream to send the message to.
148 * @param samlResponse The SAML Response to send.
149 * @param relyingParty The relying party to send the message to.
150 * @param roleDescriptor The role of the message sender.
151 * @param endpoint The endpoint to which the message should be send.
153 * @throws ProfileException On error.
155 protected void encodeResponse(String binding,final ProfileResponse<ServletResponse> profileResponse,
156 final Response samlResponse, final RelyingPartyConfiguration relyingParty,
157 final RoleDescriptor roleDescriptor, final Endpoint endpoint) throws ProfileException {
159 MessageEncoder<ServletResponse> encoder = getMessageEncoderFactory().getMessageEncoder(binding);
160 if (encoder == null) {
161 log.error("No MessageEncoder registered for " + binding);
162 throw new ProfileException("No MessageEncoder registered for " + binding);
165 encoder.setResponse(profileResponse.getRawResponse());
166 encoder.setIssuer(relyingParty.getProviderId());
167 encoder.setMetadataProvider(getRelyingPartyConfigurationManager().getMetadataProvider());
168 encoder.setRelyingPartyRole(roleDescriptor);
169 encoder.setSigningCredential(relyingParty.getDefaultSigningCredential());
170 encoder.setSamlMessage(samlResponse);
171 encoder.setRelyingPartyEndpoint(endpoint);
175 } catch (BindingException ex) {
176 log.error("Unable to encode response the relying party: " + relyingParty.getRelyingPartyId(), ex);
177 throw new ProfileException("Unable to encode response the relying party: "
178 + relyingParty.getRelyingPartyId(), ex);