Lots of code cleanup
[java-idp.git] / src / edu / internet2 / middleware / shibboleth / idp / profile / saml1 / AbstractSAML1ProfileHandler.java
1 /*
2  * Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package edu.internet2.middleware.shibboleth.idp.profile.saml1;
18
19 import java.security.NoSuchAlgorithmException;
20
21 import javax.servlet.ServletResponse;
22
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;
40
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;
46
47
48 /**
49  * Common implementation details for profile handlers.
50  */
51 public abstract class AbstractSAML1ProfileHandler extends AbstractSAMLProfileHandler {
52     
53     /** SAML Version for this profile handler. */
54     public static final SAMLVersion SAML_VERSION = SAMLVersion.VERSION_11;
55     
56     /** Class logger. */
57     private static Logger log = Logger.getLogger(AbstractSAML1ProfileHandler.class);
58     
59     /** Builder for Status objects. */
60     protected SAMLObjectBuilder<Status> statusBuilder;
61     
62     /** Builder for StatusCode objects. */
63     protected SAMLObjectBuilder<StatusCode> statusCodeBuilder;
64     
65     /** Builder for StatusMessage objects. */
66     protected SAMLObjectBuilder<StatusMessage> statusMessageBuilder;
67     
68     /** For building signature. */
69     private XMLObjectBuilder<Signature> signatureBuilder;
70     
71     /**
72      * Default constructor.
73      */
74     @SuppressWarnings("unchecked")
75     public AbstractSAML1ProfileHandler(){
76         super();
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);
81     }
82     
83     /**
84      * Build a SAML 1 Status element.
85      *
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.
88      *
89      * @return The Status object, or <code>null</code> on error.
90      */
91     protected Status buildStatus(String statusCode, String statusMessage) {
92         
93         if (statusCode == null || statusCode.equals("")) {
94             return null;
95         }
96         
97         Status status = statusBuilder.buildObject();
98         StatusCode sc = statusCodeBuilder.buildObject();
99         sc.setValue(statusCode);
100         status.setStatusCode(sc);
101         
102         if (statusMessage != null || !(statusMessage.equals(""))) {
103             
104             StatusMessage sm = statusMessageBuilder.buildObject();
105             sm.setMessage(statusMessage);
106             status.setStatusMessage(sm);
107         }
108         
109         return status;
110     }
111     
112     /**
113      * Signs the given assertion if either the current profile configuration or the relying party configuration contains
114      * signing credentials.
115      *
116      * @param assertion assertion to sign
117      * @param rpConfig relying party configuration
118      * @param profileConfig current profile configuration
119      */
120     protected void signAssertion(Assertion assertion, RelyingPartyConfiguration rpConfig,
121             AbstractSAML1ProfileConfiguration profileConfig) {
122         if (!profileConfig.getSignAssertions()) {
123             return;
124         }
125         
126         Credential signatureCredential = profileConfig.getSigningCredential();
127         if (signatureCredential == null) {
128             signatureCredential = rpConfig.getDefaultSigningCredential();
129         }
130         
131         if (signatureCredential == null) {
132             return;
133         }
134         
135         SAMLObjectContentReference contentRef = new SAMLObjectContentReference(assertion);
136         Signature signature = signatureBuilder.buildObject(Signature.DEFAULT_ELEMENT_NAME);
137         signature.getContentReferences().add(contentRef);
138         assertion.setSignature(signature);
139         
140         Signer.signObject(signature);
141     }
142     
143     /**
144      * Encode a SAML Response.
145      * 
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.
152      * 
153      * @throws ProfileException On error.
154      */
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 {
158         
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);
163         }
164         
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);
172         
173         try {
174             encoder.encode();
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);
179         }
180         
181     }
182 }