]> WPIA git - gigi.git/blob - util-testing/org/cacert/gigi/DevelLauncher.java
upd: split certificate issuance as organisation into seperate
[gigi.git] / util-testing / org / cacert / gigi / DevelLauncher.java
1 package org.cacert.gigi;
2
3 import static org.cacert.gigi.Gigi.*;
4
5 import java.awt.Desktop;
6 import java.io.BufferedReader;
7 import java.io.ByteArrayInputStream;
8 import java.io.ByteArrayOutputStream;
9 import java.io.DataOutputStream;
10 import java.io.FileInputStream;
11 import java.io.IOException;
12 import java.io.InputStream;
13 import java.io.InputStreamReader;
14 import java.io.OutputStream;
15 import java.lang.reflect.Field;
16 import java.net.URISyntaxException;
17 import java.net.URL;
18 import java.nio.file.Files;
19 import java.nio.file.Paths;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.Properties;
24
25 import javax.servlet.http.HttpServletRequest;
26 import javax.servlet.http.HttpServletResponse;
27 import javax.servlet.http.HttpSession;
28
29 import org.cacert.gigi.dbObjects.ObjectCache;
30 import org.cacert.gigi.dbObjects.User;
31 import org.cacert.gigi.localisation.Language;
32 import org.cacert.gigi.output.template.Template;
33 import org.cacert.gigi.pages.Page;
34 import org.cacert.gigi.util.AuthorizationContext;
35 import org.cacert.gigi.util.ServerConstants;
36 import org.kamranzafar.jtar.TarEntry;
37 import org.kamranzafar.jtar.TarHeader;
38 import org.kamranzafar.jtar.TarOutputStream;
39
40 public class DevelLauncher {
41
42     public static void main(String[] args) throws Exception {
43         Properties mainProps = new Properties();
44         try (FileInputStream inStream = new FileInputStream("config/gigi.properties")) {
45             mainProps.load(inStream);
46         }
47         for (int i = 0; i < args.length; i++) {
48             if (args[i].equals("--port")) {
49                 mainProps.setProperty("port", args[i + 1]);
50             }
51             i++;
52         }
53         killPreviousInstance(mainProps);
54
55         ByteArrayOutputStream chunkConfig = new ByteArrayOutputStream();
56         DataOutputStream dos = new DataOutputStream(chunkConfig);
57         byte[] cacerts = Files.readAllBytes(Paths.get("config/cacerts.jks"));
58         byte[] keystore = Files.readAllBytes(Paths.get("config/keystore.pkcs12"));
59
60         DevelLauncher.writeGigiConfig(dos, "changeit".getBytes("UTF-8"), "changeit".getBytes("UTF-8"), mainProps, cacerts, keystore);
61         dos.flush();
62         InputStream oldin = System.in;
63         System.setIn(new ByteArrayInputStream(chunkConfig.toByteArray()));
64         new Launcher().boot();
65         addDevelPage(true);
66         new Thread("ticket awaiter") {
67
68             @Override
69             public void run() {
70                 try {
71                     Thread.sleep(8000);
72                 } catch (InterruptedException e) {
73                     e.printStackTrace();
74                 }
75                 try {
76                     if ( !ticketUsed) {
77                         Desktop.getDesktop().browse(new URL("http://" + ServerConstants.getWwwHostNamePort() + "/ticketWait").toURI());
78                     }
79                 } catch (IOException e) {
80                     e.printStackTrace();
81                 } catch (URISyntaxException e) {
82                     e.printStackTrace();
83                 }
84             }
85         }.start();
86         System.setIn(oldin);
87         BufferedReader br = new BufferedReader(new InputStreamReader(System.in, "UTF-8"));
88         System.out.println("Cacert-gigi system sucessfully started.");
89         System.out.println("Press enter to shutdown.");
90         br.readLine();
91         System.exit(0);
92     }
93
94     private static void killPreviousInstance(Properties mainProps) {
95         try {
96             String targetPort = mainProps.getProperty("http.port");
97             String targetHost = mainProps.getProperty("name.www");
98             URL u = new URL("http://" + targetHost + ":" + targetPort + "/kill");
99             u.openStream();
100         } catch (IOException e) {
101         }
102     }
103
104     public static void addDevelPage(boolean withToken) {
105         try {
106             Field instF = Gigi.class.getDeclaredField("instance");
107             Field pageF = Gigi.class.getDeclaredField("pages");
108             instF.setAccessible(true);
109             pageF.setAccessible(true);
110             Object gigi = instF.get(null);
111
112             // Check if we got a proper map (as much as we can tell)
113             Object pagesObj = pageF.get(gigi);
114             @SuppressWarnings("unchecked")
115             HashMap<String, Page> pages = pagesObj instanceof Map ? new HashMap<>((Map<String, Page>) pagesObj) : null;
116
117             pages.put("/manage", new Page("Page-manager") {
118
119                 @Override
120                 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
121                     ObjectCache.clearAllCaches();
122                     resp.getWriter().println("All caches cleared.");
123                     System.out.println("Caches cleared.");
124
125                 }
126
127                 @Override
128                 public boolean needsLogin() {
129                     return false;
130                 }
131
132             });
133
134             pages.put("/kill", new Page("Kill") {
135
136                 /**
137                  * The contained call to {@link System#exit(int)} is mainly
138                  * needed to kill this instance immediately if another
139                  * {@link DevelLauncher} is booting up to free all ports This is
140                  * required for fast development cycles.
141                  * 
142                  * @see #killPreviousInstance(Properties)
143                  */
144                 @Override
145                 public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
146                     System.exit(0);
147                 }
148
149                 @Override
150                 public boolean needsLogin() {
151                     return false;
152                 }
153             });
154
155             if (withToken) {
156                 addTicketPage(pages);
157             }
158
159             pageF.set(gigi, Collections.unmodifiableMap(pages));
160         } catch (ReflectiveOperationException e) {
161             e.printStackTrace();
162         }
163     }
164
165     static boolean ticketUsed = false;
166
167     private static void addTicketPage(HashMap<String, Page> pages) {
168         pages.put("/ticketWait", new Page("ticket") {
169
170             Template t = new Template(DevelLauncher.class.getResource("DevelTicketWait.templ"));
171
172             @Override
173             public boolean needsLogin() {
174                 return false;
175             }
176
177             @Override
178             public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
179                 resp.setHeader("content-security-policy", "");
180                 t.output(resp.getWriter(), getLanguage(req), new HashMap<String, Object>());
181             }
182
183         });
184         pages.put("/ticket", new Page("ticket") {
185
186             @Override
187             public boolean beforeTemplate(HttpServletRequest req, HttpServletResponse resp) throws IOException {
188                 // TODO Auto-generated method stub
189                 if ( !ticketUsed) {
190                     HttpSession sess = req.getSession();
191                     User user = User.getById(1);
192                     if (user == null) {
193                         resp.getWriter().println("ticket consumed but no user available for that action");
194                         ticketUsed = true;
195                         return true;
196                     }
197                     sess.setAttribute(LOGGEDIN, true);
198                     sess.setAttribute(Language.SESSION_ATTRIB_NAME, user.getPreferredLocale());
199                     sess.setAttribute(AUTH_CONTEXT, new AuthorizationContext(user, user));
200                     req.getSession().setAttribute(LOGIN_METHOD, "Ticket");
201                     resp.getWriter().println("ticket consumed");
202                     ticketUsed = true;
203                 }
204                 return true;
205             }
206
207             @Override
208             public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {}
209
210             @Override
211             public boolean needsLogin() {
212                 return false;
213             }
214         });
215     }
216
217     public static void writeGigiConfig(OutputStream target, byte[] keystorepw, byte[] truststorepw, Properties mainprop, byte[] cacerts, byte[] keystore) throws IOException {
218         TarOutputStream tos = new TarOutputStream(target);
219         ByteArrayOutputStream baos = new ByteArrayOutputStream();
220         mainprop.store(baos, "");
221
222         putTarEntry(baos.toByteArray(), tos, "gigi.properties");
223         putTarEntry(keystorepw, tos, "keystorepw");
224         putTarEntry(truststorepw, tos, "truststorepw");
225         putTarEntry(keystore, tos, "keystore.pkcs12");
226         putTarEntry(cacerts, tos, "cacerts.jks");
227         tos.close();
228
229     }
230
231     private static void putTarEntry(byte[] data, TarOutputStream tos, String name) throws IOException {
232         TarHeader th = new TarHeader();
233         th.name = new StringBuffer(name);
234         th.size = data.length;
235         tos.putNextEntry(new TarEntry(th));
236         tos.write(data);
237     }
238
239 }