001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Alexey V. Varlamov
020: * @version $Revision$
021: */package java.security;
022:
023: import java.io.ByteArrayInputStream;
024: import java.io.IOException;
025: import java.io.InvalidObjectException;
026: import java.io.NotSerializableException;
027: import java.io.ObjectInputStream;
028: import java.io.ObjectOutputStream;
029: import java.io.ObjectStreamField;
030: import java.io.Serializable;
031: import java.security.cert.Certificate;
032: import java.security.cert.CertificateEncodingException;
033: import java.security.cert.CertificateException;
034: import java.security.cert.CertificateFactory;
035: import java.util.ArrayList;
036: import java.util.List;
037:
038: import org.apache.harmony.security.fortress.PolicyUtils;
039: import org.apache.harmony.security.internal.nls.Messages;
040:
041: /**
042: * Holds permissions which are of an unknown type when a policy file is read.
043: *
044: * Technically, the resolution of UnresolvedPermissions and
045: * substitution by actual permissions takes place in the
046: * <code>implies()</code> method of a <code>Permissions</code>
047: * collection, right before actual checking.
048: *
049: */
050: public final class UnresolvedPermission extends Permission implements
051: Serializable {
052:
053: /**
054: * @com.intel.drl.spec_ref
055: */
056: private static final long serialVersionUID = -4821973115467008846L;
057:
058: private String type;
059:
060: private String name;
061:
062: private String actions;
063:
064: // The signer certificates
065: private transient Certificate[] targetCerts;
066:
067: // Cached hash value
068: private transient int hash;
069:
070: /**
071: * Constructs a new instance of this class with its type, name, and
072: * certificates set to the arguments by definition, actions are ignored
073: *
074: * @param type
075: * class of permission object
076: * @param name
077: * identifies the permission that could not be resolved
078: * @param actions
079: * @param certs
080: */
081: public UnresolvedPermission(String type, String name,
082: String actions, Certificate[] certs) {
083: super (type);
084: checkType(type);
085: this .type = type;
086: this .name = name;
087: this .actions = actions;
088: if (certs != null && certs.length != 0) {
089: //TODO filter non-signer certificates ???
090: List tmp = new ArrayList();
091: for (int i = 0; i < certs.length; i++) {
092: if (certs[i] != null) {
093: tmp.add(certs[i]);
094: }
095: }
096: if (tmp.size() != 0) {
097: targetCerts = (Certificate[]) tmp
098: .toArray(new Certificate[tmp.size()]);
099: }
100: }
101: hash = 0;
102: }
103:
104: // Check type parameter
105: private final void checkType(String type) {
106: if (type == null) {
107: throw new NullPointerException(Messages
108: .getString("security.2F")); //$NON-NLS-1$
109: }
110:
111: // type is the class name of the Permission class.
112: // Empty string is inappropriate for class name.
113: // But this check is commented out for compatibility with RI.
114: // see JIRA issue HARMONY-733
115: // if (type.length() == 0) {
116: // throw new IllegalArgumentException("type cannot be empty");
117: // }
118: }
119:
120: /**
121: * Compares the argument to the receiver, and answers true if they represent
122: * the <em>same</em> object using a class specific comparison. In this
123: * case, the receiver and the object must have the same class, permission
124: * name, actions, and certificates
125: *
126: * @param obj
127: * the object to compare with this object
128: * @return <code>true</code> if the object is the same as this object,
129: * <code>false</code> otherwise.
130: *
131: * @see #hashCode
132: */
133: public boolean equals(Object obj) {
134: if (obj == this ) {
135: return true;
136: }
137: if (obj instanceof UnresolvedPermission) {
138: UnresolvedPermission that = (UnresolvedPermission) obj;
139: if (getName().equals(that.getName())
140: && (name == null ? that.name == null : name
141: .equals(that.name))
142: && (actions == null ? that.actions == null
143: : actions.equals(that.actions))
144: && (PolicyUtils.matchSubset(targetCerts,
145: that.targetCerts) && PolicyUtils
146: .matchSubset(that.targetCerts, targetCerts))) {
147: return true;
148: }
149: }
150: return false;
151: }
152:
153: /**
154: * Answers an integer hash code for the receiver. Any two objects which
155: * answer <code>true</code> when passed to <code>equals</code> must
156: * answer the same value for this method.
157: *
158: * @return the receiver's hash
159: *
160: * @see #equals
161: */
162: public int hashCode() {
163: if (hash == 0) {
164: hash = getName().hashCode();
165: if (name != null) {
166: hash ^= name.hashCode();
167: }
168: if (actions != null) {
169: hash ^= actions.hashCode();
170: }
171: }
172: return hash;
173: }
174:
175: /**
176: * Answers the actions associated with the receiver. Since
177: * UnresolvedPermission objects have no actions, answer the empty string.
178: *
179: * @return the actions associated with the receiver.
180: */
181: public String getActions() {
182: return ""; //$NON-NLS-1$
183: }
184:
185: /**
186: * @com.intel.drl.spec_ref
187: */
188: public String getUnresolvedName() {
189: return name;
190: }
191:
192: /**
193: * @com.intel.drl.spec_ref
194: */
195: public String getUnresolvedActions() {
196: return actions;
197: }
198:
199: /**
200: * @com.intel.drl.spec_ref
201: */
202: public String getUnresolvedType() {
203: return super .getName();
204: }
205:
206: /**
207: * @com.intel.drl.spec_ref
208: */
209: public Certificate[] getUnresolvedCerts() {
210: if (targetCerts != null) {
211: Certificate[] certs = new Certificate[targetCerts.length];
212: System.arraycopy(targetCerts, 0, certs, 0, certs.length);
213: return certs;
214: }
215: return null;
216: }
217:
218: /**
219: * Indicates whether the argument permission is implied by the
220: * receiver. UnresolvedPermission objects imply nothing
221: * because nothing is known about them yet.
222: *
223: * Before actual implication checking, this method tries to
224: * resolve UnresolvedPermissions (if any) against the passed
225: * instance. Successfully resolved permissions (if any) are
226: * taken into account during further processing.
227: *
228: * @param permission
229: * the permission to check
230: * @return always replies false
231: */
232: public boolean implies(Permission permission) {
233: return false;
234: }
235:
236: /**
237: * Answers a string containing a concise, human-readable description of the
238: * receiver.
239: *
240: * @return a printable representation for the receiver.
241: */
242: public String toString() {
243: return "(unresolved " + type + " " + name + " " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
244: + actions + ")"; //$NON-NLS-1$
245: }
246:
247: /**
248: * Answers a new PermissionCollection for holding permissions of this class.
249: * Answer null if any permission collection can be used.
250: *
251: * @return a new PermissionCollection or null
252: *
253: * @see java.security.BasicPermissionCollection
254: */
255: public PermissionCollection newPermissionCollection() {
256: return new UnresolvedPermissionCollection();
257: }
258:
259: /**
260: * Tries to resolve this permission into the specified class. It is assumed
261: * that the class has a proper name (as returned by <code>getName()</code>
262: * of this unresolved permission), so no check is performed to verify this.
263: * However, the class must have all required certificates (as per
264: * <code>getUnresolvedCerts()</code>) among the passed collection of
265: * signers. If it does, a zero, one, and/or two-argument constructor is
266: * tried to instantiate a new permission, which is then returned. <br>
267: * If an appropriate constructor is not available or the class is
268: * improperly signed, <code>null</code> is returned.
269: *
270: * @param targetType - a target class instance, must not be
271: * <code>null</code>
272: * @param signers - actual signers of the targetType
273: * @return resolved permission or null
274: */
275: Permission resolve(Class targetType) {
276: // check signers at first
277: if (PolicyUtils.matchSubset(targetCerts, targetType
278: .getSigners())) {
279: try {
280: return PolicyUtils.instantiatePermission(targetType,
281: name, actions);
282: } catch (Exception ignore) {
283: //TODO log warning?
284: }
285: }
286: return null;
287: }
288:
289: /**
290: * @com.intel.drl.spec_ref
291: *
292: * Outputs <code>type</code>,<code>name</code>,<code>actions</code>
293: * fields via default mechanism; next manually writes certificates in the
294: * following format: <br>
295: *
296: * <ol>
297: * <li> int : number of certs or zero </li>
298: * <li> each cert in the following format
299: * <ol>
300: * <li> String : certificate type </li>
301: * <li> int : length in bytes of certificate </li>
302: * <li> byte[] : certificate encoding </li>
303: * </ol>
304: * </li>
305: * </ol>
306: *
307: * @see <a href="http://java.sun.com/j2se/1.5.0/docs/api/serialized-form.html#java.security.UnresolvedPermission">Java Spec</a>
308: */
309: private void writeObject(ObjectOutputStream out) throws IOException {
310: out.defaultWriteObject();
311: if (targetCerts == null) {
312: out.writeInt(0);
313: } else {
314: out.writeInt(targetCerts.length);
315: for (int i = 0; i < targetCerts.length; i++) {
316: try {
317: byte[] enc = targetCerts[i].getEncoded();
318: out.writeUTF(targetCerts[i].getType());
319: out.writeInt(enc.length);
320: out.write(enc);
321: } catch (CertificateEncodingException cee) {
322: throw ((IOException) new NotSerializableException(
323: Messages.getString("security.30", //$NON-NLS-1$
324: targetCerts[i])).initCause(cee));
325: }
326: }
327: }
328: }
329:
330: /**
331: * @com.intel.drl.spec_ref
332: *
333: * Reads the object from stream and checks target type for validity.
334: */
335: private void readObject(ObjectInputStream in) throws IOException,
336: ClassNotFoundException {
337: in.defaultReadObject();
338: checkType(getUnresolvedType());
339: int certNumber = in.readInt();
340: if (certNumber != 0) {
341: targetCerts = new Certificate[certNumber];
342: for (int i = 0; i < certNumber; i++) {
343: try {
344: String type = in.readUTF();
345: int length = in.readInt();
346: byte[] enc = new byte[length];
347: in.readFully(enc, 0, length);
348: targetCerts[i] = CertificateFactory.getInstance(
349: type).generateCertificate(
350: new ByteArrayInputStream(enc));
351: } catch (CertificateException cee) {
352: throw ((IOException) new IOException(Messages
353: .getString("security.32")).initCause(cee)); //$NON-NLS-1$
354: }
355: }
356: }
357: }
358: }
|