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