Add MockIdp and test case
[java-idp.git] / tests / edu / internet2 / middleware / shibboleth / runner / MadSignertest.java
1 /*
2  * Copyright [2005] [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.runner;
18
19 import java.io.FileInputStream;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.PrintWriter;
24 import java.security.KeyStore;
25 import java.security.KeyStoreException;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.cert.CertificateException;
28 import java.util.Arrays;
29 import java.util.Date;
30 import java.util.Iterator;
31
32 import javax.servlet.ServletException;
33 import javax.servlet.ServletOutputStream;
34 import javax.servlet.http.HttpServlet;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
37
38 import org.apache.xml.security.signature.XMLSignature;
39 import org.opensaml.SAMLAssertion;
40 import org.opensaml.SAMLIdentifier;
41 import org.opensaml.SAMLResponse;
42
43 import com.mockrunner.mock.web.MockHttpServletRequest;
44 import com.mockrunner.mock.web.MockHttpServletResponse;
45
46 /**
47  * Class that signs and resets the timestamps on SAML objects.
48  * 
49  * <p>SAML Responses and Assertions must be signed and they have
50  * expiration times that are very short. This makes static files
51  * of test cases hard to use. This class promiscuously signs 
52  * any static assertion in an XML file with credentials supplied
53  * in a JKS and it resets the timestamps. It is used to support
54  * JUnit testing where signed input is required.</p>
55  * 
56  * @author gilbert
57  *
58  */
59 public class MadSignertest {
60
61     private KeyStore ks = null;
62     private char[] passwd;
63
64     /**
65      * Create a signer associated with a JKS file
66      * @param path The JKS file path
67      * @param password The password of the JKS file and all its Keys.
68      */
69     public MadSignertest(String path, String password) 
70         throws KeyStoreException, 
71             NoSuchAlgorithmException, 
72             CertificateException, 
73             FileNotFoundException, 
74             IOException {
75         passwd = password.toCharArray();
76         ks = KeyStore.getInstance("JKS");
77         ks.load(new FileInputStream(path), passwd);
78     }
79     
80     /**
81      * Sign the SAMLResponse in a test data xml file.
82      * 
83      * <p>SAML Assertions are good for 60 seconds, so
84      * if you want an assertion to be expired set the
85      * timestamp back at least a minute.</p>
86      * 
87      * @param path Path to the input XML file.
88      * @param alias Alias in the JKS of the signing key.
89      * @param now Date to use for timestamps
90      * @param reidentify Option to change response/assertion IDs
91      * 
92      * @return SAMLResponse now signed
93      */
94     public SAMLResponse signResponseFile(
95             String path, 
96             String alias, 
97             Date now, 
98             boolean reidentify) 
99         throws Exception {
100         
101         InputStream in = new FileInputStream(path);
102         
103         if (now==null)
104             now = new Date(); // default is current time
105         SAMLIdentifier defaultIDProvider = ShibbolethRunner.samlConfig.getDefaultIDProvider();
106         
107         // Read in and parse the XML and turn it into a SAMLResponse
108         // [obviously it better be a SAML Response to begin with.]
109         SAMLResponse r = new SAMLResponse(in);
110         
111         if (reidentify)
112             r.setId(defaultIDProvider.getIdentifier());
113         
114         // Retimestamp and resign each assertions
115         Iterator assertions = r.getAssertions();
116         while (assertions.hasNext()) {
117             SAMLAssertion assertion = (SAMLAssertion) assertions.next();
118             assertion.setIssueInstant(now);
119             assertion.setNotBefore(now);
120             assertion.setNotOnOrAfter(new Date(now.getTime() + 60000));
121             if (reidentify)
122                 assertion.setId(defaultIDProvider.getIdentifier());
123             assertion.sign(
124                     XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,
125                     ks.getKey(alias,passwd),
126                     Arrays.asList(ks.getCertificateChain(alias))
127                     );
128             
129         }
130         
131         // Now resign the Response
132         r.sign(
133                 XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,
134                 ks.getKey(alias,passwd),
135                 Arrays.asList(ks.getCertificateChain(alias))
136                 );
137         
138         return r;
139     }
140     
141     public SAMLResponse signResponseFile(
142             String path, 
143             String alias) throws Exception{
144         return signResponseFile(path,alias,null,true);
145     }
146     
147     
148     
149     /**
150      * A dummy Idp that can be used to create a ShibbolethRunner
151      * IdPTestContext when the response is to come from a file.
152      */
153     public class MockIdp extends HttpServlet {
154         
155         public String ssoResponseFile = null;
156         public String artifactResponseFile = null;
157         public String attributeResponseFile = null;
158         public String alias = "tomcat";
159         
160         public void init() {}
161
162         public void doGet(HttpServletRequest arg1, 
163                 HttpServletResponse arg2) 
164             throws ServletException, IOException {
165             
166             MockHttpServletRequest request = (MockHttpServletRequest) arg1;
167             MockHttpServletResponse response = (MockHttpServletResponse) arg2;
168             
169             String uri = request.getRequestURI();
170             SAMLResponse r = null;
171             
172             
173             // A very simple test for how to respond.
174             
175             try {
176                 if (uri.endsWith("SSO")){
177                     r=signResponseFile(ssoResponseFile, alias);
178                     request.setAttribute("assertion",new String(r.toBase64()));
179                     request.setAttribute("shire",request.getParameter("shire"));
180                     request.setAttribute("target",request.getParameter("target"));
181                     return;
182                 }
183                 if (uri.endsWith("AA")) {
184                     r=signResponseFile(attributeResponseFile, alias);
185                 }
186                 if (uri.endsWith("Artifact")) {
187                     r=signResponseFile(artifactResponseFile, alias);
188                 }
189             } catch (Exception e) {
190                 throw new ServletException("test file problem");
191             }
192             
193             response.setContentType("text/xml");
194             PrintWriter writer = response.getWriter();
195             writer.write(r.toString());
196             writer.close();
197             
198         }
199     }
200     
201 }