RT 4.2.11, ticket#13852
[freeside.git] / rt / t / web / smime / outgoing.t
1 use strict;
2 use warnings;
3
4 use RT::Test::SMIME tests => undef;
5 my $test = 'RT::Test::SMIME';
6
7 use RT::Action::SendEmail;
8 use File::Temp qw(tempdir);
9
10 use_ok('RT::Crypt::SMIME');
11
12 RT::Test::SMIME->import_key('sender@example.com');
13
14 my $user_email = 'root@example.com';
15 {
16     my $user = RT::Test->load_or_create_user(
17         Name => $user_email, EmailAddress => $user_email
18     );
19     ok $user && $user->id, 'loaded or created user';
20     RT::Test::SMIME->import_key($user_email, $user);
21 }
22
23 my $queue = RT::Test->load_or_create_queue(
24     Name              => 'Regression',
25     CorrespondAddress => 'sender@example.com',
26     CommentAddress    => 'sender@example.com',
27 );
28 ok $queue && $queue->id, 'loaded or created queue';
29
30 RT::Test->set_rights(
31     Principal => 'Everyone',
32     Right => ['CreateTicket', 'ShowTicket', 'SeeQueue', 'ReplyToTicket', 'ModifyTicket'],
33 );
34
35 my ($baseurl, $m) = RT::Test->started_ok;
36 ok $m->login, 'logged in';
37
38 my @variants = (
39     {},
40     { Sign => 1 },
41     { Encrypt => 1 },
42     { Sign => 1, Encrypt => 1 },
43 );
44
45 # collect emails
46 my %mail = (
47     plain            => [],
48     signed           => [],
49     encrypted        => [],
50     signed_encrypted => [],
51 );
52
53 diag "check in read-only mode that queue's props influence create/update ticket pages" if $ENV{TEST_VERBOSE};
54 {
55     foreach my $variant ( @variants ) {
56         set_queue_crypt_options( %$variant );
57         $m->goto_create_ticket( $queue );
58         $m->form_name('TicketCreate');
59         if ( $variant->{'Encrypt'} ) {
60             ok $m->value('Encrypt', 2), "encrypt tick box is checked";
61         } else {
62             ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked";
63         }
64         if ( $variant->{'Sign'} ) {
65             ok $m->value('Sign', 2), "sign tick box is checked";
66         } else {
67             ok !$m->value('Sign', 2), "sign tick box is unchecked";
68         }
69     }
70
71     # to avoid encryption/signing during create
72     set_queue_crypt_options();
73
74     my $ticket = RT::Ticket->new( $RT::SystemUser );
75     my ($id) = $ticket->Create(
76         Subject   => 'test',
77         Queue     => $queue->id,
78         Requestor => $user_email,
79     );
80     ok $id, 'ticket created';
81
82     foreach my $variant ( @variants ) {
83         set_queue_crypt_options( %$variant );
84         $m->goto_ticket( $id );
85         $m->follow_link_ok({text => 'Reply'}, '-> reply');
86         $m->form_number(3);
87         if ( $variant->{'Encrypt'} ) {
88             ok $m->value('Encrypt', 2), "encrypt tick box is checked";
89         } else {
90             ok !$m->value('Encrypt', 2), "encrypt tick box is unchecked";
91         }
92         if ( $variant->{'Sign'} ) {
93             ok $m->value('Sign', 2), "sign tick box is checked";
94         } else {
95             ok !$m->value('Sign', 2), "sign tick box is unchecked";
96         }
97     }
98 }
99
100 # create a ticket for each combination
101 foreach my $queue_set ( @variants ) {
102     set_queue_crypt_options( %$queue_set );
103     foreach my $ticket_set ( @variants ) {
104         create_a_ticket( %$ticket_set );
105     }
106 }
107
108 my $tid;
109 {
110     my $ticket = RT::Ticket->new( $RT::SystemUser );
111     ($tid) = $ticket->Create(
112         Subject   => 'test',
113         Queue     => $queue->id,
114         Requestor => $user_email,
115     );
116     ok $tid, 'ticket created';
117 }
118
119 # again for each combination add a reply message
120 foreach my $queue_set ( @variants ) {
121     set_queue_crypt_options( %$queue_set );
122     foreach my $ticket_set ( @variants ) {
123         update_ticket( $tid, %$ticket_set );
124     }
125 }
126
127
128 # ------------------------------------------------------------------------------
129 # now delete all keys from the keyring and put back secret/pub pair for rt-test@
130 # and only public key for sender@ so we can verify signatures and decrypt
131 # like we are on another side recieving emails
132 # ------------------------------------------------------------------------------
133
134 my $keyring = $test->keyring_path;
135 unlink $_ foreach glob( $keyring ."/*" );
136 RT::Test::SMIME->import_key('sender@example.com.crt');
137 RT::Test::SMIME->import_key($user_email);
138
139 $queue = RT::Test->load_or_create_queue(
140     Name              => 'Regression',
141     CorrespondAddress => $user_email,
142     CommentAddress    => $user_email,
143 );
144 ok $queue && $queue->id, 'changed props of the queue';
145
146 foreach my $mail ( map cleanup_headers($_), @{ $mail{'plain'} } ) {
147     my ($status, $id) = RT::Test->send_via_mailgate($mail);
148     is ($status >> 8, 0, "The mail gateway exited normally");
149     ok ($id, "got id of a newly created ticket - $id");
150
151     my $tick = RT::Ticket->new( $RT::SystemUser );
152     $tick->Load( $id );
153     ok ($tick->id, "loaded ticket #$id");
154
155     my $txn = $tick->Transactions->First;
156     my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
157
158     ok !$msg->GetHeader('X-RT-Privacy'), "RT's outgoing mail has no crypto";
159     is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted',
160         "RT's outgoing mail looks not encrypted";
161     ok !$msg->GetHeader('X-RT-Incoming-Signature'),
162         "RT's outgoing mail looks not signed";
163
164     like $txn->Content, qr/Some content/, "RT's mail includes copy of ticket text";
165 }
166
167 foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed'} } ) {
168     my ($status, $id) = RT::Test->send_via_mailgate($mail);
169     is ($status >> 8, 0, "The mail gateway exited normally");
170     ok ($id, "got id of a newly created ticket - $id");
171
172     my $tick = RT::Ticket->new( $RT::SystemUser );
173     $tick->Load( $id );
174     ok ($tick->id, "loaded ticket #$id");
175
176     my $txn = $tick->Transactions->First;
177     my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
178
179     is $msg->GetHeader('X-RT-Privacy'), 'SMIME',
180         "RT's outgoing mail has crypto" or exit 0;
181     is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Not encrypted',
182         "RT's outgoing mail looks not encrypted";
183     like $msg->GetHeader('X-RT-Incoming-Signature'),
184         qr/<sender\@example\.com>/,
185         "RT's outgoing mail looks signed";
186
187     like $attachments[0]->Content, qr/Some content/,
188         "RT's mail includes copy of ticket text";
189 }
190
191 foreach my $mail ( map cleanup_headers($_), @{ $mail{'encrypted'} } ) {
192     my ($status, $id) = RT::Test->send_via_mailgate($mail);
193     is ($status >> 8, 0, "The mail gateway exited normally");
194     ok ($id, "got id of a newly created ticket - $id");
195
196     my $tick = RT::Ticket->new( $RT::SystemUser );
197     $tick->Load( $id );
198     ok ($tick->id, "loaded ticket #$id");
199
200     my $txn = $tick->Transactions->First;
201     my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
202
203     is $msg->GetHeader('X-RT-Privacy'), 'SMIME',
204         "RT's outgoing mail has crypto";
205     is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success',
206         "RT's outgoing mail looks encrypted";
207     ok !$msg->GetHeader('X-RT-Incoming-Signature'),
208         "RT's outgoing mail looks not signed";
209
210     like $attachments[0]->Content, qr/Some content/,
211         "RT's mail includes copy of ticket text";
212 }
213
214 foreach my $mail ( map cleanup_headers($_), @{ $mail{'signed_encrypted'} } ) {
215     my ($status, $id) = RT::Test->send_via_mailgate($mail);
216     is ($status >> 8, 0, "The mail gateway exited normally");
217     ok ($id, "got id of a newly created ticket - $id");
218
219     my $tick = RT::Ticket->new( $RT::SystemUser );
220     $tick->Load( $id );
221     ok ($tick->id, "loaded ticket #$id");
222
223     my $txn = $tick->Transactions->First;
224     my ($msg, @attachments) = @{$txn->Attachments->ItemsArrayRef};
225
226     is $msg->GetHeader('X-RT-Privacy'), 'SMIME',
227         "RT's outgoing mail has crypto";
228     is $msg->GetHeader('X-RT-Incoming-Encryption'), 'Success',
229         "RT's outgoing mail looks encrypted";
230     like $msg->GetHeader('X-RT-Incoming-Signature'),
231         qr/<sender\@example.com>/,
232         "RT's outgoing mail looks signed";
233
234     like $attachments[0]->Content, qr/Some content/,
235         "RT's mail includes copy of ticket text";
236 }
237
238 sub create_a_ticket {
239     my %args = (@_);
240
241     RT::Test->clean_caught_mails;
242
243     describe_options('creating a ticket: ', %args);
244
245     $m->goto_create_ticket( $queue );
246     $m->form_name('TicketCreate');
247     $m->field( Subject    => 'test' );
248     $m->field( Requestors => $user_email );
249     $m->field( Content    => 'Some content' );
250
251     foreach ( qw(Sign Encrypt) ) {
252         if ( $args{ $_ } ) {
253             $m->tick( $_ => 1 );
254         } else {
255             $m->untick( $_ => 1 );
256         }
257     }
258
259     $m->submit;
260     is $m->status, 200, "request successful";
261
262     unlike($m->content, qr/unable to sign outgoing email messages/);
263
264     $m->get_ok('/'); # ensure that the mail has been processed
265
266     my @mail = RT::Test->fetch_caught_mails;
267     check_text_emails( \%args, @mail );
268 }
269
270 sub update_ticket {
271     my $tid = shift;
272     my %args = (@_);
273
274     RT::Test->clean_caught_mails;
275
276     describe_options('updating ticket #'. $tid .': ', %args);
277
278     ok $m->goto_ticket( $tid ), "UI -> ticket #$tid";
279     $m->follow_link_ok( { text => 'Reply' }, 'ticket -> reply' );
280     $m->form_number(3);
281     $m->field( UpdateContent => 'Some content' );
282
283     foreach ( qw(Sign Encrypt) ) {
284         if ( $args{ $_ } ) {
285             $m->tick( $_ => 1 );
286         } else {
287             $m->untick( $_ => 1 );
288         }
289     }
290
291     $m->click('SubmitTicket');
292     is $m->status, 200, "request successful";
293     $m->content_like(qr/Correspondence added/, 'Correspondence added');# or diag $m->content;
294
295     $m->get_ok('/'); # ensure that the mail has been processed
296
297     my @mail = RT::Test->fetch_caught_mails;
298     check_text_emails( \%args, @mail );
299 }
300
301 undef $m;
302 done_testing;
303
304 sub check_text_emails {
305     my %args = %{ shift @_ };
306     my @mail = @_;
307
308     describe_options('testing that we got at least one mail: ', %args);
309
310     ok scalar @mail, "got some mail";
311     for my $mail (@mail) {
312         if ( $args{'Encrypt'} ) {
313             unlike $mail, qr/Some content/, "outgoing email was encrypted";
314         } else {
315             like $mail, qr/Some content/, "outgoing email was not encrypted";
316         }
317
318         if ( $args{'Encrypt'} ) {
319             like $mail, qr/application\/(?:x-)?pkcs7-mime/, 'outgoing email was processed';
320         } elsif ( $args{'Sign'} ) {
321             like $mail, qr/(?:x-)?pkcs7-signature/, 'outgoing email was processed';
322         } else {
323             unlike $mail, qr/smime/, 'outgoing email was not processed';
324         }
325     }
326     if ( $args{'Sign'} && $args{'Encrypt'} ) {
327         push @{ $mail{'signed_encrypted'} }, @mail;
328     } elsif ( $args{'Sign'} ) {
329         push @{ $mail{'signed'} }, @mail;
330     } elsif ( $args{'Encrypt'} ) {
331         push @{ $mail{'encrypted'} }, @mail;
332     } else {
333         push @{ $mail{'plain'} }, @mail;
334     }
335 }
336
337 sub cleanup_headers {
338     my $mail = shift;
339     # strip id from subject to create new ticket
340     $mail =~ s/^(Subject:)\s*\[.*?\s+#\d+\]\s*/$1 /m;
341     # strip several headers
342     foreach my $field ( qw(Message-ID RT-Originator RT-Ticket X-RT-Loop-Prevention) ) {
343         $mail =~ s/^$field:.*?\n(?! |\t)//gmsi;
344     }
345     return $mail;
346 }
347
348 sub set_queue_crypt_options {
349     my %args = @_;
350
351     describe_options('setting queue options: ', %args);
352
353     $m->get_ok("/Admin/Queues/Modify.html?id=". $queue->id);
354     $m->form_with_fields('Sign', 'Encrypt');
355     foreach my $opt ('Sign', 'Encrypt') {
356         if ( $args{$opt} ) {
357             $m->tick($opt => 1);
358         } else {
359             $m->untick($opt => 1);
360         }
361     }
362     $m->submit;
363 }
364
365 sub describe_options {
366     return unless $ENV{'TEST_VERBOSE'};
367
368     my $msg = shift;
369     my %args = @_;
370     if ( $args{'Encrypt'} && $args{'Sign'} ) {
371         $msg .= 'encrypt and sign';
372     }
373     elsif ( $args{'Sign'} ) {
374         $msg .= 'sign';
375     }
376     elsif ( $args{'Encrypt'} ) {
377         $msg .= 'encrypt';
378     }
379     else {
380         $msg .= 'no encrypt and no sign';
381     }
382     diag $msg;
383 }
384