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
17package com.android.emailcommon.provider;
18
19import android.os.Parcel;
20import android.test.AndroidTestCase;
21import android.test.mock.MockContext;
22import android.test.suitebuilder.annotation.SmallTest;
23
24import org.json.JSONException;
25import org.json.JSONObject;
26
27import 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
34public class HostAuthTests extends AndroidTestCase {
35
36    /**
37     * Test user name and password are set correctly
38     */
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     */
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     */
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
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
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
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
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