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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package javax.security.auth;
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;
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
34 * targetName = CredentialClass {PrincipalClass "PrincipalName"}*
37 * First it states a credential class and is followed then by a list of one or
38 * more principals identifying the subject.
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\""
45 * The syntax also allows the use of the wildcard "*" in place of {@code
46 * CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}.
50 public final class PrivateCredentialPermission extends Permission {
52 private static final long serialVersionUID = 5284372143517237068L;
55 private static final String READ = "read";
57 private String credentialClass;
60 private transient int offset;
63 private transient CredOwner[] set;
66 * Creates a new permission for private credentials specified by the target
67 * name {@code name} and an {@code action}. The action is always
71 * the target name of the permission.
73 * the action {@code "read"}.
75 public PrivateCredentialPermission(String name, String action) {
77 if (READ.equalsIgnoreCase(action)) {
80 throw new IllegalArgumentException("Action must be \"read\"");
85 * Creates a {@code PrivateCredentialPermission} from the {@code Credential}
86 * class and set of principals.
88 * @param credentialClass
89 * the credential class name.
91 * the set of principals.
93 PrivateCredentialPermission(String credentialClass, Set<Principal> principals) {
94 super(credentialClass);
95 this.credentialClass = credentialClass;
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)) {
109 set[offset++] = element;
115 * Initialize a PrivateCredentialPermission object and checks that a target
116 * name has a correct format: CredentialClass 1*(PrincipalClass
119 private void initTargetName(String name) {
122 throw new NullPointerException("name == null");
125 // check empty string
127 if (name.isEmpty()) {
128 throw new IllegalArgumentException("name is empty");
131 // get CredentialClass
132 int beg = name.indexOf(' ');
136 credentialClass = name.substring(0, beg);
138 // get a number of pairs: PrincipalClass "PrincipalName"
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);
146 if (i == -1 || j == -1 || name.charAt(i + 1) != '"') {
151 // name MUST have one pair at least
156 beg = name.indexOf(' ');
159 // populate principal set with instances of CredOwner class
160 String principalClass;
161 String principalName;
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);
168 principalClass = name.substring(beg, i);
169 principalName = name.substring(i + 2, j);
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)) {
181 set[offset++] = element;
186 private IllegalArgumentException badSyntax() {
187 throw new IllegalArgumentException("Target name MUST have the following syntax: " +
188 "CredentialClass 1*(PrincipalClass \"PrincipalName\")");
191 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
192 ois.defaultReadObject();
193 initTargetName(getName());
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].
203 * This corresponds to the the target name's syntax:
206 * targetName = CredentialClass {PrincipalClass "PrincipalName"}*
209 * @return the principal classes and names associated with this {@code
210 * PrivateCredentialPermission}.
212 public String[][] getPrincipals() {
214 String[][] s = new String[offset][2];
216 for (int i = 0; i < s.length; i++) {
217 s[i][0] = set[i].principalClass;
218 s[i][1] = set[i].principalName;
224 public String getActions() {
229 * Returns the class name of the credential associated with this permission.
231 * @return the class name of the credential associated with this permission.
233 public String getCredentialClass() {
234 return credentialClass;
238 public int hashCode() {
240 for (int i = 0; i < offset; i++) {
241 hash = hash + set[i].hashCode();
243 return getCredentialClass().hashCode() + hash;
247 public boolean equals(Object obj) {
252 if (obj == null || this.getClass() != obj.getClass()) {
256 PrivateCredentialPermission that = (PrivateCredentialPermission) obj;
258 return credentialClass.equals(that.credentialClass) && (offset == that.offset)
259 && sameMembers(set, that.set, offset);
263 public boolean implies(Permission permission) {
265 if (permission == null || this.getClass() != permission.getClass()) {
269 PrivateCredentialPermission that = (PrivateCredentialPermission) permission;
271 if (!("*".equals(credentialClass) || credentialClass
272 .equals(that.getCredentialClass()))) {
276 if (that.offset == 0) {
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])) {
290 if (j == thatCo.length) {
298 public PermissionCollection newPermissionCollection() {
303 * Returns true if the two arrays have the same length, and every member of
304 * one array is contained in another array
306 private boolean sameMembers(Object[] ar1, Object[] ar2, int length) {
307 if (ar1 == null && ar2 == null) {
310 if (ar1 == null || ar2 == null) {
314 for (int i = 0; i < length; i++) {
316 for (int j = 0; j < length; j++) {
317 if (ar1[i].equals(ar2[j])) {
329 private static final class CredOwner implements Serializable {
331 private static final long serialVersionUID = -5607449830436408266L;
333 String principalClass;
335 String principalName;
337 // whether class name contains wildcards
338 private transient boolean isClassWildcard;
340 // whether pname contains wildcards
341 private transient boolean isPNameWildcard;
343 // Creates a new CredOwner with the specified Principal Class and Principal Name
344 CredOwner(String principalClass, String principalName) {
346 if ("*".equals(principalClass)) {
347 isClassWildcard = true;
350 if ("*".equals(principalName)) {
351 isPNameWildcard = true;
354 if (isClassWildcard && !isPNameWildcard) {
355 throw badPrincipal();
358 this.principalClass = principalClass;
359 this.principalName = principalName;
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");
367 // Checks if this CredOwner implies the specified Object.
368 boolean implies(Object obj) {
373 CredOwner co = (CredOwner) obj;
375 if (isClassWildcard || principalClass.equals(co.principalClass)) {
376 if (isPNameWildcard || principalName.equals(co.principalName)) {
383 // Checks two CredOwner objects for equality.
385 public boolean equals(Object obj) {
386 return principalClass.equals(((CredOwner) obj).principalClass)
387 && principalName.equals(((CredOwner) obj).principalName);
390 // Returns the hash code value for this object.
392 public int hashCode() {
393 return principalClass.hashCode() + principalName.hashCode();