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
18package org.apache.harmony.javax.security.auth;
19
20import java.security.DomainCombiner;
21import java.security.Principal;
22import java.security.ProtectionDomain;
23import java.util.Set;
24
25/**
26 * Merges permissions based on code source and code signers with permissions
27 * granted to the specified {@link Subject}.
28 */
29public class SubjectDomainCombiner implements DomainCombiner {
30
31    // subject to be associated
32    private Subject subject;
33
34    // permission required to get a subject object
35    private static final AuthPermission _GET = new AuthPermission(
36            "getSubjectFromDomainCombiner"); //$NON-NLS-1$
37
38    /**
39     * Creates a domain combiner for the entity provided in {@code subject}.
40     *
41     * @param subject
42     *            the entity to which this domain combiner is associated.
43     */
44    public SubjectDomainCombiner(Subject subject) {
45        super();
46        if (subject == null) {
47            throw new NullPointerException();
48        }
49        this.subject = subject;
50    }
51
52    /**
53     * Returns the entity to which this domain combiner is associated.
54     *
55     * @return the entity to which this domain combiner is associated.
56     */
57    public Subject getSubject() {
58        SecurityManager sm = System.getSecurityManager();
59        if (sm != null) {
60            sm.checkPermission(_GET);
61        }
62
63        return subject;
64    }
65
66    /**
67     * Merges the {@code ProtectionDomain} with the {@code Principal}s
68     * associated with the subject of this {@code SubjectDomainCombiner}.
69     *
70     * @param currentDomains
71     *            the {@code ProtectionDomain}s associated with the context of
72     *            the current thread. The domains must be sorted according to
73     *            the execution order, the most recent residing at the
74     *            beginning.
75     * @param assignedDomains
76     *            the {@code ProtectionDomain}s from the parent thread based on
77     *            code source and signers.
78     * @return a single {@code ProtectionDomain} array computed from the two
79     *         provided arrays, or {@code null}.
80     * @see ProtectionDomain
81     */
82    public ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
83            ProtectionDomain[] assignedDomains) {
84        // get array length for combining protection domains
85        int len = 0;
86        if (currentDomains != null) {
87            len += currentDomains.length;
88        }
89        if (assignedDomains != null) {
90            len += assignedDomains.length;
91        }
92        if (len == 0) {
93            return null;
94        }
95
96        ProtectionDomain[] pd = new ProtectionDomain[len];
97
98        // for each current domain substitute set of principal with subject's
99        int cur = 0;
100        if (currentDomains != null) {
101
102            Set<Principal> s = subject.getPrincipals();
103            Principal[] p = s.toArray(new Principal[s.size()]);
104
105            for (cur = 0; cur < currentDomains.length; cur++) {
106                if (currentDomains[cur] != null) {
107                    ProtectionDomain newPD;
108                    newPD = new ProtectionDomain(currentDomains[cur].getCodeSource(),
109                            currentDomains[cur].getPermissions(), currentDomains[cur]
110                                    .getClassLoader(), p);
111                    pd[cur] = newPD;
112                }
113            }
114        }
115
116        // copy assigned domains
117        if (assignedDomains != null) {
118            System.arraycopy(assignedDomains, 0, pd, cur, assignedDomains.length);
119        }
120
121        return pd;
122    }
123}
124