1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 module hunt.shiro.authc.UsernamePasswordToken; 20 21 import hunt.shiro.authc.AuthenticationToken; 22 import hunt.shiro.authc.RememberMeAuthenticationToken; 23 import hunt.shiro.authc.HostAuthenticationToken; 24 25 import hunt.util.StringBuilder; 26 27 /** 28 * <p>A simple username/password authentication token to support the most widely-used authentication mechanism. This 29 * class also : the {@link RememberMeAuthenticationToken RememberMeAuthenticationToken} interface to support 30 * "Remember Me" services across user sessions as well as the 31 * {@link hunt.shiro.authc.HostAuthenticationToken HostAuthenticationToken} interface to retain the host name 32 * or IP address location from where the authentication attempt is occurring.</p> 33 * <p/> 34 * <p>"Remember Me" authentications are disabled by default, but if the application developer wishes to allow 35 * it for a login attempt, all that is necessary is to call {@link #setRememberMe setRememberMe(true)}. If the underlying 36 * <tt>SecurityManager</tt> implementation also supports <tt>RememberMe</tt> services, the user's identity will be 37 * remembered across sessions. 38 * <p/> 39 * <p>Note that this class stores a password as[] a char instead of a string 40 * (which may seem more logical). This is because Strings are immutable and their 41 * internal value cannot be overwritten - meaning even a nulled string instance might be accessible in memory at a later 42 * time (e.g. memory dump). This is not good for sensitive information such as passwords. For more information, see the 43 * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx"> 44 * Java Cryptography Extension Reference Guide</a>.</p> 45 * <p/> 46 * <p>To avoid this possibility of later memory access, the application developer should always call 47 * {@link #clear() clear()} after using the token to perform a login attempt.</p> 48 * 49 */ 50 class UsernamePasswordToken : HostAuthenticationToken, RememberMeAuthenticationToken { 51 52 /*-------------------------------------------- 53 | C O N S T A N T S | 54 ============================================*/ 55 56 /*-------------------------------------------- 57 | I N S T A N C E V A R I A B L E S | 58 ============================================*/ 59 /** 60 * The username 61 */ 62 private string username; 63 64 /** 65 * The password, in[] char format 66 */ 67 private char[] password; 68 69 /** 70 * Whether or not 'rememberMe' should be enabled for the corresponding login attempt; 71 * default is <code>false</code> 72 */ 73 private bool rememberMe = false; 74 75 /** 76 * The location from where the login attempt occurs, or <code>null</code> if not known or explicitly 77 * omitted. 78 */ 79 private string host; 80 81 private string _name = DEFAULT_AUTH_TOKEN_NAME; 82 83 /*-------------------------------------------- 84 | C O N S T R U C T O R S | 85 ============================================*/ 86 87 /** 88 * JavaBeans compatible no-arg constructor. 89 */ 90 this() { 91 } 92 93 /** 94 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted 95 * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and a 96 * <tt>rememberMe</tt> default of <tt>false</tt>. 97 * 98 * @param username the username submitted for authentication 99 * @param password the password character array submitted for authentication 100 */ 101 this(string username, char[] password) { 102 this(username, password, false, null); 103 } 104 105 /** 106 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted 107 * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and 108 * a <tt>rememberMe</tt> default of <tt>false</tt> 109 * <p/> 110 * <p>This is a convenience constructor and maintains the password internally via a character 111 * array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a string 112 * in your code could have possible security implications as noted in the class JavaDoc.</p> 113 * 114 * @param username the username submitted for authentication 115 * @param password the password string submitted for authentication 116 */ 117 this(string username, string password) { 118 this(username, password !is null ? password.dup : null, false, cast(string)null); 119 } 120 121 /** 122 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the 123 * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt> 124 * 125 * @param username the username submitted for authentication 126 * @param password the password string submitted for authentication 127 * @param host the host name or IP string from where the attempt is occurring 128 */ 129 this(string username, char[] password, string host) { 130 this(username, password, false, host); 131 } 132 133 /** 134 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the 135 * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt> 136 * <p/> 137 * <p>This is a convenience constructor and maintains the password internally via a character 138 * array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a string 139 * in your code could have possible security implications as noted in the class JavaDoc.</p> 140 * 141 * @param username the username submitted for authentication 142 * @param password the password string submitted for authentication 143 * @param host the host name or IP string from where the attempt is occurring 144 */ 145 this(string username, string password, string host) { 146 this(username, password !is null ? password.dup : null, false, host); 147 } 148 149 /** 150 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user 151 * wishes their identity to be remembered across sessions. 152 * 153 * @param username the username submitted for authentication 154 * @param password the password string submitted for authentication 155 * @param rememberMe if the user wishes their identity to be remembered across sessions 156 */ 157 this(string username, char[] password, bool rememberMe) { 158 this(username, password, rememberMe, null); 159 } 160 161 /** 162 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user 163 * wishes their identity to be remembered across sessions. 164 * <p/> 165 * <p>This is a convenience constructor and maintains the password internally via a character 166 * array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a string 167 * in your code could have possible security implications as noted in the class JavaDoc.</p> 168 * 169 * @param username the username submitted for authentication 170 * @param password the password string submitted for authentication 171 * @param rememberMe if the user wishes their identity to be remembered across sessions 172 */ 173 this(string username, string password, bool rememberMe) { 174 this(username, password !is null ? password.dup : null, rememberMe, cast(string)null); 175 } 176 177 /** 178 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, if the user 179 * wishes their identity to be remembered across sessions, and the inetAddress from where the attempt is occurring. 180 * 181 * @param username the username submitted for authentication 182 * @param password the password character array submitted for authentication 183 * @param rememberMe if the user wishes their identity to be remembered across sessions 184 * @param host the host name or IP string from where the attempt is occurring 185 */ 186 this(string username, char[] password, bool rememberMe, string host) { 187 this.username = username; 188 this.password = password; 189 this.rememberMe = rememberMe; 190 this.host = host; 191 } 192 193 194 /** 195 * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, if the user 196 * wishes their identity to be remembered across sessions, and the inetAddress from where the attempt is occurring. 197 * <p/> 198 * <p>This is a convenience constructor and maintains the password internally via a character 199 * array, i.e. <tt>password.toCharArray();</tt>. Note that storing a password as a string 200 * in your code could have possible security implications as noted in the class JavaDoc.</p> 201 * 202 * @param username the username submitted for authentication 203 * @param password the password string submitted for authentication 204 * @param rememberMe if the user wishes their identity to be remembered across sessions 205 * @param host the host name or IP string from where the attempt is occurring 206 */ 207 this(string username, string password, bool rememberMe, string host) { 208 this(username, password !is null ? password.dup : null, rememberMe, host); 209 } 210 211 /*-------------------------------------------- 212 | A C C E S S O R S / M O D I F I E R S | 213 ============================================*/ 214 215 string name() { 216 return _name; 217 } 218 219 void name(string value) { 220 _name = value; 221 } 222 223 /** 224 * Returns the username submitted during an authentication attempt. 225 * 226 * @return the username submitted during an authentication attempt. 227 */ 228 string getUsername() { 229 return username; 230 } 231 232 /** 233 * Sets the username for submission during an authentication attempt. 234 * 235 * @param username the username to be used for submission during an authentication attempt. 236 */ 237 void setUsername(string username) { 238 this.username = username; 239 } 240 241 242 /** 243 * Returns the password submitted during an authentication attempt as a character array. 244 * 245 * @return the password submitted during an authentication attempt as a character array. 246 */ 247 char[] getPassword() { 248 return password; 249 } 250 251 /** 252 * Sets the password for submission during an authentication attempt. 253 * 254 * @param password the password to be used for submission during an authentication attempt. 255 */ 256 void setPassword(char[] password) { 257 this.password = password; 258 } 259 260 /** 261 * Simply returns {@link #getUsername() getUsername()}. 262 * 263 * @return the {@link #getUsername() username}. 264 * @see hunt.shiro.authc.AuthenticationToken#getPrincipal() 265 */ 266 string getPrincipal() { 267 return getUsername(); 268 } 269 270 /** 271 * Returns the {@link #getPassword() password} char array. 272 * 273 * @return the {@link #getPassword() password} char array. 274 * @see hunt.shiro.authc.AuthenticationToken#getCredentials() 275 */ 276 char[] getCredentials() { 277 return getPassword(); 278 } 279 280 /** 281 * Returns the host name or IP string from where the authentication attempt occurs. May be <tt>null</tt> if the 282 * host name/IP is unknown or explicitly omitted. It is up to the Authenticator implementation processing this 283 * token if an authentication attempt without a host is valid or not. 284 * <p/> 285 * <p>(Shiro's default Authenticator allows <tt>null</tt> hosts to support localhost and proxy server environments).</p> 286 * 287 * @return the host from where the authentication attempt occurs, or <tt>null</tt> if it is unknown or 288 * explicitly omitted. 289 */ 290 string getHost() { 291 return host; 292 } 293 294 /** 295 * Sets the host name or IP string from where the authentication attempt occurs. It is up to the Authenticator 296 * implementation processing this token if an authentication attempt without a host is valid or not. 297 * <p/> 298 * <p>(Shiro's default Authenticator 299 * allows <tt>null</tt> hosts to allow localhost and proxy server environments).</p> 300 * 301 * @param host the host name or IP string from where the attempt is occurring 302 */ 303 void setHost(string host) { 304 this.host = host; 305 } 306 307 /** 308 * Returns <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered 309 * across sessions, <tt>false</tt> otherwise. Unless overridden, this value is <tt>false</tt> by default. 310 * 311 * @return <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered 312 * across sessions, <tt>false</tt> otherwise (<tt>false</tt> by default). 313 */ 314 bool isRememberMe() { 315 return rememberMe; 316 } 317 318 /** 319 * Sets if the submitting user wishes their identity (principal(s)) to be remembered across sessions. Unless 320 * overridden, the default value is <tt>false</tt>, indicating <em>not</em> to be remembered across sessions. 321 * 322 * @param rememberMe value indicating if the user wishes their identity (principal(s)) to be remembered across 323 * sessions. 324 */ 325 void setRememberMe(bool rememberMe) { 326 this.rememberMe = rememberMe; 327 } 328 329 /*-------------------------------------------- 330 | M E T H O D S | 331 ============================================*/ 332 333 /** 334 * Clears out (nulls) the username, password, rememberMe, and inetAddress. The password bytes are explicitly set to 335 * <tt>0x00</tt> before nulling to eliminate the possibility of memory access at a later time. 336 */ 337 void clear() { 338 this.username = null; 339 this.host = null; 340 this.rememberMe = false; 341 342 if (this.password !is null) { 343 for (int i = 0; i < password.length; i++) { 344 this.password[i] = 0x00; 345 } 346 this.password = null; 347 } 348 349 } 350 351 /** 352 * Returns the string representation. It does not include the password in the resulting 353 * string for security reasons to prevent accidentally printing out a password 354 * that might be widely viewable). 355 * 356 * @return the string representation of the <tt>UsernamePasswordToken</tt>, omitting 357 * the password. 358 */ 359 override string toString() { 360 StringBuilder sb = new StringBuilder(); 361 sb.append(typeid(this).name); 362 sb.append(" - "); 363 sb.append(username); 364 sb.append(", rememberMe=").append(rememberMe); 365 if (host !is null) { 366 sb.append(" (").append(host).append(")"); 367 } 368 return sb.toString(); 369 } 370 371 }