OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / javax / security / auth / PrivateCredentialPermission.java
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 package javax.security.auth;
19
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.Serializable;
23 import java.security.Permission;
24 import java.security.PermissionCollection;
25 import java.security.Principal;
26 import java.util.Set;
27
28 /**
29  * Protects private credential objects belonging to a {@code Subject}. It has
30  * only one action which is "read". The target name of this permission has a
31  * special syntax:
32  *
33  * <pre>
34  * targetName = CredentialClass {PrincipalClass &quot;PrincipalName&quot;}*
35  * </pre>
36  *
37  * First it states a credential class and is followed then by a list of one or
38  * more principals identifying the subject.
39  * <p>
40  * The principals on their part are specified as the name of the {@code
41  * Principal} class followed by the principal name in quotes. For example, the
42  * following file may define permission to read the private credentials of a
43  * principal named "Bob": "com.sun.PrivateCredential com.sun.Principal \"Bob\""
44  * <p>
45  * The syntax also allows the use of the wildcard "*" in place of {@code
46  * CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}.
47  *
48  * @see Principal
49  */
50 public final class PrivateCredentialPermission extends Permission {
51
52     private static final long serialVersionUID = 5284372143517237068L;
53
54     // allowed action
55     private static final String READ = "read";
56
57     private String credentialClass;
58
59     // current offset
60     private transient int offset;
61
62     // owners set
63     private transient CredOwner[] set;
64
65     /**
66      * Creates a new permission for private credentials specified by the target
67      * name {@code name} and an {@code action}. The action is always
68      * {@code "read"}.
69      *
70      * @param name
71      *            the target name of the permission.
72      * @param action
73      *            the action {@code "read"}.
74      */
75     public PrivateCredentialPermission(String name, String action) {
76         super(name);
77         if (READ.equalsIgnoreCase(action)) {
78             initTargetName(name);
79         } else {
80             throw new IllegalArgumentException("Action must be \"read\"");
81         }
82     }
83
84     /**
85      * Creates a {@code PrivateCredentialPermission} from the {@code Credential}
86      * class and set of principals.
87      *
88      * @param credentialClass
89      *            the credential class name.
90      * @param principals
91      *            the set of principals.
92      */
93     PrivateCredentialPermission(String credentialClass, Set<Principal> principals) {
94         super(credentialClass);
95         this.credentialClass = credentialClass;
96
97         set = new CredOwner[principals.size()];
98         for (Principal p : principals) {
99             CredOwner element = new CredOwner(p.getClass().getName(), p.getName());
100             // check for duplicate elements
101             boolean found = false;
102             for (int ii = 0; ii < offset; ii++) {
103                 if (set[ii].equals(element)) {
104                     found = true;
105                     break;
106                 }
107             }
108             if (!found) {
109                 set[offset++] = element;
110             }
111         }
112     }
113
114     /**
115      * Initialize a PrivateCredentialPermission object and checks that a target
116      * name has a correct format: CredentialClass 1*(PrincipalClass
117      * "PrincipalName")
118      */
119     private void initTargetName(String name) {
120
121         if (name == null) {
122             throw new NullPointerException("name == null");
123         }
124
125         // check empty string
126         name = name.trim();
127         if (name.isEmpty()) {
128             throw new IllegalArgumentException("name is empty");
129         }
130
131         // get CredentialClass
132         int beg = name.indexOf(' ');
133         if (beg == -1) {
134             throw badSyntax();
135         }
136         credentialClass = name.substring(0, beg);
137
138         // get a number of pairs: PrincipalClass "PrincipalName"
139         beg++;
140         int count = 0;
141         int nameLength = name.length();
142         for (int i, j = 0; beg < nameLength; beg = j + 2, count++) {
143             i = name.indexOf(' ', beg);
144             j = name.indexOf('"', i + 2);
145
146             if (i == -1 || j == -1 || name.charAt(i + 1) != '"') {
147                 throw badSyntax();
148             }
149         }
150
151         // name MUST have one pair at least
152         if (count < 1) {
153             throw badSyntax();
154         }
155
156         beg = name.indexOf(' ');
157         beg++;
158
159         // populate principal set with instances of CredOwner class
160         String principalClass;
161         String principalName;
162
163         set = new CredOwner[count];
164         for (int index = 0, i, j; index < count; beg = j + 2, index++) {
165             i = name.indexOf(' ', beg);
166             j = name.indexOf('"', i + 2);
167
168             principalClass = name.substring(beg, i);
169             principalName = name.substring(i + 2, j);
170
171             CredOwner element = new CredOwner(principalClass, principalName);
172             // check for duplicate elements
173             boolean found = false;
174             for (int ii = 0; ii < offset; ii++) {
175                 if (set[ii].equals(element)) {
176                     found = true;
177                     break;
178                 }
179             }
180             if (!found) {
181                 set[offset++] = element;
182             }
183         }
184     }
185
186     private IllegalArgumentException badSyntax() {
187         throw new IllegalArgumentException("Target name MUST have the following syntax: " +
188                 "CredentialClass 1*(PrincipalClass \"PrincipalName\")");
189     }
190
191     private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
192         ois.defaultReadObject();
193         initTargetName(getName());
194     }
195
196     /**
197      * Returns the principal's classes and names associated with this {@code
198      * PrivateCredentialPermission} as a two dimensional array. The first
199      * dimension of the array corresponds to the number of principals. The
200      * second dimension defines either the name of the {@code PrincipalClass}
201      * [x][0] or the value of {@code PrincipalName} [x][1].
202      * <p>
203      * This corresponds to the the target name's syntax:
204      *
205      * <pre>
206      * targetName = CredentialClass {PrincipalClass &quot;PrincipalName&quot;}*
207      * </pre>
208      *
209      * @return the principal classes and names associated with this {@code
210      *         PrivateCredentialPermission}.
211      */
212     public String[][] getPrincipals() {
213
214         String[][] s = new String[offset][2];
215
216         for (int i = 0; i < s.length; i++) {
217             s[i][0] = set[i].principalClass;
218             s[i][1] = set[i].principalName;
219         }
220         return s;
221     }
222
223     @Override
224     public String getActions() {
225         return READ;
226     }
227
228     /**
229      * Returns the class name of the credential associated with this permission.
230      *
231      * @return the class name of the credential associated with this permission.
232      */
233     public String getCredentialClass() {
234         return credentialClass;
235     }
236
237     @Override
238     public int hashCode() {
239         int hash = 0;
240         for (int i = 0; i < offset; i++) {
241             hash = hash + set[i].hashCode();
242         }
243         return getCredentialClass().hashCode() + hash;
244     }
245
246     @Override
247     public boolean equals(Object obj) {
248         if (obj == this) {
249             return true;
250         }
251
252         if (obj == null || this.getClass() != obj.getClass()) {
253             return false;
254         }
255
256         PrivateCredentialPermission that = (PrivateCredentialPermission) obj;
257
258         return credentialClass.equals(that.credentialClass) && (offset == that.offset)
259                 && sameMembers(set, that.set, offset);
260     }
261
262     @Override
263     public boolean implies(Permission permission) {
264
265         if (permission == null || this.getClass() != permission.getClass()) {
266             return false;
267         }
268
269         PrivateCredentialPermission that = (PrivateCredentialPermission) permission;
270
271         if (!("*".equals(credentialClass) || credentialClass
272                 .equals(that.getCredentialClass()))) {
273             return false;
274         }
275
276         if (that.offset == 0) {
277             return true;
278         }
279
280         CredOwner[] thisCo = set;
281         CredOwner[] thatCo = that.set;
282         int thisPrincipalsSize = offset;
283         int thatPrincipalsSize = that.offset;
284         for (int i = 0, j; i < thisPrincipalsSize; i++) {
285             for (j = 0; j < thatPrincipalsSize; j++) {
286                 if (thisCo[i].implies(thatCo[j])) {
287                     break;
288                 }
289             }
290             if (j == thatCo.length) {
291                 return false;
292             }
293         }
294         return true;
295     }
296
297     @Override
298     public PermissionCollection newPermissionCollection() {
299         return null;
300     }
301
302     /**
303      * Returns true if the two arrays have the same length, and every member of
304      * one array is contained in another array
305      */
306     private boolean sameMembers(Object[] ar1, Object[] ar2, int length) {
307         if (ar1 == null && ar2 == null) {
308             return true;
309         }
310         if (ar1 == null || ar2 == null) {
311             return false;
312         }
313         boolean found;
314         for (int i = 0; i < length; i++) {
315             found = false;
316             for (int j = 0; j < length; j++) {
317                 if (ar1[i].equals(ar2[j])) {
318                     found = true;
319                     break;
320                 }
321             }
322             if (!found) {
323                 return false;
324             }
325         }
326         return true;
327     }
328
329     private static final class CredOwner implements Serializable {
330
331         private static final long serialVersionUID = -5607449830436408266L;
332
333         String principalClass;
334
335         String principalName;
336
337         // whether class name contains wildcards
338         private transient boolean isClassWildcard;
339
340         // whether pname contains wildcards
341         private transient boolean isPNameWildcard;
342
343         // Creates a new CredOwner with the specified Principal Class and Principal Name
344         CredOwner(String principalClass, String principalName) {
345             super();
346             if ("*".equals(principalClass)) {
347                 isClassWildcard = true;
348             }
349
350             if ("*".equals(principalName)) {
351                 isPNameWildcard = true;
352             }
353
354             if (isClassWildcard && !isPNameWildcard) {
355                 throw badPrincipal();
356             }
357
358             this.principalClass = principalClass;
359             this.principalName = principalName;
360         }
361
362         private IllegalArgumentException badPrincipal() {
363             throw new IllegalArgumentException("invalid syntax: Principal Class can not be a " +
364                     "wildcard (*) value if Principal Name is not a wildcard (*) value");
365         }
366
367         // Checks if this CredOwner implies the specified Object.
368         boolean implies(Object obj) {
369             if (obj == this) {
370                 return true;
371             }
372
373             CredOwner co = (CredOwner) obj;
374
375             if (isClassWildcard || principalClass.equals(co.principalClass)) {
376                 if (isPNameWildcard || principalName.equals(co.principalName)) {
377                     return true;
378                 }
379             }
380             return false;
381         }
382
383         // Checks two CredOwner objects for equality.
384         @Override
385         public boolean equals(Object obj) {
386             return principalClass.equals(((CredOwner) obj).principalClass)
387                     && principalName.equals(((CredOwner) obj).principalName);
388         }
389
390         // Returns the hash code value for this object.
391         @Override
392         public int hashCode() {
393             return principalClass.hashCode() + principalName.hashCode();
394         }
395     }
396 }