PrivateCredentialPermission.java 12 KB

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