1 /******************************************************************************* 2 * Copyright (c) 2011 SAP AG 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Lazar Kirchev, SAP AG - initial API and implementation 13 *******************************************************************************/ 14 15 package org.eclipse.equinox.console.ssh; 16 17 import java.io.BufferedReader; 18 import java.io.IOException; 19 import java.io.InputStreamReader; 20 import java.util.regex.Matcher; 21 import java.util.regex.Pattern; 22 23 import org.apache.felix.service.command.CommandSession; 24 import org.apache.felix.service.command.Descriptor; 25 import org.eclipse.equinox.console.common.ConsoleInputScanner; 26 import org.eclipse.equinox.console.common.Scanner; 27 import org.eclipse.equinox.console.storage.DigestUtil; 28 import org.eclipse.equinox.console.storage.SecureUserStore; 29 30 /** 31 * This class provides commands for administering users: adding, removing and listing users; setting or changing password; 32 * resetting password; adding and removing roles 33 * 34 * 35 */ 36 public class UserAdminCommand { 37 private static final String INPUT_SCANNER = "INPUT_SCANNER"; 38 private static final String SSH_INPUT_SCANNER = "SSH_INPUT_SCANNER"; 39 private static final String DEFAULT_USER = "equinox"; 40 private static final int MINIMAL_PASSWORD_LENGTH = 8; 41 private static final int PASSWORD_INPUT_TRIALS_LIMIT = 3; 42 43 /** 44 * Command for adding a user 45 * 46 * @param args command line arguments in the format -username <username> -password <password> -roles <comma-separated list of user roles (optional)> 47 * @throws Exception 48 */ 49 @Descriptor("Add user with password and roles") addUser(@escriptorR) String[] args)50 public void addUser(@Descriptor("-username <username>\r\n-password <password>\r\n-roles <comma-separated list of user roles (optional)>") String[] args) throws Exception { 51 String username = null; 52 String password = null; 53 String roles = ""; 54 55 for (int i = 0; i < args.length; i++) { 56 if ("-username".equals(args[i]) && i < args.length - 1) { 57 username = args[i + 1]; 58 i++; 59 } else if ("-password".equals(args[i]) && i < args.length - 1) { 60 password = args[i + 1]; 61 i++; 62 } else if ("-roles".equals(args[i]) && i < args.length - 1) { 63 roles = args[i + 1]; 64 i++; 65 } 66 } 67 68 if (! validateUsername(username)) { 69 throw new Exception("Invalid username"); 70 } 71 72 if (password == null) { 73 throw new Exception("Password not specified"); 74 } 75 76 if (password.length() < MINIMAL_PASSWORD_LENGTH) { 77 throw new Exception("Password should be at least 8 characters"); 78 } 79 80 SecureUserStore.putUser(username, DigestUtil.encrypt(password), roles); 81 82 if(SecureUserStore.existsUser(DEFAULT_USER)) { 83 SecureUserStore.deleteUser(DEFAULT_USER); 84 } 85 } 86 87 /** 88 * Command for setting or changing the password of a user. 89 * 90 * @param args command-line arguments in the format -username <username> -password <password> 91 * @throws Exception 92 */ 93 @Descriptor("Set or change password") setPassword(@escriptorR) String[] args)94 public void setPassword(@Descriptor("-username <username>\r\n-password <password>") String[] args) throws Exception { 95 String username = null; 96 String password = null; 97 98 for (int i = 0; i < args.length; i++) { 99 if ("-username".equals(args[i]) && i < args.length - 1) { 100 username = args[i + 1]; 101 i++; 102 } else if ("-password".equals(args[i]) && i < args.length - 1) { 103 password = args[i + 1]; 104 i++; 105 } 106 } 107 108 if (! validateUsername(username)) { 109 throw new Exception("Invalid username"); 110 } 111 112 if (password == null) { 113 throw new Exception("Password not specified"); 114 } 115 116 if (password.length() < MINIMAL_PASSWORD_LENGTH) { 117 throw new Exception("Password should be at least 8 characters"); 118 } 119 120 SecureUserStore.setPassword(username, DigestUtil.encrypt(password)); 121 } 122 123 /** 124 * Command for adding a user. The command interactively asks for username, password and roles; the 125 * input plain text password is encrypted before storing. 126 * 127 * @param session 128 * @return true if the user was successfully added 129 * 130 * @throws Exception 131 */ 132 @Descriptor("Add user with password and roles interactively") addUser(final CommandSession session)133 public boolean addUser(final CommandSession session) throws Exception { 134 135 ConsoleInputScanner inputScanner = (ConsoleInputScanner) session.get(INPUT_SCANNER); 136 Scanner scanner = (Scanner) session.get(SSH_INPUT_SCANNER); 137 138 try { 139 // switch off the history so that username, password and roles will not be saved in console history 140 if (scanner != null) { 141 inputScanner.toggleHistoryEnabled(false); 142 } 143 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 144 String username = readUsername(reader); 145 if (!validateUsername(username)) { 146 System.out.println("Invalid username"); 147 return false; 148 } 149 150 if (SecureUserStore.existsUser(username)) { 151 System.out.println("Username already exists"); 152 return false; 153 } 154 155 // switch off the echo so that the password will not be printed in the console 156 if (scanner != null) { 157 scanner.toggleEchoEnabled(false); 158 } 159 String password = readPassword(reader); 160 if (password == null){ 161 return false; 162 } 163 if (scanner != null) { 164 scanner.toggleEchoEnabled(true); 165 } 166 167 String roles = readRoles(reader); 168 if (roles == null) { 169 return false; 170 } 171 172 SecureUserStore.putUser(username, DigestUtil.encrypt(password), roles); 173 174 if(SecureUserStore.existsUser(DEFAULT_USER)) { 175 SecureUserStore.deleteUser(DEFAULT_USER); 176 } 177 } finally { 178 if (scanner != null) { 179 inputScanner.toggleHistoryEnabled(true); 180 scanner.toggleEchoEnabled(true); 181 } 182 } 183 184 return true; 185 } 186 187 @Descriptor("Delete user") deleteUser(@escriptorR) String username)188 public void deleteUser(@Descriptor("username of the user to be deleted") String username) { 189 if (SecureUserStore.existsUser(username)) { 190 SecureUserStore.deleteUser(username); 191 } 192 } 193 194 /** 195 * Command to remove the password for a user 196 * 197 * @param username user to remove the password for 198 * @throws Exception 199 */ 200 @Descriptor("Reset password") resetPassword(@escriptorR) String username)201 public void resetPassword(@Descriptor("username of the user whose password will be reset") String username) throws Exception { 202 if (!SecureUserStore.existsUser(username)) { 203 throw new Exception("Such user does not exist"); 204 } 205 206 SecureUserStore.resetPassword(username); 207 } 208 209 /** 210 * Command to set or change the password for a user; the command asks interactively for the new password; the 211 * input plain text password is encrypted before storing. 212 * 213 * @param session 214 * @param username the user whose password will be changed 215 * @throws Exception 216 */ 217 @Descriptor("Set or change password") setPassword(final CommandSession session, @Descriptor(R) String username)218 public void setPassword(final CommandSession session, @Descriptor("Username of the user whose password will be changed") String username) throws Exception { 219 if ("".equals(username)) { 220 System.out.println("Username not specified"); 221 return; 222 } 223 224 if (!SecureUserStore.existsUser(username)) { 225 throw new Exception("Such user does not exist"); 226 } 227 228 ConsoleInputScanner inputScanner = (ConsoleInputScanner) session.get(INPUT_SCANNER); 229 Scanner scanner = (Scanner) session.get(SSH_INPUT_SCANNER); 230 231 try { 232 // switch off echo and history so that the password is neither echoed to the console, nor saved in history 233 if (scanner != null) { 234 inputScanner.toggleHistoryEnabled(false); 235 scanner.toggleEchoEnabled(false); 236 } 237 238 BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 239 String password = readPassword(reader); 240 if (password == null) { 241 return; 242 } 243 244 SecureUserStore.setPassword(username, DigestUtil.encrypt(password)); 245 } finally { 246 if (scanner != null) { 247 inputScanner.toggleHistoryEnabled(true); 248 scanner.toggleEchoEnabled(true); 249 } 250 } 251 } 252 253 /** 254 * Command to add roles to a user 255 * 256 * @param args command line arguments in the format -username <username>\r\n-roles <comma-separated list of roles to add> 257 * @throws Exception 258 */ 259 @Descriptor("Add roles to user") addRoles(@escriptorR) String[] args)260 public void addRoles(@Descriptor("-username <username>\r\n-roles <comma-separated list of roles to add>") String[] args) throws Exception { 261 String username = null; 262 String roles = ""; 263 264 for (int i = 0; i < args.length; i++) { 265 if ("-username".equals(args[i]) && i < args.length - 1) { 266 username = args[i + 1]; 267 i++; 268 } else if ("-roles".equals(args[i]) && i < args.length - 1) { 269 roles = args[i + 1]; 270 i++; 271 } 272 } 273 274 if (username == null) { 275 throw new Exception("Username not specified"); 276 } 277 278 if("".equals(roles)) { 279 return; 280 } 281 282 if (!SecureUserStore.existsUser(username)) { 283 throw new Exception("Such user does not exist"); 284 } 285 286 SecureUserStore.addRoles(username, roles); 287 } 288 289 /** 290 * Command to remove roles for a particular user 291 * 292 * @param args command line arguments in the format -username <username>\r\n-roles <comma-separated list of roles to remove> 293 * @throws Exception 294 */ 295 @Descriptor("Remove user roles") removeRoles(@escriptorR) String[] args)296 public void removeRoles(@Descriptor("-username <username>\r\n-roles <comma-separated list of roles to remove>") String[] args) throws Exception { 297 String username = null; 298 String roles = ""; 299 300 for (int i = 0; i < args.length; i++) { 301 if ("-username".equals(args[i]) && i < args.length - 1) { 302 username = args[i + 1]; 303 i++; 304 } else if ("-roles".equals(args[i]) && i < args.length - 1) { 305 roles = args[i + 1]; 306 i++; 307 } 308 } 309 310 if (username == null) { 311 throw new Exception("Username not specified"); 312 } 313 314 if("".equals(roles)) { 315 return; 316 } 317 318 if (!SecureUserStore.existsUser(username)) { 319 throw new Exception("Such user does not exist"); 320 } 321 322 SecureUserStore.removeRoles(username, roles); 323 } 324 325 /** 326 * Command to list available users 327 */ 328 @Descriptor("Lists available users") listUsers()329 public void listUsers() { 330 331 String[] users = SecureUserStore.getUserNames(); 332 333 if(users.length == 0) { 334 System.out.println("No users available"); 335 return; 336 } 337 338 for(String user : users) { 339 System.out.println(user); 340 } 341 } 342 readPassword(BufferedReader reader)343 private String readPassword(BufferedReader reader) { 344 String password = null; 345 int count = 0; 346 347 while (password == null && count < PASSWORD_INPUT_TRIALS_LIMIT){ 348 System.out.print("password: "); 349 System.out.flush(); 350 351 try { 352 password = reader.readLine(); 353 } catch (IOException e) { 354 System.out.println("Error while reading password"); 355 return null; 356 } 357 358 359 if (password == null || "".equals(password)) { 360 System.out.println("Password not specified"); 361 password = null; 362 } else if (password.length() < MINIMAL_PASSWORD_LENGTH) { 363 System.out.println("Password should be at least 8 characters"); 364 password = null; 365 } 366 367 count++; 368 } 369 370 if (password == null) { 371 return null; 372 } 373 374 String passwordConfirmation = null; 375 count = 0; 376 377 while (passwordConfirmation == null && count < PASSWORD_INPUT_TRIALS_LIMIT){ 378 System.out.print("Confirm password: "); 379 System.out.flush(); 380 381 try { 382 passwordConfirmation = reader.readLine(); 383 if (!password.equals(passwordConfirmation)) { 384 System.out.println("The passwords do not match!"); 385 passwordConfirmation = null; 386 } 387 } catch (IOException e) { 388 System.out.println("Error while reading password"); 389 return null; 390 } 391 392 count++; 393 } 394 if (passwordConfirmation == null){ 395 return null; 396 } 397 return password; 398 } 399 readUsername(BufferedReader reader)400 private String readUsername (BufferedReader reader) { 401 System.out.print("username: "); 402 System.out.flush(); 403 String username = null; 404 405 try { 406 username = reader.readLine(); 407 } catch (IOException e) { 408 System.out.println("Error while reading username"); 409 return null; 410 } 411 412 if (username == null || "".equals(username)) { 413 System.out.println("Username not specified"); 414 return null; 415 } 416 417 return username; 418 } 419 readRoles(BufferedReader reader)420 private String readRoles (BufferedReader reader){ 421 //roles input validation 422 System.out.print("roles: "); 423 System.out.flush(); 424 String roles = null; 425 try { 426 roles = reader.readLine(); 427 } catch (IOException e) { 428 System.out.println("Error while reading roles"); 429 return null; 430 } 431 432 if (roles == null) { 433 roles = ""; 434 } 435 return roles; 436 } 437 validateUsername(String username)438 private static boolean validateUsername (String username){ 439 if( username == null){ 440 return false; 441 }else{ 442 Pattern allowedChars = Pattern.compile("[A-Za-z0-9_.]+"); 443 Matcher matcher = allowedChars.matcher(username); 444 return matcher.matches(); 445 } 446 } 447 448 } 449