|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 package com.nokia.mj.impl.security.midp.common; |
|
19 |
|
20 import com.nokia.mj.impl.utils.Tokenizer; |
|
21 import com.nokia.mj.impl.security.utils.Logger; |
|
22 import com.nokia.mj.impl.security.packageprotection.PackageNames; |
|
23 |
|
24 import java.util.Hashtable; |
|
25 import java.util.Enumeration; |
|
26 import java.util.Vector; |
|
27 |
|
28 /** |
|
29 * This class reads the security extensions from the extensions |
|
30 * deployment packages. |
|
31 * |
|
32 * A security extension is a group of permissions and their usage |
|
33 * with regard to protection domains, function groups and security |
|
34 * prompt texts. |
|
35 * |
|
36 * Security extensions are contained into the extensions ODC files |
|
37 * as system properties, as follows: |
|
38 * -Dcom.nokia.mj.addon.protected.<odcname>=<comma separated list |
|
39 * of protected packages> |
|
40 * -Dcom.nokia.mj.addon.restricted.<odcname>=<comma separated list |
|
41 * of restricted packages> |
|
42 * -Dcom.nokia.mj.addon.permissions.<odcname>=<";" separated list |
|
43 * of permission mappings> |
|
44 * -Dcom.nokia.mj.addon.policies.<odcname>=<";" separated list |
|
45 * of policies file names> |
|
46 * where: |
|
47 * <odcname> is always the odc filename without path and extension |
|
48 * <permission mappings> has following syntax: |
|
49 * <named-permission>","<permission-class-name>","<taget>","<actionList> |
|
50 * |
|
51 * This class validates the security extensions and discards the invalid |
|
52 * elements of the security extension by writing a WARNING log entry into |
|
53 * JavaSecurity.log |
|
54 */ |
|
55 public final class SecurityExtensionsReader |
|
56 { |
|
57 /** |
|
58 * The extensions of the ODC file containing the security |
|
59 * extensions definitions |
|
60 */ |
|
61 public final static String POLICIES_SEPARATOR = ""; |
|
62 |
|
63 /** |
|
64 * The extensions of the ODC file containing the security |
|
65 * extensions definitions |
|
66 */ |
|
67 private final static String ODC_EXTENSIONS = ".odc"; |
|
68 |
|
69 /** |
|
70 * The names of the system properties defining the |
|
71 * security extension |
|
72 */ |
|
73 private final static String PROTECTED_PACKAGE_PROPERTY = "com.nokia.mj.addon.protected."; |
|
74 private final static String RESTRICTED_PACKAGE_PROPERTY = "com.nokia.mj.addon.restricted."; |
|
75 private final static String PERMISSION_MAPPINGS_PROPERTY = "com.nokia.mj.addon.permissions."; |
|
76 private final static String SECURITY_POLICIES_PROPERTY = "com.nokia.mj.addon.policies."; |
|
77 |
|
78 /** |
|
79 * The allowed locations for the security extensions policies |
|
80 */ |
|
81 private final static String ALLOWED_POLICY_FILE_LOCATION1 = "c:\\resource\\"; |
|
82 private final static String ALLOWED_POLICY_FILE_LOCATION2 = "c:/resource/"; |
|
83 |
|
84 /** |
|
85 * Internal data members |
|
86 */ |
|
87 private static final int PROTECTED_PACKAGES = 1; |
|
88 private static final int RESTRICTED_PACKAGES = 2; |
|
89 private static Vector extProtectedPackageNames = new Vector(); |
|
90 private static Vector extRestrictedPackageNames = new Vector(); |
|
91 private static Vector extPoliciesFileNames = new Vector(); |
|
92 private static Hashtable extPermissionMappings = new Hashtable(); |
|
93 |
|
94 /** |
|
95 * Boolean used in lazy initialization: the system properties |
|
96 * are read only once when they are needed for the first time |
|
97 */ |
|
98 private static boolean initialized = false; |
|
99 |
|
100 |
|
101 /** |
|
102 * Retrieves the names of all the installed security extensions |
|
103 */ |
|
104 public static Vector getExtPoliciesFileNames() |
|
105 { |
|
106 lazyInit(); |
|
107 return extPoliciesFileNames; |
|
108 } |
|
109 |
|
110 /** |
|
111 * Retrieves the names of all the protected packages brought in by |
|
112 * security extensions |
|
113 */ |
|
114 public static Vector getExtProtectedPackages() |
|
115 { |
|
116 lazyInit(); |
|
117 return extProtectedPackageNames; |
|
118 } |
|
119 |
|
120 /** |
|
121 * Retrieves the names of all the restricted packages brought in by |
|
122 * security extensions |
|
123 */ |
|
124 public static Vector getExtRestrictedPackages() |
|
125 { |
|
126 lazyInit(); |
|
127 return extRestrictedPackageNames; |
|
128 } |
|
129 |
|
130 /** |
|
131 * Retrieves the permission mapping of a certain named-permission, |
|
132 * if found among the permission mappings brought in by all the |
|
133 * security extensions |
|
134 */ |
|
135 public static MIDPPermission getExtPermission(String permissionName) |
|
136 { |
|
137 lazyInit(); |
|
138 return (MIDPPermission)extPermissionMappings.get(permissionName); |
|
139 } |
|
140 |
|
141 /** |
|
142 * Loggs a discard operation of an invalid security extension element |
|
143 */ |
|
144 public static void discard(String discardReason) |
|
145 { |
|
146 Logger.logWarning(discardReason); |
|
147 } |
|
148 |
|
149 /*** ----------------------------- PACKAGE ---------------------------- */ |
|
150 |
|
151 |
|
152 /*** ----------------------------- PRIVATE ---------------------------- */ |
|
153 |
|
154 /** |
|
155 * Lazy initialization of the security extension definitions |
|
156 */ |
|
157 private static void lazyInit() |
|
158 { |
|
159 if (!initialized) |
|
160 { |
|
161 handleExtensions(); |
|
162 initialized = true; |
|
163 } |
|
164 } |
|
165 |
|
166 /** |
|
167 * Reads the list of extensions and goes through each of the extension's |
|
168 * (ODC-based) system properties, reading and validating the |
|
169 * details of the security extension. |
|
170 */ |
|
171 private static void handleExtensions() |
|
172 { |
|
173 String extOdcList = System.getProperty("com.nokia.mj.addon.list"); |
|
174 if (extOdcList != null) |
|
175 { |
|
176 //Split the list to vector |
|
177 String[] result = Tokenizer.split(extOdcList, ";"); |
|
178 if (result != null) |
|
179 { |
|
180 for (int i=0; i<result.length; i++) |
|
181 { |
|
182 String extOdcFile = result[i]; |
|
183 |
|
184 // Support also plain .jar extensions (for Java 1.3 compatibility) |
|
185 if (extOdcFile.endsWith(ODC_EXTENSIONS)) |
|
186 { |
|
187 handleAddOnSystemProperties(extOdcFile); |
|
188 } |
|
189 } |
|
190 } |
|
191 } |
|
192 } |
|
193 |
|
194 /** |
|
195 * Validates the security extension read as an (ODC-based) system property |
|
196 */ |
|
197 private static void handleAddOnSystemProperties(String extOdcFile) |
|
198 { |
|
199 char pathSeparator = System.getProperty("file.separator").charAt(0); |
|
200 |
|
201 // Locate the last file separator |
|
202 int lastFileSeparator = |
|
203 extOdcFile.lastIndexOf(pathSeparator); |
|
204 |
|
205 // The line must contain at least one file separator and the |
|
206 // name of the file must end with .odc. |
|
207 if (lastFileSeparator >= 0) |
|
208 { |
|
209 // Strip away the path and file name extension. E.g. |
|
210 // c:\foo\eswtmobile.odc would be eswtmobile |
|
211 String propertyName = extOdcFile.substring( |
|
212 lastFileSeparator+1, |
|
213 extOdcFile.length()- |
|
214 ODC_EXTENSIONS.length()); |
|
215 |
|
216 // validate&set the security extensions |
|
217 setExtPackageNames(extOdcFile, |
|
218 PROTECTED_PACKAGES, System.getProperty( |
|
219 PROTECTED_PACKAGE_PROPERTY + propertyName)); |
|
220 setExtPackageNames( |
|
221 extOdcFile, |
|
222 RESTRICTED_PACKAGES, System.getProperty( |
|
223 RESTRICTED_PACKAGE_PROPERTY + propertyName)); |
|
224 setExtPermissionMappings( |
|
225 extOdcFile, |
|
226 System.getProperty( |
|
227 PERMISSION_MAPPINGS_PROPERTY + propertyName)); |
|
228 setExtPoliciesFileNames(extOdcFile, |
|
229 System.getProperty( |
|
230 SECURITY_POLICIES_PROPERTY + propertyName)); |
|
231 } |
|
232 } |
|
233 |
|
234 /** |
|
235 * Validates the security extension package names applying the following |
|
236 * rule: package names collisions are only allowed for same type of |
|
237 * packages (e.g. an extension can not declare as protected a package |
|
238 * name which is already declared restricted) |
|
239 */ |
|
240 private static void setExtPackageNames(String odcFile, int packageType, |
|
241 String packageNamesSystemProperty) |
|
242 { |
|
243 // sanity check |
|
244 if (packageNamesSystemProperty == null) |
|
245 { |
|
246 return; |
|
247 } |
|
248 |
|
249 String[] basePackageNames = (packageType == PROTECTED_PACKAGES |
|
250 ? PackageNames.restrictedPackages : PackageNames.protectedPackages); |
|
251 String[] extPackageNames = Tokenizer.split(packageNamesSystemProperty, |
|
252 ","); |
|
253 Vector okPackageNames = new Vector(); |
|
254 for (int i=0; i<extPackageNames.length; i++) |
|
255 { |
|
256 boolean found = find(extPackageNames[i], basePackageNames); |
|
257 if (!found) |
|
258 { |
|
259 // one more check against the already existing extensions |
|
260 // package names |
|
261 Vector otherPackageNames = (packageType == PROTECTED_PACKAGES |
|
262 ? extRestrictedPackageNames : extProtectedPackageNames); |
|
263 found = find(extPackageNames[i], otherPackageNames); |
|
264 } |
|
265 if (!found) |
|
266 { |
|
267 okPackageNames.addElement(extPackageNames[i]); |
|
268 } |
|
269 else |
|
270 { |
|
271 discard(odcFile, extPackageNames[i] |
|
272 + " is declared as " |
|
273 + (packageType == PROTECTED_PACKAGES ? "protected": "restricted") |
|
274 + " but it is already declared as " |
|
275 + (packageType == PROTECTED_PACKAGES ? "restricted": "protected")); |
|
276 } |
|
277 } |
|
278 Vector packageNames = (packageType == PROTECTED_PACKAGES |
|
279 ? extProtectedPackageNames : extRestrictedPackageNames); |
|
280 for (int i=0; i<okPackageNames.size(); i++) |
|
281 { |
|
282 packageNames.addElement(okPackageNames.elementAt(i)); |
|
283 } |
|
284 } |
|
285 |
|
286 /** |
|
287 * Validates the names of the security extension's policies applying the |
|
288 * following rule: the policies can only be loaded from "c:\\resource\\" |
|
289 * or "c:/resource/" |
|
290 */ |
|
291 private static void setExtPoliciesFileNames(String odcFile, |
|
292 String policiesSystemProperty) |
|
293 { |
|
294 String[] policiesFileNames = Tokenizer.split(policiesSystemProperty, |
|
295 ";"); |
|
296 if (policiesFileNames != null) |
|
297 { |
|
298 for (int i=0; i<policiesFileNames.length; i++) |
|
299 { |
|
300 String policyFileName = policiesFileNames[i]; |
|
301 if (policyFileName != null && policyFileName.length() > 0) |
|
302 { |
|
303 policyFileName = policyFileName.toLowerCase(); |
|
304 if (policyFileName.startsWith(ALLOWED_POLICY_FILE_LOCATION1) |
|
305 || (policyFileName.startsWith(ALLOWED_POLICY_FILE_LOCATION2))) |
|
306 { |
|
307 extPoliciesFileNames.addElement(policyFileName); |
|
308 } |
|
309 else |
|
310 { |
|
311 discard(odcFile, policyFileName + " points to unsafe location"); |
|
312 } |
|
313 } |
|
314 } |
|
315 // add the separator for new set of policies, so that the policies |
|
316 // could be treated as a group of related policies |
|
317 extPoliciesFileNames.addElement(POLICIES_SEPARATOR); |
|
318 } |
|
319 } |
|
320 |
|
321 /** |
|
322 * Validates the security extension's permission mappings applying the |
|
323 * following rule: permission mappings can not refer to any existing |
|
324 * named permissions nor to existing class names |
|
325 */ |
|
326 private static void setExtPermissionMappings(String odcFile, |
|
327 String mappingsSystemProperty) |
|
328 { |
|
329 String[] mappings = Tokenizer.split(mappingsSystemProperty, ";"); |
|
330 if (mappings != null) |
|
331 { |
|
332 for (int i=0; i<mappings.length; i++) |
|
333 { |
|
334 String mapping = mappings[i]; |
|
335 String[] tokens = Tokenizer.split(mapping, ","); |
|
336 if (tokens != null && tokens.length >= 2) |
|
337 { |
|
338 String namedPermName = tokens[0]; |
|
339 String classBasedPermName = null; |
|
340 String classBasedPermTarget = null; |
|
341 String classBasedPermActionList = null; |
|
342 switch (tokens.length) |
|
343 { |
|
344 case 4: |
|
345 classBasedPermActionList = tokens[3]; |
|
346 case 3: |
|
347 classBasedPermTarget = tokens[2]; |
|
348 case 2: |
|
349 classBasedPermName = tokens[1]; |
|
350 } |
|
351 if (classBasedPermName != null) |
|
352 { |
|
353 boolean found = find(namedPermName, |
|
354 classBasedPermName, |
|
355 PermissionMappingTable.PERMISSION_MAPPING_TABLE); |
|
356 if (!found) |
|
357 { |
|
358 // one more check against the existing extensions |
|
359 // permission mappings |
|
360 found = find(namedPermName, |
|
361 classBasedPermName, |
|
362 extPermissionMappings); |
|
363 } |
|
364 if (!found) |
|
365 { |
|
366 extPermissionMappings.put( |
|
367 namedPermName, |
|
368 new MIDPPermission( |
|
369 classBasedPermName, |
|
370 classBasedPermTarget, |
|
371 classBasedPermActionList)); |
|
372 } |
|
373 else |
|
374 { |
|
375 discard(odcFile, mappings[i] + " refers to existing permission mapping"); |
|
376 } |
|
377 } |
|
378 } |
|
379 } |
|
380 } |
|
381 } |
|
382 |
|
383 private static boolean find(String namedPermName, String classBasedPermName, Hashtable permMapping) |
|
384 { |
|
385 for (Enumeration e = permMapping.keys() ; e.hasMoreElements() ;) |
|
386 { |
|
387 Object key = e.nextElement(); |
|
388 Object value = permMapping.get(key); |
|
389 if (((String)key).equalsIgnoreCase(namedPermName) |
|
390 || (((MIDPPermission)value)).getName() |
|
391 .equalsIgnoreCase(classBasedPermName)) |
|
392 { |
|
393 return true; |
|
394 } |
|
395 } |
|
396 return false; |
|
397 } |
|
398 |
|
399 private static boolean find(String packageName, Vector packageNames) |
|
400 { |
|
401 String[] tmp = new String[packageNames.size()]; |
|
402 packageNames.copyInto(tmp); |
|
403 return find(packageName, tmp); |
|
404 } |
|
405 |
|
406 private static boolean find(String packageName, String[] packageNames) |
|
407 { |
|
408 packageName = packageName.replace('.', '/'); |
|
409 for (int i=0; i<packageNames.length; i++) |
|
410 { |
|
411 String otherPackageName = packageNames[i].replace('.', '/'); |
|
412 if (otherPackageName.startsWith(packageName) |
|
413 || packageName.startsWith(otherPackageName)) |
|
414 { |
|
415 return true; |
|
416 } |
|
417 } |
|
418 return false; |
|
419 } |
|
420 |
|
421 private static void discard(String odcFile, String discardReason) |
|
422 { |
|
423 Logger.logWarning(odcFile + " contains unsafe properties. Details: " + discardReason); |
|
424 } |
|
425 } |