1 /* 2 * Copyright (C) 2004-2008 Jive Software. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.jivesoftware.util; 18 19 import java.io.File; 20 import java.io.FileOutputStream; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.OutputStream; 24 import java.net.URL; 25 import java.util.Arrays; 26 import java.util.Comparator; 27 import java.util.Date; 28 import java.util.StringTokenizer; 29 30 import org.jivesoftware.openfire.PresenceManager; 31 import org.jivesoftware.openfire.PrivateStorage; 32 import org.jivesoftware.openfire.SessionManager; 33 import org.jivesoftware.openfire.XMPPServer; 34 import org.jivesoftware.openfire.XMPPServerInfo; 35 import org.jivesoftware.openfire.auth.AuthToken; 36 import org.jivesoftware.openfire.group.GroupManager; 37 import org.jivesoftware.openfire.lockout.LockOutManager; 38 import org.jivesoftware.openfire.muc.MultiUserChatManager; 39 import org.jivesoftware.openfire.pubsub.PubSubInfo; 40 import org.jivesoftware.openfire.pubsub.PubSubServiceInfo; 41 import org.jivesoftware.openfire.roster.RosterManager; 42 import org.jivesoftware.openfire.security.SecurityAuditManager; 43 import org.jivesoftware.openfire.user.User; 44 import org.jivesoftware.openfire.user.UserManager; 45 import org.jivesoftware.util.cache.Cache; 46 import org.jivesoftware.util.cache.CacheFactory; 47 import org.slf4j.Logger; 48 import org.slf4j.LoggerFactory; 49 50 import javax.servlet.http.HttpSession; 51 52 /** 53 * A utility bean for Openfire admin console pages. 54 */ 55 public class WebManager extends WebBean { 56 57 private static final Logger Log = LoggerFactory.getLogger(WebManager.class); 58 59 private int start = 0; 60 private int range = 15; 61 WebManager()62 public WebManager() { 63 } 64 65 /** 66 * Invalidates and recreates session (do this on login/logout). 67 * @return the new HTTP session 68 */ invalidateSession()69 public HttpSession invalidateSession() { 70 session.invalidate(); 71 session = request.getSession(true); 72 return session; 73 } 74 75 /** 76 * @return the auth token; redirect to the login page if an auth token is not found. 77 */ getAuthToken()78 public AuthToken getAuthToken() { 79 return session == null ? null : (AuthToken)session.getAttribute("jive.admin.authToken"); 80 } 81 82 /** 83 * @return {@code true} if the Openfire container is in setup mode, {@code false} otherwise. 84 */ isSetupMode()85 public boolean isSetupMode() { 86 return getXMPPServer().isSetupMode(); 87 } 88 89 /** 90 * @return the XMPP server object -- can get many config items from here. 91 */ getXMPPServer()92 public XMPPServer getXMPPServer() { 93 final XMPPServer xmppServer = XMPPServer.getInstance(); 94 if (xmppServer == null) { 95 // Show that the server is down 96 showServerDown(); 97 return null; 98 } 99 return xmppServer; 100 } 101 getUserManager()102 public UserManager getUserManager() { 103 return getXMPPServer().getUserManager(); 104 } 105 getGroupManager()106 public GroupManager getGroupManager() { 107 return GroupManager.getInstance(); 108 } 109 getLockOutManager()110 public LockOutManager getLockOutManager() { 111 return LockOutManager.getInstance(); 112 } 113 getSecurityAuditManager()114 public SecurityAuditManager getSecurityAuditManager() { 115 return SecurityAuditManager.getInstance(); 116 } 117 getRosterManager()118 public RosterManager getRosterManager() { 119 return getXMPPServer().getRosterManager(); 120 } 121 getPrivateStore()122 public PrivateStorage getPrivateStore() { 123 return getXMPPServer().getPrivateStorage(); 124 } 125 getPresenceManager()126 public PresenceManager getPresenceManager() { 127 return getXMPPServer().getPresenceManager(); 128 } 129 getSessionManager()130 public SessionManager getSessionManager() { 131 return getXMPPServer().getSessionManager(); 132 } 133 getMultiUserChatManager()134 public MultiUserChatManager getMultiUserChatManager() { 135 return getXMPPServer().getMultiUserChatManager(); 136 } 137 getServerInfo()138 public XMPPServerInfo getServerInfo() { 139 return getXMPPServer().getServerInfo(); 140 } 141 getPubSubInfo()142 public PubSubServiceInfo getPubSubInfo() { 143 return new PubSubInfo(); 144 } 145 146 /** 147 * Logs a security event as the currently logged in user. (convenience routine for SecurityAuditManager) 148 * 149 * @param summary Summary of event. 150 * @param details Details of event, can be null if no details available. 151 */ logEvent(String summary, String details)152 public void logEvent(String summary, String details) { 153 SecurityAuditManager.getInstance().logEvent(getUser().getUsername(), summary, details); 154 } 155 156 /** 157 * @return the page user or {@code null} if one is not found. 158 */ getUser()159 public User getUser() { 160 User pageUser = null; 161 try { 162 final AuthToken authToken = getAuthToken(); 163 if (authToken == null) 164 { 165 Log.debug( "Unable to get user: no session or no auth token on session." ); 166 return null; 167 } 168 if (authToken instanceof AuthToken.OneTimeAuthToken) { 169 return new User(authToken.getUsername(), "Recovery via One Time Auth Token", null, new Date(), new Date()); 170 } 171 final String username = authToken.getUsername(); 172 if (username == null || username.isEmpty()) 173 { 174 Log.debug( "Unable to get user: no username in auth token on session." ); 175 return null; 176 } 177 pageUser = getUserManager().getUser(username); 178 } 179 catch (Exception ex) { 180 Log.debug("Unexpected exception (which is ignored) while trying to obtain user.", ex); 181 } 182 return pageUser; 183 } 184 185 /** 186 * @return {@code true} if the server is in embedded mode, {@code false} otherwise. 187 */ isEmbedded()188 public boolean isEmbedded() { 189 try { 190 ClassUtils.forName("org.jivesoftware.openfire.starter.ServerStarter"); 191 return true; 192 } 193 catch (Exception ignored) { 194 return false; 195 } 196 } 197 198 /** 199 * Restarts the server then sleeps for 3 seconds. 200 */ restart()201 public void restart() { 202 try { 203 getXMPPServer().restart(); 204 } 205 catch (Exception e) { 206 Log.error(e.getMessage(), e); 207 } 208 sleep(); 209 } 210 211 /** 212 * Stops the server then sleeps for 3 seconds. 213 */ stop()214 public void stop() { 215 try { 216 getXMPPServer().stop(); 217 } 218 catch (Exception e) { 219 Log.error(e.getMessage(), e); 220 } 221 sleep(); 222 } 223 getManager()224 public WebManager getManager() { 225 return this; 226 } 227 validateService()228 public void validateService() { 229 if (getPresenceManager() == null || 230 getXMPPServer() == null) { 231 showServerDown(); 232 } 233 } 234 isServerRunning()235 public boolean isServerRunning() { 236 return !(getPresenceManager() == null || getXMPPServer() == null); 237 } 238 setStart(int start)239 public void setStart(int start) { 240 this.start = start; 241 } 242 getStart()243 public int getStart() { 244 return start; 245 } 246 setRange(int range)247 public void setRange(int range) { 248 this.range = range; 249 } 250 getRange()251 public int getRange() { 252 return range; 253 } 254 getCurrentPage()255 public int getCurrentPage() { 256 return (start / range) + 1; 257 } 258 sleep()259 private void sleep() { 260 // Sleep for a minute: 261 try { 262 Thread.sleep(3000L); 263 } 264 catch (Exception ignored) { 265 Log.trace("Sleep got interrupted."); 266 } 267 } 268 showServerDown()269 protected void showServerDown() { 270 try { 271 response.sendRedirect("error-serverdown.jsp"); 272 } 273 catch (Exception ex) { 274 ex.printStackTrace(); 275 } 276 } 277 278 /** 279 * Copies the contents at <CODE>src</CODE> to <CODE>dst</CODE>. 280 * @param src the source location 281 * @param dst the target location 282 * @throws IOException if the copy failed 283 */ copy(URL src, File dst)284 public static void copy(URL src, File dst) throws IOException { 285 286 try (InputStream in = src.openStream()) { 287 try (OutputStream out = new FileOutputStream(dst)) { 288 dst.mkdirs(); 289 copy(in, out); 290 } 291 } 292 } 293 294 /** 295 * Common code for copy routines. By convention, the streams are 296 * closed in the same method in which they were opened. Thus, 297 * this method does not close the streams when the copying is done. 298 * @param in the input stream 299 * @param out the output stream 300 * @throws IOException if the copy failed 301 */ copy(InputStream in, OutputStream out)302 private static void copy(InputStream in, OutputStream out) throws IOException { 303 byte[] buffer = new byte[4096]; 304 while (true) { 305 int bytesRead = in.read(buffer); 306 if (bytesRead < 0) { 307 break; 308 } 309 out.write(buffer, 0, bytesRead); 310 } 311 } 312 313 /** 314 * Returns the number of rows per page for the specified page for the current logged user. 315 * The rows per page value is stored as a user property. The same property is being used for 316 * different pages. The encoding format is the following "pageName1=value,pageName2=value". 317 * 318 * @param pageName the name of the page to look up its stored value. 319 * @param defaultValue the default value to return if no user value was found. 320 * @return the number of rows per page for the specified page for the current logged user. 321 */ getRowsPerPage(String pageName, int defaultValue)322 public int getRowsPerPage(String pageName, int defaultValue) { 323 return getPageProperty(pageName, "console.rows_per_page", defaultValue); 324 } 325 326 /** 327 * Sets the new number of rows per page for the specified page for the current logged user. 328 * The rows per page value is stored as a user property. The same property is being used for 329 * different pages. The encoding format is the following "pageName1=value,pageName2=value". 330 * 331 * @param pageName the name of the page to stored its new value. 332 * @param newValue the new rows per page value. 333 */ setRowsPerPage(String pageName, int newValue)334 public void setRowsPerPage(String pageName, int newValue) { 335 setPageProperty(pageName, "console.rows_per_page", newValue); 336 } 337 338 /** 339 * Returns the number of seconds between each page refresh for the specified page for the 340 * current logged user. The value is stored as a user property. The same property is being 341 * used for different pages. The encoding format is the following 342 * "pageName1=value,pageName2=value". 343 * 344 * @param pageName the name of the page to look up its stored value. 345 * @param defaultValue the default value to return if no user value was found. 346 * @return the number of seconds between each page refresh for the specified page for 347 * the current logged user. 348 */ getRefreshValue(String pageName, int defaultValue)349 public int getRefreshValue(String pageName, int defaultValue) { 350 return getPageProperty(pageName, "console.refresh", defaultValue); 351 } 352 353 /** 354 * Sets the number of seconds between each page refresh for the specified page for the 355 * current logged user. The value is stored as a user property. The same property is being 356 * used for different pages. The encoding format is the following 357 * "pageName1=value,pageName2=value". 358 * 359 * @param pageName the name of the page to stored its new value. 360 * @param newValue the new number of seconds between each page refresh. 361 */ setRefreshValue(String pageName, int newValue)362 public void setRefreshValue(String pageName, int newValue) { 363 setPageProperty(pageName, "console.refresh", newValue); 364 } 365 getPageProperty(String pageName, String property, int defaultValue)366 public int getPageProperty(String pageName, String property, int defaultValue) { 367 User user = getUser(); 368 if (user != null) { 369 String values = user.getProperties().get(property); 370 if (values != null) { 371 StringTokenizer tokens = new StringTokenizer(values, ",="); 372 while (tokens.hasMoreTokens()) { 373 String page = tokens.nextToken().trim(); 374 String rows = tokens.nextToken().trim(); 375 if (pageName.equals(page)) { 376 try { 377 return Integer.parseInt(rows); 378 } 379 catch (NumberFormatException e) { 380 return defaultValue; 381 } 382 } 383 } 384 } 385 } 386 return defaultValue; 387 } 388 setPageProperty(String pageName, String property, int newValue)389 public void setPageProperty(String pageName, String property, int newValue) { 390 String toStore = pageName + "=" + newValue; 391 User user = getUser(); 392 if (user != null) { 393 String values = user.getProperties().get(property); 394 if (values != null) { 395 if (values.contains(toStore)) { 396 // The new value for the page was already stored so do nothing 397 return; 398 } 399 else { 400 if (values.contains(pageName)) { 401 // Replace an old value for the page with the new value 402 int oldValue = getPageProperty(pageName, property, -1); 403 String toRemove = pageName + "=" + oldValue; 404 user.getProperties().put(property, values.replace(toRemove, toStore)); 405 } 406 else { 407 // Append the new page-value 408 user.getProperties().put(property, values + "," + toStore); 409 } 410 } 411 } 412 else { 413 // Store the new page-value as a new user property 414 user.getProperties().put(property, toStore); 415 } 416 } 417 } 418 getCaches()419 public Cache[] getCaches() { 420 Cache[] caches =CacheFactory.getAllCaches(); 421 Arrays.sort(caches, new Comparator<Cache>() { 422 @Override 423 public int compare(Cache cache1, Cache cache2) { 424 return cache1.getName().toLowerCase().compareTo(cache2.getName().toLowerCase()); 425 } 426 }); 427 return caches; 428 } 429 } 430