1 /*
2  * Copyright (C) 2011 The Android Open Source Project
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 com.android.emailcommon.provider;
18 
19 import android.os.Parcel;
20 import android.test.AndroidTestCase;
21 import android.test.mock.MockContext;
22 import android.test.suitebuilder.annotation.SmallTest;
23 
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 
27 import java.util.Arrays;
28 
29 /**
30  * Unit tests for the HostAuth inner class.
31  * These tests must be locally complete - no server(s) required.
32  */
33 @SmallTest
34 public class HostAuthTests extends AndroidTestCase {
35 
36     /**
37      * Test user name and password are set correctly
38      */
testSetLogin()39     public void testSetLogin() {
40         HostAuth ha = new HostAuth();
41         ha.setLogin("user:password");
42         assertEquals("user", ha.mLogin);
43         assertEquals("password", ha.mPassword);
44 
45         // special characters are not removed during insertion
46         ha.setLogin("%20us%20er%20:password");
47         assertEquals("%20us%20er%20", ha.mLogin);
48         assertEquals("password", ha.mPassword);
49 
50         // special characters are not removed during insertion
51         ha.setLogin("user:%20pass%20word%20");
52         assertEquals("user", ha.mLogin);
53         assertEquals("%20pass%20word%20", ha.mPassword);
54 
55         ha.setLogin("user:");
56         assertEquals("user", ha.mLogin);
57         assertEquals("", ha.mPassword);
58 
59         ha.setLogin(":password");
60         assertEquals("", ha.mLogin);
61         assertEquals("password", ha.mPassword);
62 
63         ha.setLogin("");
64         assertNull(ha.mLogin);
65         assertNull(ha.mPassword);
66 
67         ha.setLogin(null);
68         assertNull(ha.mLogin);
69         assertNull(ha.mPassword);
70 
71         ha.setLogin("userpassword");
72         assertEquals("userpassword", ha.mLogin);
73         assertNull(ha.mPassword);
74     }
75 
76     /**
77      * Test the authentication flag is set correctly when setting user name and password
78      */
testSetLoginAuthenticate()79     public void testSetLoginAuthenticate() {
80         HostAuth ha = new HostAuth();
81 
82         ha.mFlags = 0x00000000;
83         ha.setLogin("user", "password");
84         assertEquals(HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
85 
86         ha.mFlags = 0x00000000;
87         ha.setLogin("user", "");
88         assertEquals(HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
89 
90         ha.mFlags = 0xffffffff;
91         ha.setLogin("", "password");
92         assertEquals(~HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
93 
94         ha.mFlags = 0x00000000;
95         ha.setLogin("user", null);
96         assertEquals(HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
97 
98         ha.mFlags = 0xffffffff;
99         ha.setLogin(null, "password");
100         assertEquals(~HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
101 
102         ha.mFlags = 0xffffffff;
103         ha.setLogin(null, null);
104         assertEquals(~HostAuth.FLAG_AUTHENTICATE, ha.mFlags);
105     }
106 
107     /**
108      * Test setting the connection using a protocol and flags
109      */
testSetConnectionFlags()110     public void testSetConnectionFlags() {
111         HostAuth ha = new HostAuth();
112 
113         // Different port types don't affect flags
114         ha.setConnection("imap", "server", 123, 0);
115         assertEquals(0, ha.mFlags);
116         ha.setConnection("imap", "server", -1, 0);
117         assertEquals(0, ha.mFlags);
118 
119         // Different protocol types don't affect flags
120         ha.setConnection("pop3", "server", 123, 0);
121         assertEquals(0, ha.mFlags);
122         ha.setConnection("pop3", "server", -1, 0);
123         assertEquals(0, ha.mFlags);
124         ha.setConnection("eas", "server", 123, 0);
125         assertEquals(0, ha.mFlags);
126         ha.setConnection("eas", "server", -1, 0);
127         assertEquals(0, ha.mFlags);
128         ha.setConnection("smtp", "server", 123, 0);
129         assertEquals(0, ha.mFlags);
130         ha.setConnection("smtp", "server", -1, 0);
131         assertEquals(0, ha.mFlags);
132 
133         // Sets SSL flag
134         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_SSL);
135         assertEquals(HostAuth.FLAG_SSL, ha.mFlags);
136 
137         // Sets SSL+Trusted flags
138         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN,
139                 HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL);
140         assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
141 
142         // Sets TLS flag
143         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_TLS);
144         assertEquals(HostAuth.FLAG_TLS, ha.mFlags);
145 
146         // Sets TLS+Trusted flags
147         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN,
148                 HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL);
149         assertEquals(HostAuth.FLAG_TLS | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
150 
151         // Test other defined flags; should not affect mFlags
152         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_AUTHENTICATE);
153         assertEquals(0, ha.mFlags);
154 
155         // Test every other bit; should not affect mFlags
156         // mFlag is evalutated to the following:
157         // mFlag = (0 & (some operation)) | (0xfffffff4 & 0x1b)
158         // mFlag = 0 | 0x10
159         // mFlag = 0x10
160         ha.setConnection("imap", "server", HostAuth.PORT_UNKNOWN, 0xfffffff4);
161         assertEquals(0x10, ha.mFlags);
162     }
163 
testSetConnectionWithCerts()164     public void testSetConnectionWithCerts() {
165         HostAuth ha = new HostAuth();
166 
167         ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_SSL, "client-cert");
168         assertEquals(HostAuth.FLAG_SSL, ha.mFlags);
169         assertEquals("client-cert", ha.mClientCertAlias);
170 
171         ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN, HostAuth.FLAG_TLS, "client-cert");
172         assertEquals(HostAuth.FLAG_TLS, ha.mFlags);
173         assertEquals("client-cert", ha.mClientCertAlias);
174 
175         // Note that we can still trust all server certificates, even if we present a client
176         // user certificate.
177         ha.setConnection("eas", "server", HostAuth.PORT_UNKNOWN,
178                 HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, "client-cert");
179         assertEquals(HostAuth.FLAG_SSL | HostAuth.FLAG_TRUST_ALL, ha.mFlags);
180         assertEquals("client-cert", ha.mClientCertAlias);
181 
182         try {
183             ha.setConnection(
184                     "eas", "server", HostAuth.PORT_UNKNOWN, 0 /* no flags */, "client-cert");
185             fail("Shouldn't be able to set a client certificate on an unsecure connection");
186         } catch (IllegalArgumentException expected) {
187             // ignore
188         }
189     }
190 
testParceling()191     public void testParceling() {
192         final HostAuth orig = new HostAuth();
193         // Fill in some data
194         orig.mPort = 993;
195         orig.mProtocol = "imap";
196         orig.mAddress = "example.com";
197         orig.mLogin = "user";
198         orig.mPassword = "supersecret";
199         orig.mDomain = "domain";
200         orig.mClientCertAlias = "certalias";
201 
202         final Parcel p1 = Parcel.obtain();
203         orig.writeToParcel(p1, 0);
204         p1.setDataPosition(0);
205         final HostAuth unparceled1 = new HostAuth(p1);
206         p1.recycle();
207         assertEquals(orig, unparceled1);
208         assertEquals(orig.mCredentialKey, unparceled1.mCredentialKey);
209         assertEquals(orig.mCredential, unparceled1.mCredential);
210 
211         orig.getOrCreateCredential(new MockContext());
212 
213         final Parcel p2 = Parcel.obtain();
214         orig.writeToParcel(p2, 0);
215         p2.setDataPosition(0);
216         final HostAuth unparceled2 = new HostAuth(p2);
217         p2.recycle();
218         assertEquals(orig, unparceled2);
219         assertEquals(orig.mCredentialKey, unparceled2.mCredentialKey);
220         assertEquals(orig.mCredential, unparceled2.mCredential);
221     }
222 
testDeserializeFromJSON()223     public void testDeserializeFromJSON() throws JSONException {
224         final JSONObject json = new JSONObject();
225         json.put(EmailContent.HostAuthColumns.PROTOCOL, "IMAP");
226         json.put(EmailContent.HostAuthColumns.ADDRESS, "dhoff@example.com");
227         json.put(EmailContent.HostAuthColumns.PORT, 1337);
228         json.put(EmailContent.HostAuthColumns.FLAGS, 293847);
229         json.put(EmailContent.HostAuthColumns.LOGIN, "dhoff");
230         json.put(EmailContent.HostAuthColumns.PASSWORD, "daknightrida");
231         json.put(EmailContent.HostAuthColumns.DOMAIN, "example.com");
232         json.put(EmailContent.HostAuthColumns.CLIENT_CERT_ALIAS, "I'm a client cert alias");
233         json.put(HostAuth.JSON_TAG_CREDENTIAL, Credential.EMPTY.toJson());
234 
235         // deserialize the json
236         final HostAuth ha = HostAuth.fromJson(json);
237 
238         // verify that all fields deserialized as expected
239         assertEquals("IMAP", ha.mProtocol);
240         assertEquals("dhoff@example.com", ha.mAddress);
241         assertEquals(1337, ha.mPort);
242         assertEquals(293847, ha.mFlags);
243         assertEquals("dhoff", ha.mLogin);
244         assertEquals("daknightrida", ha.mPassword);
245         assertEquals("example.com", ha.mDomain);
246         assertEquals("I'm a client cert alias", ha.mClientCertAlias);
247         assertEquals(Credential.EMPTY, ha.mCredential);
248 
249         assertNull(ha.mServerCert); // server cert is not serialized; field defaults to null
250         assertEquals(-1, ha.mCredentialKey); // cred key is not serialized; field defaults to -1
251     }
252 
testSerializeAndDeserializeWithJSON()253     public void testSerializeAndDeserializeWithJSON() {
254         final HostAuth before = new HostAuth();
255         before.mProtocol = "IMAP";
256         before.mAddress = "dhoff@example.com";
257         before.mPort = 1337;
258         before.mFlags = 293847;
259         before.setLogin("dhoff", "daknightrida");
260         before.mDomain = "example.com";
261         before.mClientCertAlias = "I'm a client cert alias";
262         before.mServerCert = new byte[] {(byte) 0xFF, (byte) 0xAA};
263         before.mCredentialKey = 9873425;
264         before.mCredential = Credential.EMPTY;
265 
266         // this must be called before serialization occurs
267         before.ensureLoaded(getContext());
268 
269         // serialize and deserialize
270         final HostAuth after = HostAuth.fromJson(before.toJson());
271 
272         assertEquals(before.mProtocol, after.mProtocol);
273         assertEquals(before.mAddress, after.mAddress);
274         assertEquals(before.mPort, after.mPort);
275         assertEquals(before.mFlags, after.mFlags);
276         assertTrue(Arrays.equals(before.getLogin(), after.getLogin()));
277         assertEquals(before.mDomain, after.mDomain);
278         assertEquals(before.mClientCertAlias, after.mClientCertAlias);
279         assertEquals(before.mCredential, after.mCredential);
280 
281         assertNull(after.mServerCert); // server cert is not serialized; field defaults to null
282         assertEquals(-1, after.mCredentialKey); // cred key is not serialized; field defaults to 0
283     }
284 }
285 
286