1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19 * @author Boris V. Kuznetsov
20 * @version $Revision$
21 */
22
23package org.apache.harmony.security.tests.java.security;
24
25import java.io.ByteArrayInputStream;
26import java.io.ByteArrayOutputStream;
27import java.io.IOException;
28import java.io.InputStream;
29import java.io.PrintStream;
30import java.security.NoSuchAlgorithmException;
31import java.security.Permission;
32import java.security.Provider;
33import java.security.Security;
34import java.security.SecurityPermission;
35import java.security.Provider.Service;
36import java.util.Collection;
37import java.util.ConcurrentModificationException;
38import java.util.HashMap;
39import java.util.Iterator;
40import java.util.Locale;
41import java.util.Set;
42import java.util.Map.Entry;
43
44import junit.framework.TestCase;
45
46/**
47 * Tests for <code>Provider</code> constructor and methods
48 *
49 */
50public class ProviderTest extends TestCase {
51    /*
52     * Implementation note: The algorithm name ASH-1 might seem a bit strange,
53     * but since the algorithms cannot be uninstalled anymore we need to make
54     * sure there are not side-effects on other tests. Simply inserting SHA-1
55     * destroys the existing provider infrastructure.
56     */
57
58    Provider[] storedProviders;
59
60    Provider p;
61
62    /*
63     * @see TestCase#setUp()
64     */
65    protected void setUp() throws Exception {
66        super.setUp();
67
68        storedProviders = Security.getProviders();
69
70        p = new MyProvider();
71    }
72
73    @Override
74    protected void tearDown() throws Exception {
75        p.remove("MessageDigest.ASH-1");
76        p.remove("MessageDigest.abc");
77        p.remove("Alg.Alias.MessageDigest.ASH1");
78
79        for (Provider p: Security.getProviders()) {
80            Security.removeProvider(p.getName());
81        }
82
83        for (Provider p: storedProviders) {
84            Security.addProvider(p);
85        }
86
87        super.tearDown();
88    }
89
90    /*
91     * Class under test for void Provider()
92     */
93    public final void testProvider() {
94        if (!p.getProperty("Provider.id name").equals(
95                String.valueOf(p.getName()))) {
96            fail("Incorrect \"Provider.id name\" value");
97        }
98        if (!p.getProperty("Provider.id version").equals(
99                String.valueOf(p.getVersion()))) {
100            fail("Incorrect \"Provider.id version\" value");
101        }
102        if (!p.getProperty("Provider.id info").equals(
103                String.valueOf(p.getInfo()))) {
104            fail("Incorrect \"Provider.id info\" value");
105        }
106        if (!p.getProperty("Provider.id className").equals(
107                p.getClass().getName())) {
108            fail("Incorrect \"Provider.id className\" value");
109        }
110    }
111
112    public final void testClear() {
113        p.clear();
114        assertNull(p.getProperty("MessageDigest.SHA-1"));
115    }
116
117    /*
118     * Class under test for void Provider(String, double, String)
119     */
120    public final void testProviderStringdoubleString() {
121        Provider p = new MyProvider("Provider name", 123.456, "Provider info");
122        assertEquals("Provider name", p.getName());
123        assertEquals(123.456, p.getVersion(), 0L);
124        assertEquals("Provider info", p.getInfo());
125    }
126
127    public final void testGetName() {
128        assertEquals("MyProvider", p.getName());
129    }
130
131    public final void testGetVersion() {
132        assertEquals(1.0, p.getVersion(), 0L);
133    }
134
135    public final void testGetInfo() {
136        assertEquals("Provider for testing", p.getInfo());
137    }
138
139    /*
140     * Class under test for void putAll(Map)
141     */
142    public final void testPutAllMap() {
143        HashMap hm = new HashMap();
144        hm.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
145        hm.put("Property 1", "value 1");
146        hm.put("serviceName.algName attrName", "attrValue");
147        hm.put("Alg.Alias.engineClassName.aliasName", "standardName");
148        p.putAll(hm);
149        if (!"value 1".equals(p.getProperty("Property 1").trim()) ||
150                !"attrValue".equals(p.getProperty("serviceName.algName attrName").trim()) ||
151                !"standardName".equals(p.getProperty("Alg.Alias.engineClassName.aliasName").trim()) ||
152                !"aaa.bbb.ccc.ddd".equals(p.getProperty("MessageDigest.SHA-1").trim()) ) {
153            fail("Incorrect property value");
154        }
155    }
156
157    /*
158     * Class under test for Set entrySet()
159     */
160    public final void testEntrySet() {
161        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
162
163        Set s = p.entrySet();
164        try {
165            s.clear();
166            fail("Must return unmodifiable set");
167        } catch (UnsupportedOperationException e) {
168        }
169
170        assertEquals("Incorrect set size", 8, s.size());
171
172        for (Iterator it = s.iterator(); it.hasNext();) {
173            Entry e = (Entry)it.next();
174            String key = (String)e.getKey();
175            String val = (String)e.getValue();
176            if (key.equals("MessageDigest.SHA-1") && val.equals("SomeClassName")) {
177                continue;
178            }
179            if (key.equals("Alg.Alias.MessageDigest.SHA1") && val.equals("SHA-1")) {
180                continue;
181            }
182            if (key.equals("MessageDigest.abc") && val.equals("SomeClassName")) {
183                continue;
184            }
185            if (key.equals("Provider.id className") && val.equals(p.getClass().getName())) {
186                continue;
187            }
188            if (key.equals("Provider.id name") && val.equals("MyProvider")) {
189                continue;
190            }
191            if (key.equals("MessageDigest.SHA-256") && val.equals("aaa.bbb.ccc.ddd")) {
192                continue;
193            }
194            if (key.equals("Provider.id version") && val.equals("1.0")) {
195                continue;
196            }
197            if (key.equals("Provider.id info") && val.equals("Provider for testing")) {
198                continue;
199            }
200            fail("Incorrect set");
201        }
202    }
203
204    public final void testForEach() {
205        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
206        p.put("MessageDigest.abc", "value 1");
207
208        HashMap<String, String> hm = new HashMap<>();
209        p.forEach((k,v)-> hm.put((String)k, (String)v));
210
211        assertEquals(p.size(), hm.size());
212        for(String key : hm.keySet()) {
213          assertEquals(p.get(key), hm.get(key));
214        }
215    }
216
217    public void testForEachNPE() throws Exception {
218        try {
219            p.forEach(null);
220            fail();
221        } catch(NullPointerException expected) {}
222    }
223
224    public void testForEachCME() throws Exception {
225        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
226        p.put("MessageDigest.abc", "value 1");
227        try {
228            p.forEach(new java.util.function.BiConsumer<Object, Object>() {
229                    @Override
230                    public void accept(Object k, Object v) {p.put("foo", "bar");}
231                });
232            fail();
233        } catch(ConcurrentModificationException expected) {}
234    }
235
236    /*
237     * Class under test for Set keySet()
238     */
239    public final void testKeySet() {
240        p.put("MessageDigest.SHA-256", "aaa.bbb.ccc.ddd");
241
242        Set<Object> s = p.keySet();
243        try {
244            s.clear();
245        } catch (UnsupportedOperationException e) {
246        }
247        Set s1 = p.keySet();
248
249        assertNotSame(s, s1);
250        assertFalse(s1.isEmpty());
251        assertEquals(8, s1.size());
252
253        assertTrue(s1.contains("MessageDigest.SHA-256"));
254        assertTrue(s1.contains("MessageDigest.SHA-1"));
255        assertTrue(s1.contains("Alg.Alias.MessageDigest.SHA1"));
256        assertTrue(s1.contains("MessageDigest.abc"));
257        assertTrue(s1.contains("Provider.id info"));
258        assertTrue(s1.contains("Provider.id className"));
259        assertTrue(s1.contains("Provider.id version"));
260        assertTrue(s1.contains("Provider.id name"));
261    }
262
263    /*
264     * Class under test for Collection values()
265     */
266    public final void testValues() {
267        p.put("MessageDigest.ASH-256", "aaa.bbb.ccc.ddd");
268
269        Collection<Object> c = p.values();
270        try {
271            c.clear();
272        } catch (UnsupportedOperationException e) {
273        }
274        Collection c1 = p.values();
275
276        assertNotSame(c, c1);
277        assertFalse(c1.isEmpty());
278        assertEquals(8, c1.size());
279
280        assertTrue(c1.contains("MyProvider"));
281        assertTrue(c1.contains("aaa.bbb.ccc.ddd"));
282        assertTrue(c1.contains("Provider for testing"));
283        assertTrue(c1.contains("1.0"));
284        assertTrue(c1.contains("SomeClassName"));
285        assertTrue(c1.contains("SHA-1"));
286        assertTrue(c1.contains(p.getClass().getName()));
287    }
288
289    /*
290     * Class under test for Object put(Object, Object)
291     */
292    public final void testPutObjectObject() {
293        p.put("MessageDigest.SHA-1", "aaa.bbb.ccc.ddd");
294        p.put("Type.Algorithm", "className");
295        assertEquals("aaa.bbb.ccc.ddd", p.getProperty("MessageDigest.SHA-1")
296                .trim());
297
298        Set services = p.getServices();
299        assertEquals(3, services.size());
300
301        for (Iterator it = services.iterator(); it.hasNext();) {
302            Provider.Service s = (Provider.Service)it.next();
303            if ("Type".equals(s.getType()) &&
304                    "Algorithm".equals(s.getAlgorithm()) &&
305                    "className".equals(s.getClassName())) {
306                continue;
307            }
308            if ("MessageDigest".equals(s.getType()) &&
309                    "SHA-1".equals(s.getAlgorithm()) &&
310                    "aaa.bbb.ccc.ddd".equals(s.getClassName())) {
311                continue;
312            }
313            if ("MessageDigest".equals(s.getType()) &&
314                    "abc".equals(s.getAlgorithm()) &&
315                    "SomeClassName".equals(s.getClassName())) {
316                continue;
317            }
318            fail("Incorrect service");
319        }
320    }
321
322    /*
323     * Class under test for Object remove(Object)
324     */
325    public final void testRemoveObject() {
326        Object o = p.remove("MessageDigest.SHA-1");
327
328        assertEquals("SomeClassName", o);
329        assertNull(p.getProperty("MessageDigest.SHA-1"));
330        assertEquals(1, p.getServices().size());
331    }
332
333    public final void testService1() {
334        p.put("MessageDigest.SHA-1", "AnotherClassName");
335        Provider.Service s = p.getService("MessageDigest", "SHA-1");
336        assertEquals("AnotherClassName", s.getClassName());
337    }
338
339    public final void testGetServiceCaseSensitivity() {
340        p.put("i.I", "foo");
341
342        Locale defaultLocale = Locale.getDefault();
343        Locale.setDefault(new Locale("tr", "TR"));
344        try {
345            assertEquals("foo", p.getService("i", "i").getClassName());
346            assertEquals("foo", p.getService("i", "I").getClassName());
347            assertNull(p.getService("\u0130", "\u0130")); // Turkish dotless i and dotted I
348            assertNull(p.getService("\u0131", "\u0131"));
349        } finally {
350            Locale.setDefault(defaultLocale);
351        }
352    }
353
354    // Regression for HARMONY-2760.
355    public void testConstructor() {
356        MyProvider myProvider = new MyProvider(null, 1, null);
357        assertNull(myProvider.getName());
358        assertNull(myProvider.getInfo());
359        assertEquals("null", myProvider.getProperty("Provider.id name"));
360        assertEquals("null", myProvider.getProperty("Provider.id info"));
361    }
362
363    class MyProvider extends Provider {
364        MyProvider() {
365            super("MyProvider", 1.0, "Provider for testing");
366            put("MessageDigest.SHA-1", "SomeClassName");
367            put("MessageDigest.abc", "SomeClassName");
368            put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
369        }
370
371        MyProvider(String name, double version, String info) {
372            super(name, version, info);
373        }
374
375        // BEGIN android-added
376        public void putService(Provider.Service s) {
377            super.putService(s);
378        }
379        // END android-added
380
381        // BEGIN android-added
382        public void removeService(Provider.Service s) {
383            super.removeService(s);
384        }
385        // END android-added
386
387        // BEGIN android-added
388        public int getNumServices() {
389            return getServices().size();
390        }
391        // END android-added
392    }
393
394    // BEGIN android-added
395    public final void testService2() {
396        Provider[] pp = Security.getProviders("MessageDigest.ASH-1");
397        if (pp == null) {
398            return;
399        }
400        Provider p2 = pp[0];
401        String old = p2.getProperty("MessageDigest.ASH-1");
402        p2.put("MessageDigest.ASH-1", "AnotherClassName");
403        Provider.Service s = p2.getService("MessageDigest", "ASH-1");
404        if (!"AnotherClassName".equals(s.getClassName())) {
405            fail("Incorrect class name " + s.getClassName());
406        }
407        try {
408            s.newInstance(null);
409            fail("No expected NoSuchAlgorithmException");
410        } catch (NoSuchAlgorithmException e) {
411        }
412    }
413    // END android-added
414
415    // BEGIN android-added
416    public final void testGetServices() {
417        MyProvider myProvider = new MyProvider(null, 1, null);
418        Set<Provider.Service> services = myProvider.getServices();
419        assertEquals(0, services.size());
420
421        Provider.Service s[] = new Provider.Service[3];
422
423        s[0] = new Provider.Service(myProvider, "type1", "algorithm1", "className1",
424                null, null);
425        s[1] = new Provider.Service(myProvider, "type2", "algorithm2", "className2",
426                null, null);
427        s[2] = new Provider.Service(myProvider, "type3", "algorithm3", "className3",
428                null, null);
429        myProvider.putService(s[0]);
430        myProvider.putService(s[1]);
431        assertEquals(2, myProvider.getNumServices());
432        Set<Service> actual = myProvider.getServices();
433
434        assertTrue(actual.contains(s[0]));
435        assertTrue(actual.contains(s[1]));
436        assertTrue(!actual.contains(s[2]));
437
438        myProvider.removeService(s[1]);
439        actual = myProvider.getServices();
440        assertEquals(1, myProvider.getNumServices());
441
442        assertTrue(actual.contains(s[0]));
443        assertTrue(!actual.contains(s[1]));
444        assertTrue(!actual.contains(s[2]));
445
446        myProvider.putService(s[2]);
447        actual = myProvider.getServices();
448        assertEquals(2, myProvider.getNumServices());
449        assertTrue(actual.contains(s[0]));
450        assertTrue(!actual.contains(s[1]));
451        assertTrue(actual.contains(s[2]));
452    }
453    // END android-added
454
455    // BEGIN android-added
456    public final void testPutService() {
457        MyProvider myProvider = new MyProvider(null, 1, null);
458        Provider.Service s[] = new Provider.Service[3];
459
460        s[0] = new Provider.Service(myProvider, "type1", "algorithm1", "className1",
461                null, null);
462        s[1] = new Provider.Service(myProvider, "type2", "algorithm2", "className2",
463                null, null);
464        s[2] = new Provider.Service(myProvider, "type3", "algorithm3", "className3",
465                null, null);
466        myProvider.putService(s[0]);
467        myProvider.putService(s[1]);
468        assertEquals(2, myProvider.getNumServices());
469        Set<Service> actual = myProvider.getServices();
470
471        assertTrue(actual.contains(s[0]));
472        assertTrue(actual.contains(s[1]));
473        assertTrue(!actual.contains(s[2]));
474
475        myProvider.removeService(s[1]);
476        assertEquals(1, myProvider.getNumServices());
477        actual = myProvider.getServices();
478
479        assertTrue(actual.contains(s[0]));
480        assertTrue(!actual.contains(s[1]));
481        assertTrue(!actual.contains(s[2]));
482
483        myProvider.putService(s[2]);
484        actual = myProvider.getServices();
485        assertEquals(2, myProvider.getNumServices());
486        assertTrue(actual.contains(s[0]));
487        assertTrue(!actual.contains(s[1]));
488        assertTrue(actual.contains(s[2]));
489
490        myProvider.putService(s[2]);
491        actual = myProvider.getServices();
492        assertEquals(2, myProvider.getNumServices());
493        assertTrue(actual.contains(s[0]));
494        assertTrue(!actual.contains(s[1]));
495        assertTrue(actual.contains(s[2]));
496
497        try {
498            myProvider.putService(null);
499            fail("NullPointerException expected");
500        } catch (NullPointerException e) {
501            // expected
502        }
503    }
504    // END android-added
505
506    // BEGIN android-added
507    public final void testRemoveService() {
508        MyProvider myProvider = new MyProvider(null, 1, null);
509        try {
510            myProvider.removeService(null);
511            fail("NullPoiterException expected");
512        } catch (NullPointerException e) {
513            // expected
514        }
515
516        Provider.Service s[] = new Provider.Service[3];
517
518        s[0] = new Provider.Service(myProvider, "type0", "algorithm0", "className0",
519                null, null);
520        s[1] = new Provider.Service(myProvider, "type1", "algorithm1", "className1",
521                null, null);
522        s[2] = new Provider.Service(myProvider, "type2", "algorithm2", "className2",
523                null, null);
524
525        try {
526            myProvider.removeService(s[0]);
527        } catch (NullPointerException e) {
528            fail("Unexpected exception");
529        }
530
531        myProvider.putService(s[0]);
532        myProvider.putService(s[1]);
533        myProvider.putService(s[2]);
534        assertEquals(3, myProvider.getNumServices());
535        Set<Service> actual = myProvider.getServices();
536
537        assertTrue(actual.contains(s[0]));
538        assertTrue(actual.contains(s[1]));
539        assertTrue(actual.contains(s[2]));
540
541        myProvider.removeService(s[1]);
542        assertEquals(2, myProvider.getNumServices());
543        actual = myProvider.getServices();
544
545        assertTrue(actual.contains(s[0]));
546        assertTrue(!actual.contains(s[1]));
547        assertTrue(actual.contains(s[2]));
548
549        myProvider.removeService(s[0]);
550        assertEquals(1, myProvider.getNumServices());
551        actual = myProvider.getServices();
552
553        assertTrue(!actual.contains(s[0]));
554        assertTrue(!actual.contains(s[1]));
555        assertTrue(actual.contains(s[2]));
556
557        myProvider.removeService(s[2]);
558        assertEquals(0, myProvider.getNumServices());
559        actual = myProvider.getServices();
560
561        assertTrue(!actual.contains(s[0]));
562        assertTrue(!actual.contains(s[1]));
563        assertTrue(!actual.contains(s[2]));
564
565        try {
566            myProvider.removeService(null);
567            fail("NullPoiterException expected");
568        } catch (NullPointerException e) {
569            // expected
570        }
571    }
572    // END android-added
573
574    // BEGIN android-added
575    public final void testLoad() throws IOException {
576        InputStream is = new ByteArrayInputStream(writeProperties());
577        MyProvider myProvider = new MyProvider("name", 1, "info");
578        myProvider.load(is);
579        assertEquals("tests.security", myProvider.get("test.pkg"));
580        assertEquals("Unit Tests", myProvider.get("test.proj"));
581        assertNull(myProvider.get("#commented.entry"));
582
583        assertEquals("info", myProvider.get("Provider.id info"));
584        String className = myProvider.getClass().toString();
585        assertEquals(
586                className.substring("class ".length(), className.length()),
587                myProvider.get("Provider.id className"));
588        assertEquals("1.0", myProvider.get("Provider.id version"));
589
590        try {
591            myProvider.load((InputStream) null);
592            fail("NullPointerException expected");
593        } catch (NullPointerException e) {
594            // expected
595        }
596    }
597    // END android-added
598
599    // BEGIN android-added
600    public final void testLoad2() {
601        class TestInputStream extends InputStream {
602            @Override
603            public int read() throws IOException {
604                throw new IOException();
605            }
606        }
607
608        MyProvider p = new MyProvider();
609        try {
610            p.load(new TestInputStream());
611            fail("expected IOException");
612        } catch (IOException e) {
613            // expected
614        }
615    }
616    // END android-added
617
618    // BEGIN android-added
619    protected byte[] writeProperties() {
620        ByteArrayOutputStream bout = new ByteArrayOutputStream();
621        PrintStream ps = new PrintStream(bout);
622        ps.println("#commented.entry=Bogus");
623        ps.println("test.pkg=tests.security");
624        ps.println("test.proj=Unit Tests");
625        ps.close();
626        return bout.toByteArray();
627    }
628    // END android-added
629
630    // BEGIN android-added
631    static class TestSecurityManager extends SecurityManager {
632        boolean called = false;
633        private final String permissionName;
634
635        public TestSecurityManager(String permissionName) {
636            this.permissionName = permissionName;
637        }
638
639        @Override
640        public void checkPermission(Permission permission) {
641            if (permission instanceof SecurityPermission) {
642                if (permissionName.equals(permission.getName())) {
643                    called = true;
644                }
645            }
646        }
647    }
648    // END android-added
649}
650