Implemented "Clear Trust Anchor" button in Edit Identity Dialog.
[moonshot-ui.git] / src / moonshot-provisioning-common.vala
1 /*
2  * Copyright (c) 2011-2014, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31 */
32
33
34
35 namespace WebProvisioning
36 {
37     bool check_stack(SList<string> stack, string[] reference) {
38
39         if (stack.length() < reference.length)
40             return false;
41
42         for (int i = 0; i < reference.length; i++)
43         {
44             if (stack.nth_data(i) != reference[i])
45                 return false;
46         }
47
48         return true;
49     }
50
51     bool always_confirm_handler(SList<string> stack)
52     {
53         string[] always_confirm_path = {"always-confirm", "rule", "selection-rules", "identity", "identities"};
54
55         return check_stack(stack, always_confirm_path);
56     }
57
58     bool
59     pattern_handler(SList<string> stack)
60     {
61         string[] pattern_path = {"pattern", "rule", "selection-rules", "identity", "identities"};
62
63         return check_stack(stack, pattern_path);
64     }
65
66     bool server_cert_handler(SList<string> stack)
67     {
68         string[] server_cert_path = {"server-cert", "trust-anchor", "identity", "identities"};
69
70         return check_stack(stack, server_cert_path);
71     }
72
73     bool subject_alt_handler(SList<string> stack)
74     {
75         string[] subject_alt_path = {"subject-alt", "trust-anchor", "identity", "identities"};
76
77         return check_stack(stack, subject_alt_path);
78     }
79
80     bool subject_handler(SList<string> stack)
81     {
82         string[] subject_path = {"subject", "trust-anchor", "identity", "identities"};
83
84         return check_stack(stack, subject_path);
85     }
86
87     bool ca_cert_handler(SList<string> stack)
88     {
89         string[] ca_path = {"ca-cert", "trust-anchor", "identity", "identities"};
90
91         return check_stack(stack, ca_path);
92     }
93
94     bool realm_handler(SList<string> stack)
95     {
96         string[] realm_path = {"realm", "identity", "identities"};
97
98         return check_stack(stack, realm_path);
99     }
100
101     bool password_handler(SList<string> stack)
102     {
103         string[] password_path = {"password", "identity", "identities"};
104
105         return check_stack(stack, password_path);
106     }
107
108     bool user_handler(SList<string> stack)
109     {
110         string[] user_path = {"user", "identity", "identities"};
111
112         return check_stack(stack, user_path);
113     }
114
115     bool display_name_handler(SList<string> stack)
116     {
117         string[] display_name_path = {"display-name", "identity", "identities"};
118
119         return check_stack(stack, display_name_path);
120     }
121
122     public class Parser : Object
123     {
124         private static MoonshotLogger logger = new MoonshotLogger("WebProvisioning");
125
126         private void start_element_func(MarkupParseContext context,
127                                         string element_name,
128                                         string[] attribute_names,
129                                         string[] attribute_values) throws MarkupError
130             {
131                 if (element_name == "identity")
132                 {
133                     logger.trace("start_element_func (%p): Adding an identity".printf(this));
134                     card = new IdCard();
135                     _cards += card;
136                 }
137                 else if (element_name == "rule")
138                 {
139                     card.add_rule(Rule());
140                 }
141             }
142
143             private void
144             text_element_func(MarkupParseContext context,
145                               string             text,
146                               size_t             text_len) throws MarkupError {
147                 unowned SList<string> stack = context.get_element_stack();
148
149                 if (text_len < 1)
150                     return;
151
152                 logger.trace("text_element_func (%p): text='%s'".printf(this, stack.nth_data(0)));
153
154                 if (stack.nth_data(0) == "display-name" && display_name_handler(stack))
155                 {
156                     card.display_name = text;
157                 }
158                 else if (stack.nth_data(0) == "user" && user_handler(stack))
159                 {
160                     card.username = text;
161                 }
162                 else if (stack.nth_data(0) == "password" && password_handler(stack))
163                 {
164                     card.password = text;
165                 }
166                 else if (stack.nth_data(0) == "realm" && realm_handler(stack))
167                 {
168                     card.issuer = text;
169                 }
170                 else if (stack.nth_data(0) == "service")
171                 {
172                     card.services.add(text);
173                 }
174
175                 /* Rules */
176                 else if (stack.nth_data(0) == "pattern" && pattern_handler(stack))
177                 {
178                     /* use temp array to workaround valac 0.10 bug accessing array property length */
179                     var temp = card.rules;
180                     card.rules[temp.length - 1].pattern = text;
181                 }
182                 else if (stack.nth_data(0) == "always-confirm" && always_confirm_handler(stack))
183                 {
184                     if (text == "true" || text == "false") {
185                         /* use temp array to workaround valac 0.10 bug accessing array property length*/
186                         var temp = card.rules;
187                         card.rules[temp.length - 1].always_confirm = text;
188                     }
189                 }
190                 // This is ugly, but... we use the TrustAnchor field in the IdCard as a placeholder,
191                 // replacing it with a new one every time we read a new element.
192                 // "user_verified" is always false, since we're reading the TrustAnchor from XML.
193                 else if (stack.nth_data(0) == "ca-cert" && ca_cert_handler(stack))
194                 {
195                     string ca_cert = text;
196                     var ta = new TrustAnchor(ca_cert,
197                                              card.trust_anchor.server_cert,
198                                              card.trust_anchor.subject,
199                                              card.trust_anchor.subject_alt,
200                                              false);
201                     card.set_trust_anchor_from_store(ta);
202                 }
203                 else if (stack.nth_data(0) == "server-cert" && server_cert_handler(stack))
204                 {
205                     string server_cert = text;
206                     var ta = new TrustAnchor(card.trust_anchor.ca_cert,
207                                              server_cert,
208                                              card.trust_anchor.subject,
209                                              card.trust_anchor.subject_alt,
210                                              false);
211                     card.set_trust_anchor_from_store(ta);
212
213                 }
214                 else if (stack.nth_data(0) == "subject" && subject_handler(stack))
215                 {
216                     string subject = text;
217                     var ta = new TrustAnchor(card.trust_anchor.ca_cert,
218                                              card.trust_anchor.server_cert,
219                                              subject,
220                                              card.trust_anchor.subject_alt,
221                                              false);
222                     card.set_trust_anchor_from_store(ta);
223                 }
224                 else if (stack.nth_data(0) == "subject-alt" && subject_alt_handler(stack))
225                 {
226                     string subject_alt = text;
227                     var ta = new TrustAnchor(card.trust_anchor.ca_cert,
228                                              card.trust_anchor.server_cert,
229                                              card.trust_anchor.subject,
230                                              subject_alt,
231                                              false);
232                     card.set_trust_anchor_from_store(ta);
233                 }
234             }
235
236
237
238         private const MarkupParser parser = {
239             start_element_func, null, text_element_func, null, null
240         };
241
242         private MarkupParseContext ctx;
243
244         private string       text;
245         private string       path;
246
247         private IdCard card;
248         private IdCard[] _cards = {};
249
250         public IdCard[] cards {
251             get {return _cards;}
252             private set {_cards = value ?? new IdCard[0] ;}
253         }
254
255         public Parser(string path) {
256
257             ctx = new MarkupParseContext(parser, 0, this, null);
258
259             text = "";
260             this.path = path;
261
262             var file = File.new_for_path(path);
263
264             try
265             {
266                 var dis = new DataInputStream(file.read());
267                 string line;
268                 while ((line = dis.read_line(null)) != null) {
269                     text += line;
270
271                     // Preserve newlines -- important for certificate import.
272                     // (X509 certs can't be parsed without the newlines.)
273                     //
274                     // This may add an extra newline at EOF. Maybe use
275                     // dis.read_upto("\n", ...) followed by dis.read_byte() instead?
276                     text += "\n";
277                 }
278             }
279             catch(GLib.Error e)
280             {
281                 error("Could not retreive file size");
282             }
283
284             logger.trace(@"Parser(): read text to parse; length=$(text.length)");
285         }
286
287         public void parse() {
288             try
289             {
290                 ctx.parse(text, text.length);
291             }
292             catch(GLib.Error e)
293             {
294                 error("Could not parse %s, invalid content", path);
295             }
296         }
297     }
298 }