PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/src/net/java/sip/communicator/plugin/provisioning/ProvisioningServiceImpl.java

https://bitbucket.org/LANJr4D/jitsi
Java | 848 lines | 574 code | 113 blank | 161 comment | 114 complexity | 488f4d1bfe2cd43ca609f71417fb3f46 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1
  1. package net.java.sip.communicator.plugin.provisioning;
  2. import java.awt.*;
  3. import java.io.*;
  4. import java.net.*;
  5. import java.util.*;
  6. import java.util.List;
  7. import java.util.regex.*;
  8. import javax.swing.*;
  9. import net.java.sip.communicator.service.httputil.*;
  10. import net.java.sip.communicator.service.provisioning.*;
  11. import net.java.sip.communicator.util.*;
  12. import net.java.sip.communicator.util.Logger;
  13. import net.java.sip.communicator.plugin.desktoputil.*;
  14. import org.jitsi.service.configuration.*;
  15. import org.jitsi.service.resources.*;
  16. import org.jitsi.util.*;
  17. import org.osgi.framework.*;
  18. // disambiguation
  19. /**
  20. * Provisioning service.
  21. *
  22. * @author Sebastien Vincent
  23. */
  24. public class ProvisioningServiceImpl
  25. implements ProvisioningService
  26. {
  27. /**
  28. * Logger of this class
  29. */
  30. private static final Logger logger
  31. = Logger.getLogger(ProvisioningServiceImpl.class);
  32. /**
  33. * Name of the UUID property.
  34. */
  35. public static final String PROVISIONING_UUID_PROP
  36. = "net.java.sip.communicator.UUID";
  37. /**
  38. * Name of the provisioning URL in the configuration service.
  39. */
  40. private static final String PROPERTY_PROVISIONING_URL
  41. = "net.java.sip.communicator.plugin.provisioning.URL";
  42. /**
  43. * Name of the provisioning username in the configuration service
  44. * authentication).
  45. */
  46. static final String PROPERTY_PROVISIONING_USERNAME
  47. = "net.java.sip.communicator.plugin.provisioning.auth.USERNAME";
  48. /**
  49. * Name of the provisioning password in the configuration service (HTTP
  50. * authentication).
  51. */
  52. static final String PROPERTY_PROVISIONING_PASSWORD
  53. = "net.java.sip.communicator.plugin.provisioning.auth";
  54. /**
  55. * Name of the property that contains the provisioning method (i.e. DHCP,
  56. * DNS, manual, ...).
  57. */
  58. private static final String PROVISIONING_METHOD_PROP
  59. = "net.java.sip.communicator.plugin.provisioning.METHOD";
  60. /**
  61. * Name of the property, whether provisioning is mandatory.
  62. */
  63. private static final String PROPERTY_PROVISIONING_MANDATORY
  64. = "net.java.sip.communicator.plugin.provisioning.MANDATORY";
  65. /**
  66. * Name of the property that contains enforce prefix list (separated by
  67. * pipe) for the provisioning. The retrieved configuration properties will
  68. * be checked against these prefixes to avoid having incorrect content in
  69. * the configuration file (such as HTML content resulting of HTTP error).
  70. */
  71. private static final String PROVISIONING_ALLOW_PREFIX_PROP
  72. = "provisioning.ALLOW_PREFIX";
  73. /**
  74. * Name of the enforce prefix property.
  75. */
  76. private static final String PROVISIONING_ENFORCE_PREFIX_PROP
  77. = "provisioning.ENFORCE_PREFIX";
  78. /**
  79. * List of allowed configuration prefixes.
  80. */
  81. private List<String> allowedPrefixes = new ArrayList<String>();
  82. /**
  83. * Authentication username.
  84. */
  85. private static String provUsername = null;
  86. /**
  87. * Authentication password.
  88. */
  89. private static String provPassword = null;
  90. /**
  91. * Constructor.
  92. */
  93. public ProvisioningServiceImpl()
  94. {
  95. // check if UUID is already configured
  96. String uuid = (String)ProvisioningActivator.getConfigurationService().
  97. getProperty(PROVISIONING_UUID_PROP);
  98. if(uuid == null || uuid.equals(""))
  99. {
  100. uuid = UUID.randomUUID().toString();
  101. ProvisioningActivator.getConfigurationService().setProperty(
  102. PROVISIONING_UUID_PROP, uuid);
  103. }
  104. }
  105. /**
  106. * Starts provisioning.
  107. *
  108. * @param url provisioning URL
  109. */
  110. void start(String url)
  111. {
  112. if(url == null)
  113. {
  114. /* try to see if provisioning URL is stored in properties */
  115. url = getProvisioningUri();
  116. }
  117. if(!StringUtils.isNullOrEmpty(url))
  118. {
  119. File file = retrieveConfigurationFile(url);
  120. if(file != null)
  121. {
  122. /* store the provisioning URL in local configuration in case
  123. * the provisioning discovery failed (DHCP/DNS unavailable, ...)
  124. */
  125. ProvisioningActivator.getConfigurationService().setProperty(
  126. PROPERTY_PROVISIONING_URL, url);
  127. updateConfiguration(file);
  128. }
  129. }
  130. }
  131. /**
  132. * Indicates if the provisioning has been enabled.
  133. *
  134. * @return <tt>true</tt> if the provisioning is enabled, <tt>false</tt> -
  135. * otherwise
  136. */
  137. public String getProvisioningMethod()
  138. {
  139. String provMethod
  140. = ProvisioningActivator.getConfigurationService().getString(
  141. PROVISIONING_METHOD_PROP);
  142. if (provMethod == null || provMethod.length() <= 0)
  143. {
  144. provMethod = ProvisioningActivator.getResourceService().
  145. getSettingsString(
  146. "plugin.provisioning.DEFAULT_PROVISIONING_METHOD");
  147. if (provMethod != null && provMethod.length() > 0)
  148. setProvisioningMethod(provMethod);
  149. }
  150. return provMethod;
  151. }
  152. /**
  153. * Enables the provisioning with the given method. If the provisioningMethod
  154. * is null disables the provisioning.
  155. *
  156. * @param provisioningMethod the provisioning method
  157. */
  158. public void setProvisioningMethod(String provisioningMethod)
  159. {
  160. ProvisioningActivator.getConfigurationService().setProperty(
  161. PROVISIONING_METHOD_PROP, provisioningMethod);
  162. }
  163. /**
  164. * Returns the provisioning URI.
  165. *
  166. * @return the provisioning URI
  167. */
  168. public String getProvisioningUri()
  169. {
  170. String provUri
  171. = ProvisioningActivator.getConfigurationService().getString(
  172. PROPERTY_PROVISIONING_URL);
  173. if (provUri == null || provUri.length() <= 0)
  174. {
  175. provUri = ProvisioningActivator.getResourceService().
  176. getSettingsString(
  177. "plugin.provisioning.DEFAULT_PROVISIONING_URI");
  178. if (provUri != null && provUri.length() > 0)
  179. setProvisioningUri(provUri);
  180. }
  181. return provUri;
  182. }
  183. /**
  184. * Sets the provisioning URI.
  185. *
  186. * @param uri the provisioning URI to set
  187. */
  188. public void setProvisioningUri(String uri)
  189. {
  190. ProvisioningActivator.getConfigurationService().setProperty(
  191. PROPERTY_PROVISIONING_URL, uri);
  192. }
  193. /**
  194. * Returns provisioning username.
  195. *
  196. * @return provisioning username
  197. */
  198. public String getProvisioningUsername()
  199. {
  200. return provUsername;
  201. }
  202. /**
  203. * Returns provisioning password.
  204. *
  205. * @return provisioning password
  206. */
  207. public String getProvisioningPassword()
  208. {
  209. return provPassword;
  210. }
  211. /**
  212. * Retrieve configuration file from provisioning URL.
  213. * This method is blocking until configuration file is retrieved from the
  214. * network or if an exception happen
  215. *
  216. * @param url provisioning URL
  217. * @return provisioning file downloaded
  218. */
  219. private File retrieveConfigurationFile(String url)
  220. {
  221. File tmpFile = null;
  222. try
  223. {
  224. String arg = null;
  225. String args[] = null;
  226. final File temp = File.createTempFile("provisioning",
  227. ".properties");
  228. tmpFile = temp;
  229. URL u = new URL(url);
  230. InetAddress ipaddr =
  231. ProvisioningActivator.getNetworkAddressManagerService().
  232. getLocalHost(InetAddress.getByName(u.getHost()));
  233. // Get any system environment identified by ${env.xyz}
  234. Pattern p = Pattern.compile("\\$\\{env\\.([^\\}]*)\\}");
  235. Matcher m = p.matcher(url);
  236. StringBuffer sb = new StringBuffer();
  237. while(m.find())
  238. {
  239. String value = System.getenv(m.group(1));
  240. if(value != null)
  241. {
  242. m.appendReplacement(sb, Matcher.quoteReplacement(value));
  243. }
  244. }
  245. m.appendTail(sb);
  246. url = sb.toString();
  247. // Get any system property variable identified by ${system.xyz}
  248. p = Pattern.compile("\\$\\{system\\.([^\\}]*)\\}");
  249. m = p.matcher(url);
  250. sb = new StringBuffer();
  251. while(m.find())
  252. {
  253. String value = System.getProperty(m.group(1));
  254. if(value != null)
  255. {
  256. m.appendReplacement(sb, Matcher.quoteReplacement(value));
  257. }
  258. }
  259. m.appendTail(sb);
  260. url = sb.toString();
  261. if(url.indexOf("${home.location}") != -1)
  262. {
  263. url = url.replace("${home.location}",
  264. ProvisioningActivator.getConfigurationService()
  265. .getScHomeDirLocation());
  266. }
  267. if(url.indexOf("${home.name}") != -1)
  268. {
  269. url = url.replace("${home.name}",
  270. ProvisioningActivator.getConfigurationService()
  271. .getScHomeDirName());
  272. }
  273. if(url.indexOf("${uuid}") != -1)
  274. {
  275. url = url.replace("${uuid}",
  276. (String)ProvisioningActivator.getConfigurationService()
  277. .getProperty(PROVISIONING_UUID_PROP));
  278. }
  279. if(url.indexOf("${osname}") != -1)
  280. {
  281. url = url.replace("${osname}", System.getProperty("os.name"));
  282. }
  283. if(url.indexOf("${arch}") != -1)
  284. {
  285. url = url.replace("${arch}", System.getProperty("os.arch"));
  286. }
  287. if(url.indexOf("${resx}") != -1 || url.indexOf("${resy}") != -1)
  288. {
  289. Rectangle screen = ScreenInformation.getScreenBounds();
  290. if(url.indexOf("${resx}") != -1)
  291. {
  292. url = url.replace("${resx}", String.valueOf(screen.width));
  293. }
  294. if(url.indexOf("${resy}") != -1)
  295. {
  296. url = url.replace("${resy}", String.valueOf(screen.height));
  297. }
  298. }
  299. if(url.indexOf("${build}") != -1)
  300. {
  301. url = url.replace("${build}",
  302. System.getProperty("sip-communicator.version"));
  303. }
  304. if(url.indexOf("${locale}") != -1)
  305. {
  306. String locale =
  307. ProvisioningActivator.getConfigurationService().getString(
  308. ResourceManagementService.DEFAULT_LOCALE_CONFIG);
  309. if(locale == null)
  310. locale = "";
  311. url = url.replace("${locale}", locale);
  312. }
  313. if(url.indexOf("${ipaddr}") != -1)
  314. {
  315. url = url.replace("${ipaddr}", ipaddr.getHostAddress());
  316. }
  317. if(url.indexOf("${hostname}") != -1)
  318. {
  319. String name;
  320. if(OSUtils.IS_WINDOWS)
  321. {
  322. // avoid reverse DNS lookup
  323. name = System.getenv("COMPUTERNAME");
  324. }
  325. else
  326. {
  327. name = ipaddr.getHostName();
  328. }
  329. url = url.replace("${hostname}", name);
  330. }
  331. if(url.indexOf("${hwaddr}") != -1)
  332. {
  333. if(ipaddr != null)
  334. {
  335. /* find the hardware address of the interface
  336. * that has this IP address
  337. */
  338. Enumeration<NetworkInterface> en =
  339. NetworkInterface.getNetworkInterfaces();
  340. while(en.hasMoreElements())
  341. {
  342. NetworkInterface iface = en.nextElement();
  343. Enumeration<InetAddress> enInet =
  344. iface.getInetAddresses();
  345. while(enInet.hasMoreElements())
  346. {
  347. InetAddress inet = enInet.nextElement();
  348. if(inet.equals(ipaddr))
  349. {
  350. byte hw[] =
  351. ProvisioningActivator.
  352. getNetworkAddressManagerService().
  353. getHardwareAddress(iface);
  354. if(hw == null)
  355. continue;
  356. StringBuffer buf =
  357. new StringBuffer();
  358. for(byte h : hw)
  359. {
  360. int hi = h >= 0 ? h : h + 256;
  361. String t = new String(
  362. (hi <= 0xf) ? "0" : "");
  363. t += Integer.toHexString(hi);
  364. buf.append(t);
  365. buf.append(":");
  366. }
  367. buf.deleteCharAt(buf.length() - 1);
  368. url = url.replace("${hwaddr}",
  369. buf.toString());
  370. break;
  371. }
  372. }
  373. }
  374. }
  375. }
  376. if(url.contains("?"))
  377. {
  378. /* do not handle URL of type http://domain/index.php? (no
  379. * parameters)
  380. */
  381. if((url.indexOf('?') + 1) != url.length())
  382. {
  383. arg = url.substring(url.indexOf('?') + 1);
  384. args = arg.split("&");
  385. }
  386. url = url.substring(0, url.indexOf('?'));
  387. }
  388. ArrayList<String> paramNames = null;
  389. ArrayList<String> paramValues = null;
  390. int usernameIx = -1;
  391. int passwordIx = -1;
  392. if(args != null && args.length > 0)
  393. {
  394. paramNames = new ArrayList<String>(args.length);
  395. paramValues = new ArrayList<String>(args.length);
  396. for(int i = 0; i < args.length; i++)
  397. {
  398. String s = args[i];
  399. String usernameParam = "${username}";
  400. String passwordParam = "${password}";
  401. // If we find the username or password parameter at this
  402. // stage we replace it with an empty string.
  403. if(s.indexOf(usernameParam) != -1)
  404. {
  405. s = s.replace(usernameParam, "");
  406. usernameIx = paramNames.size();
  407. }
  408. else if(s.indexOf(passwordParam) != -1)
  409. {
  410. s = s.replace(passwordParam, "");
  411. passwordIx = paramNames.size();
  412. }
  413. int equalsIndex = s.indexOf("=");
  414. if (equalsIndex > -1)
  415. {
  416. paramNames.add(s.substring(0, equalsIndex));
  417. paramValues.add(s.substring(equalsIndex + 1));
  418. }
  419. else
  420. {
  421. if(logger.isInfoEnabled())
  422. {
  423. logger.info(
  424. "Invalid provisioning request parameter: \""
  425. + s + "\", is replaced by \"" + s + "=\"");
  426. }
  427. paramNames.add(s);
  428. paramValues.add("");
  429. }
  430. }
  431. }
  432. HttpUtils.HTTPResponseResult res = null;
  433. Throwable errorWhileProvisioning = null;
  434. try
  435. {
  436. res =
  437. HttpUtils.postForm(
  438. url,
  439. PROPERTY_PROVISIONING_USERNAME,
  440. PROPERTY_PROVISIONING_PASSWORD,
  441. paramNames,
  442. paramValues,
  443. usernameIx,
  444. passwordIx);
  445. }
  446. catch(Throwable t)
  447. {
  448. logger.error("Error posting form", t);
  449. errorWhileProvisioning = t;
  450. }
  451. // if there was an error in retrieving stop
  452. if(res == null)
  453. {
  454. // if canceled, lets check whether provisioning is
  455. // mandatory
  456. boolean provisioningMandatory = false;
  457. String defaultSettingsProp =
  458. ProvisioningActivator.getResourceService()
  459. .getSettingsString(PROPERTY_PROVISIONING_MANDATORY);
  460. if(defaultSettingsProp != null
  461. && Boolean.parseBoolean(defaultSettingsProp))
  462. provisioningMandatory = true;
  463. if(ProvisioningActivator.getConfigurationService().getBoolean(
  464. PROPERTY_PROVISIONING_MANDATORY, provisioningMandatory))
  465. {
  466. String errorMsg;
  467. if(errorWhileProvisioning != null)
  468. errorMsg = errorWhileProvisioning.getLocalizedMessage();
  469. else
  470. errorMsg = "";
  471. ErrorDialog ed = new ErrorDialog(
  472. null,
  473. ProvisioningActivator.getResourceService()
  474. .getI18NString("plugin.provisioning.PROV_FAILED"),
  475. ProvisioningActivator.getResourceService()
  476. .getI18NString("plugin.provisioning.PROV_FAILED_MSG",
  477. new String[]{errorMsg}),
  478. errorWhileProvisioning);
  479. ed.setModal(true);
  480. ed.showDialog();
  481. // as shutdown service is not started and other bundles
  482. // are scheduled to start, stop all of them
  483. {
  484. for(Bundle b : ProvisioningActivator.bundleContext
  485. .getBundles())
  486. {
  487. try
  488. {
  489. // skip our Bundle avoiding stopping us while
  490. // starting and NPE in felix
  491. if(ProvisioningActivator.bundleContext
  492. .equals(b.getBundleContext()))
  493. {
  494. continue;
  495. }
  496. b.stop();
  497. }
  498. catch (BundleException ex)
  499. {
  500. logger.error(
  501. "Failed to being gentle stop " +
  502. b.getLocation(), ex);
  503. }
  504. }
  505. }
  506. }
  507. // stop processing
  508. return null;
  509. }
  510. String userPass[] = res.getCredentials();
  511. if(userPass[0] != null && userPass[1] != null)
  512. {
  513. provUsername = userPass[0];
  514. provPassword = userPass[1];
  515. }
  516. InputStream in = res.getContent();
  517. // Chain a ProgressMonitorInputStream to the
  518. // URLConnection's InputStream
  519. final ProgressMonitorInputStream pin
  520. = new ProgressMonitorInputStream(null, u.toString(), in);
  521. // Set the maximum value of the ProgressMonitor
  522. ProgressMonitor pm = pin.getProgressMonitor();
  523. pm.setMaximum((int)res.getContentLength());
  524. final BufferedOutputStream bout
  525. = new BufferedOutputStream(new FileOutputStream(temp));
  526. ByteArrayOutputStream logStream = new ByteArrayOutputStream();
  527. try
  528. {
  529. int read = -1;
  530. byte[] buff = new byte[1024];
  531. while((read = pin.read(buff)) != -1)
  532. {
  533. bout.write(buff, 0, read);
  534. logStream.write(buff, 0, read);
  535. }
  536. pin.close();
  537. bout.flush();
  538. bout.close();
  539. return temp;
  540. }
  541. catch (Exception e)
  542. {
  543. logger.error("Error saving", e);
  544. try
  545. {
  546. pin.close();
  547. bout.close();
  548. }
  549. catch (Exception e1)
  550. {
  551. }
  552. return null;
  553. }
  554. }
  555. catch (Exception e)
  556. {
  557. if (logger.isInfoEnabled())
  558. logger.info("Error retrieving provisioning file!", e);
  559. tmpFile.delete();
  560. return null;
  561. }
  562. }
  563. /**
  564. * Update configuration with properties retrieved from provisioning URL.
  565. *
  566. * @param file provisioning file
  567. */
  568. private void updateConfiguration(final File file)
  569. {
  570. Properties fileProps = new OrderedProperties();
  571. InputStream in = null;
  572. try
  573. {
  574. in = new BufferedInputStream(new FileInputStream(file));
  575. fileProps.load(in);
  576. Iterator<Map.Entry<Object, Object> > it
  577. = fileProps.entrySet().iterator();
  578. while(it.hasNext())
  579. {
  580. Map.Entry<Object, Object> entry = it.next();
  581. String key = (String)entry.getKey();
  582. Object value = entry.getValue();
  583. // skip empty keys, prevent them going into the configuration
  584. if(key.trim().length() == 0)
  585. continue;
  586. if(key.equals(PROVISIONING_ALLOW_PREFIX_PROP))
  587. {
  588. String prefixes[] = ((String)value).split("\\|");
  589. /* updates allowed prefixes list */
  590. for(String s : prefixes)
  591. {
  592. allowedPrefixes.add(s);
  593. }
  594. continue;
  595. }
  596. else if(key.equals(PROVISIONING_ENFORCE_PREFIX_PROP))
  597. {
  598. checkEnforcePrefix((String)value);
  599. continue;
  600. }
  601. /* check that properties is allowed */
  602. if(!isPrefixAllowed(key))
  603. {
  604. continue;
  605. }
  606. processProperty(key, value);
  607. }
  608. try
  609. {
  610. /* save and reload the "new" configuration */
  611. ProvisioningActivator.getConfigurationService().
  612. storeConfiguration();
  613. ProvisioningActivator.getConfigurationService().
  614. reloadConfiguration();
  615. }
  616. catch(Exception e)
  617. {
  618. logger.error("Cannot reload configuration");
  619. }
  620. }
  621. catch(IOException e)
  622. {
  623. logger.warn("Error during load of provisioning file");
  624. }
  625. finally
  626. {
  627. try
  628. {
  629. in.close();
  630. file.delete();
  631. }
  632. catch(IOException e)
  633. {
  634. }
  635. }
  636. }
  637. /**
  638. * Check if a property name belongs to the allowed prefixes.
  639. *
  640. * @param key property key name
  641. * @return true if key is allowed, false otherwise
  642. */
  643. private boolean isPrefixAllowed(String key)
  644. {
  645. if(allowedPrefixes.size() > 0)
  646. {
  647. for(String s : allowedPrefixes)
  648. {
  649. if(key.startsWith(s))
  650. {
  651. return true;
  652. }
  653. }
  654. /* current property prefix is not allowed */
  655. return false;
  656. }
  657. else
  658. {
  659. /* no allowed prefixes configured so key is valid by default */
  660. return true;
  661. }
  662. }
  663. /**
  664. * Process a new property. If value equals "${null}", it means to remove the
  665. * property in the configuration service. If the key name end with
  666. * "PASSWORD", its value is encrypted through credentials storage service,
  667. * otherwise the property is added/updated in the configuration service.
  668. *
  669. * @param key property key name
  670. * @param value property value
  671. */
  672. private void processProperty(String key, Object value)
  673. {
  674. if((value instanceof String) && value.equals("${null}"))
  675. {
  676. ProvisioningActivator.getConfigurationService().removeProperty(key);
  677. if(logger.isInfoEnabled())
  678. logger.info(key + "=" + value);
  679. }
  680. else if(key.endsWith(".PASSWORD"))
  681. {
  682. /* password => credentials storage service */
  683. ProvisioningActivator.getCredentialsStorageService().storePassword(
  684. key.substring(0, key.lastIndexOf(".")),
  685. (String)value);
  686. if(logger.isInfoEnabled())
  687. logger.info(key +"=<password hidden>");
  688. }
  689. else
  690. {
  691. ProvisioningActivator.getConfigurationService().setProperty(key,
  692. value);
  693. if(logger.isInfoEnabled())
  694. logger.info(key + "=" + value);
  695. }
  696. }
  697. /**
  698. * Walk through all properties and make sure all properties keys match
  699. * a specific set of prefixes defined in configuration.
  700. *
  701. * @param enforcePrefix list of enforce prefix.
  702. */
  703. private void checkEnforcePrefix(String enforcePrefix)
  704. {
  705. ConfigurationService config =
  706. ProvisioningActivator.getConfigurationService();
  707. String prefixes[] = null;
  708. if(enforcePrefix == null)
  709. {
  710. return;
  711. }
  712. /* must escape the | character */
  713. prefixes = enforcePrefix.split("\\|");
  714. /* get all properties */
  715. for (String key : config.getAllPropertyNames())
  716. {
  717. boolean isValid = false;
  718. for(String k : prefixes)
  719. {
  720. if(key.startsWith(k))
  721. {
  722. isValid = true;
  723. break;
  724. }
  725. }
  726. /* property name does is not in the enforce prefix list
  727. * so remove it
  728. */
  729. if(!isValid)
  730. {
  731. config.removeProperty(key);
  732. }
  733. }
  734. }
  735. }