public void run() { try { Log.debug("Trying to configure Clearspace."); doConfigClearspace(); updateClearspaceClientSettings(); } catch (UnauthorizedException e) { Log.warn( "Unauthorization problem trying to configure Clearspace, trying again in 1 minute", e); // TODO: Mark that there is an authorization problem } catch (Exception e) { Log.warn("Unknown problem trying to configure Clearspace, trying again in 1 minute", e); } }
private synchronized void doConfigClearspace() throws UnauthorizedException { Log.debug("Starting Clearspace configuration."); List<String> bindInterfaces = getServerInterfaces(); if (bindInterfaces.size() == 0) { // We aren't up and running enough to tell Clearspace what interfaces to bind to. Log.debug("No bind interfaces found to config Clearspace"); throw new IllegalStateException("There are no binding interfaces."); } try { XMPPServerInfo serverInfo = XMPPServer.getInstance().getServerInfo(); String path = IM_URL_PREFIX + "configureComponent/"; // Creates the XML with the data Document groupDoc = DocumentHelper.createDocument(); Element rootE = groupDoc.addElement("configureComponent"); Element domainE = rootE.addElement("domain"); domainE.setText(serverInfo.getXMPPDomain()); for (String bindInterface : bindInterfaces) { Element hostsE = rootE.addElement("hosts"); hostsE.setText(bindInterface); } Element portE = rootE.addElement("port"); portE.setText(String.valueOf(ExternalComponentManager.getServicePort())); Log.debug( "Trying to configure Clearspace with: Domain: " + serverInfo.getXMPPDomain() + ", hosts: " + bindInterfaces.toString() + ", port: " + port); executeRequest(POST, path, rootE.asXML()); // Done, Clearspace was configured correctly, clear the task Log.debug("Clearspace was configured, stopping the task."); TaskEngine.getInstance().cancelScheduledTask(configClearspaceTask); configClearspaceTask = null; } catch (UnauthorizedException ue) { throw ue; } catch (Exception e) { // It is not supported exception, wrap it into an UnsupportedOperationException throw new UnsupportedOperationException("Unexpected error", e); } }
private synchronized void startClearspaceConfig() { // If the task is running, stop it if (configClearspaceTask != null) { configClearspaceTask.cancel(); Log.debug("Stopping previous configuration Clearspace task."); } // Create and schedule a confi task every minute configClearspaceTask = new ConfigClearspaceTask(); // Wait some time to start the task until Openfire has binding address TaskEngine.getInstance() .schedule(configClearspaceTask, JiveConstants.SECOND * 30, JiveConstants.MINUTE); Log.debug("Starting configuration Clearspace task in 10 seconds."); }
private void updateClearspaceSharedSecret(String newSecret) { try { String path = IM_URL_PREFIX + "updateSharedSecret/"; // Creates the XML with the data Document groupDoc = DocumentHelper.createDocument(); Element rootE = groupDoc.addElement("updateSharedSecret"); rootE.addElement("newSecret").setText(newSecret); executeRequest(POST, path, groupDoc.asXML()); } catch (UnauthorizedException ue) { Log.error("Error updating the password of Clearspace", ue); } catch (Exception e) { Log.error("Error updating the password of Clearspace", e); } }
private void updateClearspaceClientSettings() { String xmppBoshSslPort = "0"; String xmppBoshPort = "0"; String xmppPort = String.valueOf(XMPPServer.getInstance().getConnectionManager().getClientListenerPort()); if (JiveGlobals.getBooleanProperty( HttpBindManager.HTTP_BIND_ENABLED, HttpBindManager.HTTP_BIND_ENABLED_DEFAULT)) { int boshSslPort = HttpBindManager.getInstance().getHttpBindSecurePort(); int boshPort = HttpBindManager.getInstance().getHttpBindUnsecurePort(); try { if (HttpBindManager.getInstance().isHttpsBindActive() && LocalClientSession.getTLSPolicy() != org.jivesoftware.openfire.Connection.TLSPolicy.disabled) { xmppBoshSslPort = String.valueOf(boshSslPort); } } catch (Exception e) { // Exception while working with certificate Log.debug( "Error while checking SSL certificate. Instructing Clearspace not to use SSL port."); } if (HttpBindManager.getInstance().isHttpBindActive() && boshPort > 0) { xmppBoshPort = String.valueOf(boshPort); } } try { String path = CHAT_URL_PREFIX + "updateClientSettings/"; // Creates the XML with the data Document groupDoc = DocumentHelper.createDocument(); Element rootE = groupDoc.addElement("updateClientSettings"); rootE.addElement("boshSslPort").setText(xmppBoshSslPort); rootE.addElement("boshPort").setText(xmppBoshPort); rootE.addElement("tcpPort").setText(xmppPort); executeRequest(POST, path, groupDoc.asXML()); } catch (UnauthorizedException ue) { Log.error("Error updating the client settings of Clearspace", ue); } catch (Exception e) { Log.error("Error updating the client settings of Clearspace", e); } }
/** * Returns a nonce generated by Clearspace to be used in a SSO login. * * @return a unique nonce. */ public String getNonce() { try { String path = IM_URL_PREFIX + "generateNonce"; Element element = executeRequest(GET, path); return WSUtils.getReturn(element); } catch (Exception e) { Log.error("Failed executing #generateNonce with Clearspace", e); } return null; }
public synchronized boolean configClearspace() { // If the task is running, stop it if (configClearspaceTask != null) { configClearspaceTask.cancel(); Log.debug("Stopping previous configuration Clearspace task."); } boolean configured = false; try { doConfigClearspace(); updateClearspaceClientSettings(); configured = true; } catch (UnauthorizedException e) { Log.info("Unauthorized to configure Clearspace.", e); } catch (UnsupportedOperationException e) { Log.info("Error configuring Clearspace.", e); } if (!configured) { startClearspaceConfig(); } return configured; }
/** * Tests the web services connection with Clearspace given the manager's current configuration. * * @return The exception or null if connection test was successful. */ public Throwable testConnection() { // Test invoking a simple method try { // If there is a problem with the URL or the user/password this service throws an exception String path = IM_URL_PREFIX + "testCredentials"; executeRequest(GET, path); return null; } catch (Exception e) { // It is not ok, return false. Log.warn("Failed testing communicating with Clearspace", e); return e; } }
/** * Check a username/password pair for valid authentication. * * @param username Username to authenticate against. * @param password Password to use for authentication. * @return True or false of the authentication succeeded. */ public Boolean checkAuthentication(String username, String password) { try { // Un-escape username. username = JID.unescapeNode(username); // Encode potentially non-ASCII characters username = URLUTF8Encoder.encode(username); String path = ClearspaceAuthProvider.URL_PREFIX + "authenticate/" + username + "/" + password; executeRequest(GET, path); return true; } catch (Exception e) { // Nothing to do. Log.warn("Failed authenticating user with Clearspace. User = " + username, e); } return false; }
/** * Sets the shared secret for the Clearspace service we're connecting to. * * @param sharedSecret the password configured in Clearspace to authenticate Openfire. */ public void setSharedSecret(String sharedSecret) { // Set new password for external component ExternalComponentConfiguration configuration = new ExternalComponentConfiguration( "clearspace", true, ExternalComponentConfiguration.Permission.allowed, sharedSecret); try { ExternalComponentManager.allowAccess(configuration); } catch (ModificationNotAllowedException e) { Log.warn("Failed to configure password for Clearspace", e); } // After updating the component information we can update the field, but not before. // If it is done before, OF won't be able to execute the updateSharedsecret webservice // since it would try with the new password. this.sharedSecret = sharedSecret; properties.put("clearspace.sharedSecret", sharedSecret); }
static { try { factory = XmlPullParserFactory.newInstance(MXParser.class.getName(), null); factory.setNamespaceAware(true); } catch (XmlPullParserException e) { Log.error("Error creating a parser factory", e); } // Create xmpp parser to keep in each thread localParser = new ThreadLocal<XMPPPacketReader>() { protected XMPPPacketReader initialValue() { XMPPPacketReader parser = new XMPPPacketReader(); factory.setNamespaceAware(true); parser.setXPPFactory(factory); return parser; } }; // Add a new exception map from CS to OF and it will be automatically translated. exceptionMap = new HashMap<String, String>(); exceptionMap.put( "com.jivesoftware.base.UserNotFoundException", "org.jivesoftware.openfire.user.UserNotFoundException"); exceptionMap.put( "com.jivesoftware.base.UserAlreadyExistsException", "org.jivesoftware.openfire.user.UserAlreadyExistsException"); exceptionMap.put( "com.jivesoftware.base.GroupNotFoundException", "org.jivesoftware.openfire.group.GroupNotFoundException"); exceptionMap.put( "com.jivesoftware.base.GroupAlreadyExistsException", "org.jivesoftware.openfire.group.GroupAlreadyExistsException"); exceptionMap.put( "org.acegisecurity.BadCredentialsException", "org.jivesoftware.openfire.auth.UnauthorizedException"); exceptionMap.put( "com.jivesoftware.base.UnauthorizedException", "org.jivesoftware.openfire.auth.UnauthorizedException"); exceptionMap.put( "com.jivesoftware.community.NotFoundException", "org.jivesoftware.util.NotFoundException"); }
/** * Makes a rest request of any type at the specified urlSuffix. The urlSuffix should be of the * form /userService/users. If CS throws an exception it handled and transalated to a Openfire * exception if possible. This is done using the check fault method that tries to throw the best * maching exception. * * @param type Must be GET or DELETE * @param urlSuffix The url suffix of the rest request * @param xmlParams The xml with the request params, must be null if type is GET or DELETE only * @return The response as a xml doc. * @throws ConnectionException Thrown if there are issues perfoming the request. * @throws Exception Thrown if the response from Clearspace contains an exception. */ public Element executeRequest(HttpType type, String urlSuffix, String xmlParams) throws ConnectionException, Exception { if (Log.isDebugEnabled()) { Log.debug("Outgoing REST call [" + type + "] to " + urlSuffix + ": " + xmlParams); } String wsUrl = getConnectionURI() + WEBSERVICES_PATH + urlSuffix; String secret = getSharedSecret(); HttpClient client = new HttpClient(); HttpMethod method; // Configures the authentication client.getParams().setAuthenticationPreemptive(true); Credentials credentials = new UsernamePasswordCredentials(OPENFIRE_USERNAME, secret); AuthScope scope = new AuthScope(host, port, AuthScope.ANY_REALM); client.getState().setCredentials(scope, credentials); // Creates the method switch (type) { case GET: method = new GetMethod(wsUrl); break; case POST: PostMethod pm = new PostMethod(wsUrl); StringRequestEntity requestEntity = new StringRequestEntity(xmlParams); pm.setRequestEntity(requestEntity); method = pm; break; case PUT: PutMethod pm1 = new PutMethod(wsUrl); StringRequestEntity requestEntity1 = new StringRequestEntity(xmlParams); pm1.setRequestEntity(requestEntity1); method = pm1; break; case DELETE: method = new DeleteMethod(wsUrl); break; default: throw new IllegalArgumentException(); } method.setRequestHeader("Accept", "text/xml"); method.setDoAuthentication(true); try { // Executes the request client.executeMethod(method); // Parses the result String body = method.getResponseBodyAsString(); if (Log.isDebugEnabled()) { Log.debug("Outgoing REST call results: " + body); } // Checks the http status if (method.getStatusCode() != 200) { if (method.getStatusCode() == 401) { throw new ConnectionException( "Invalid password to connect to Clearspace.", ConnectionException.ErrorType.AUTHENTICATION); } else if (method.getStatusCode() == 404) { throw new ConnectionException( "Web service not found in Clearspace.", ConnectionException.ErrorType.PAGE_NOT_FOUND); } else if (method.getStatusCode() == 503) { throw new ConnectionException( "Web service not avaible in Clearspace.", ConnectionException.ErrorType.SERVICE_NOT_AVAIBLE); } else { throw new ConnectionException( "Error connecting to Clearspace, http status code: " + method.getStatusCode(), new HTTPConnectionException(method.getStatusCode()), ConnectionException.ErrorType.OTHER); } } else if (body.contains("Clearspace Upgrade Console")) { // TODO Change CS to send a more standard error message throw new ConnectionException( "Clearspace is in an update state.", ConnectionException.ErrorType.UPDATE_STATE); } Element response = localParser.get().parseDocument(body).getRootElement(); // Check for exceptions checkFault(response); // Since there is no exception, returns the response return response; } catch (DocumentException e) { throw new ConnectionException( "Error parsing the response of Clearspace.", e, ConnectionException.ErrorType.OTHER); } catch (HttpException e) { throw new ConnectionException( "Error performing http request to Clearspace", e, ConnectionException.ErrorType.OTHER); } catch (UnknownHostException e) { throw new ConnectionException( "Unknown Host " + getConnectionURI() + " trying to connect to Clearspace", e, ConnectionException.ErrorType.UNKNOWN_HOST); } catch (IOException e) { throw new ConnectionException( "Error peforming http request to Clearspace.", e, ConnectionException.ErrorType.OTHER); } finally { method.releaseConnection(); } }
public void start() throws IllegalStateException { super.start(); if (isEnabled()) { // Before starting up service make sure there is a default secret if (ExternalComponentManager.getDefaultSecret() == null || "".equals(ExternalComponentManager.getDefaultSecret())) { try { ExternalComponentManager.setDefaultSecret(StringUtils.randomString(10)); } catch (ModificationNotAllowedException e) { Log.warn("Failed to set a default secret to external component service", e); } } // Make sure that external component service is enabled if (!ExternalComponentManager.isServiceEnabled()) { try { ExternalComponentManager.setServiceEnabled(true); } catch (ModificationNotAllowedException e) { Log.warn("Failed to start external component service", e); } } // Listen for changes to external component settings ExternalComponentManager.addListener(this); // Listen for registration of new components InternalComponentManager.getInstance().addListener(this); // Listen for changes in certificates CertificateManager.addListener(this); // Listen for property changes PropertyEventDispatcher.addListener(this); // Set up custom clearspace MUC service // Create service if it doesn't exist, load if it does. MultiUserChatServiceImpl muc = (MultiUserChatServiceImpl) XMPPServer.getInstance() .getMultiUserChatManager() .getMultiUserChatService(MUC_SUBDOMAIN); if (muc == null) { try { muc = XMPPServer.getInstance() .getMultiUserChatManager() .createMultiUserChatService(MUC_SUBDOMAIN, MUC_DESCRIPTION, true); } catch (AlreadyExistsException e) { Log.error( "ClearspaceManager: Found no " + MUC_SUBDOMAIN + " service, but got already exists when creation attempted? Service probably not started!"); } } if (muc != null) { // Set up special delegate for Clearspace MUC service muc.setMUCDelegate(new ClearspaceMUCEventDelegate()); // Set up additional features for Clearspace MUC service muc.addExtraFeature("clearspace:service"); // Set up additional identity of conference service to Clearspace MUC service muc.addExtraIdentity("conference", "Clearspace Chat Service", "text"); } // Starts the clearspace configuration task startClearspaceConfig(); // Starts the Clearspace MUC transcript manager mucTranscriptManager.start(); } }
private void init() { // Register the trust manager to use when using HTTPS Protocol easyhttps = new Protocol("https", (ProtocolSocketFactory) new SSLProtocolSocketFactory(this), 443); Protocol.registerProtocol("https", easyhttps); // Convert XML based provider setup to Database based JiveGlobals.migrateProperty("clearspace.uri"); JiveGlobals.migrateProperty("clearspace.sharedSecret"); // Make sure that all Clearspace components are set up, unless they were overridden // Note that the auth provider is our way of knowing that we are set up with Clearspace, // so don't bother checking to set it. if (isEnabled()) { if (JiveGlobals.getProperty("provider.user.className") == null) { JiveGlobals.setProperty( "provider.user.className", "org.jivesoftware.openfire.clearspace.ClearspaceUserProvider"); } if (JiveGlobals.getProperty("provider.group.className") == null) { JiveGlobals.setProperty( "provider.group.className", "org.jivesoftware.openfire.clearspace.ClearspaceGroupProvider"); } if (JiveGlobals.getProperty("provider.vcard.className") == null) { JiveGlobals.setProperty( "provider.vcard.className", "org.jivesoftware.openfire.clearspace.ClearspaceVCardProvider"); } if (JiveGlobals.getProperty("provider.lockout.className") == null) { JiveGlobals.setProperty( "provider.lockout.className", "org.jivesoftware.openfire.clearspace.ClearspaceLockOutProvider"); } if (JiveGlobals.getProperty("provider.securityAudit.className") == null) { JiveGlobals.setProperty( "provider.securityAudit.className", "org.jivesoftware.openfire.clearspace.ClearspaceSecurityAuditProvider"); } if (JiveGlobals.getProperty("provider.admin.className") == null) { JiveGlobals.setProperty( "provider.admin.className", "org.jivesoftware.openfire.clearspace.ClearspaceAdminProvider"); } } this.uri = properties.get("clearspace.uri"); if (uri != null) { if (!this.uri.endsWith("/")) { this.uri = this.uri + "/"; } // Updates the host/port attributes based on the uri updateHostPort(); } sharedSecret = properties.get("clearspace.sharedSecret"); // Creates the cache maps userIDCache = new DefaultCache<String, Long>("clearspace.userid", 1000, JiveConstants.DAY); groupIDCache = new DefaultCache<String, Long>("clearspace.groupid", 1000, JiveConstants.DAY); usernameCache = new DefaultCache<Long, String>("clearspace.username", 1000, JiveConstants.DAY); if (Log.isDebugEnabled()) { StringBuilder buf = new StringBuilder(); buf.append("Created new ClearspaceManager() instance, fields:\n"); buf.append("\t URI: ").append(uri).append("\n"); buf.append("\t sharedSecret: ").append(sharedSecret).append("\n"); Log.debug("ClearspaceManager: " + buf.toString()); } // Init nonce cache nonceCache = CacheFactory.createCache("Clearspace SSO Nonce"); // Init nonce generator nonceGenerator = new Random(); }