001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.authc;
020    
021    /**
022     * <p>A simple username/password authentication token to support the most widely-used authentication mechanism.  This
023     * class also implements the {@link RememberMeAuthenticationToken RememberMeAuthenticationToken} interface to support
024     * &quot;Remember Me&quot; services across user sessions as well as the
025     * {@link org.apache.shiro.authc.HostAuthenticationToken HostAuthenticationToken} interface to retain the host name
026     * or IP address location from where the authentication attempt is occuring.</p>
027     * <p/>
028     * <p>&quot;Remember Me&quot; authentications are disabled by default, but if the application developer wishes to allow
029     * it for a login attempt, all that is necessary is to call {@link #setRememberMe setRememberMe(true)}.  If the underlying
030     * <tt>SecurityManager</tt> implementation also supports <tt>RememberMe</tt> services, the user's identity will be
031     * remembered across sessions.
032     * <p/>
033     * <p>Note that this class stores a password as a char[] instead of a String
034     * (which may seem more logical).  This is because Strings are immutable and their
035     * internal value cannot be overwritten - meaning even a nulled String instance might be accessible in memory at a later
036     * time (e.g. memory dump).  This is not good for sensitive information such as passwords. For more information, see the
037     * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/security/jce/JCERefGuide.html#PBEEx">
038     * Java Cryptography Extension Reference Guide</a>.</p>
039     * <p/>
040     * <p>To avoid this possibility of later memory access, the application developer should always call
041     * {@link #clear() clear()} after using the token to perform a login attempt.</p>
042     *
043     * @author Jeremy Haile
044     * @author Les Hazlewood
045     * @since 0.1
046     */
047    public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
048    
049        /*--------------------------------------------
050        |             C O N S T A N T S             |
051        ============================================*/
052    
053        /*--------------------------------------------
054        |    I N S T A N C E   V A R I A B L E S    |
055        ============================================*/
056        /**
057         * The username
058         */
059        private String username;
060    
061        /**
062         * The password, in char[] format
063         */
064        private char[] password;
065    
066        /**
067         * Whether or not 'rememberMe' should be enabled for the corresponding login attempt;
068         * default is <code>false</code>
069         */
070        private boolean rememberMe = false;
071    
072        /**
073         * The location from where the login attempt occurs, or <code>null</code> if not known or explicitly
074         * omitted.
075         */
076        private String host;
077    
078        /*--------------------------------------------
079        |         C O N S T R U C T O R S           |
080        ============================================*/
081    
082        /**
083         * JavaBeans compatible no-arg constructor.
084         */
085        public UsernamePasswordToken() {
086        }
087    
088        /**
089         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted
090         * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and a
091         * <tt>rememberMe</tt> default of <tt>false</tt>.
092         *
093         * @param username the username submitted for authentication
094         * @param password the password character array submitted for authentication
095         */
096        public UsernamePasswordToken(final String username, final char[] password) {
097            this(username, password, false, null);
098        }
099    
100        /**
101         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted
102         * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and
103         * a <tt>rememberMe</tt> default of <tt>false</tt>
104         * <p/>
105         * <p>This is a convience constructor and maintains the password internally via a character
106         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
107         * in your code could have possible security implications as noted in the class JavaDoc.</p>
108         *
109         * @param username the username submitted for authentication
110         * @param password the password string submitted for authentication
111         */
112        public UsernamePasswordToken(final String username, final String password) {
113            this(username, password != null ? password.toCharArray() : null, false, null);
114        }
115    
116        /**
117         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the
118         * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt>
119         *
120         * @param username the username submitted for authentication
121         * @param password the password string submitted for authentication
122         * @param host     the host name or IP string from where the attempt is occuring
123         * @since 0.2
124         */
125        public UsernamePasswordToken(final String username, final char[] password, final String host) {
126            this(username, password, false, host);
127        }
128    
129        /**
130         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the
131         * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt>
132         * <p/>
133         * <p>This is a convience constructor and maintains the password internally via a character
134         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
135         * in your code could have possible security implications as noted in the class JavaDoc.</p>
136         *
137         * @param username the username submitted for authentication
138         * @param password the password string submitted for authentication
139         * @param host     the host name or IP string from where the attempt is occuring
140         * @since 1.0
141         */
142        public UsernamePasswordToken(final String username, final String password, final String host) {
143            this(username, password != null ? password.toCharArray() : null, false, host);
144        }
145    
146        /**
147         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user
148         * wishes their identity to be remembered across sessions.
149         *
150         * @param username   the username submitted for authentication
151         * @param password   the password string submitted for authentication
152         * @param rememberMe if the user wishes their identity to be remembered across sessions
153         * @since 0.9
154         */
155        public UsernamePasswordToken(final String username, final char[] password, final boolean rememberMe) {
156            this(username, password, rememberMe, null);
157        }
158    
159        /**
160         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user
161         * wishes their identity to be remembered across sessions.
162         * <p/>
163         * <p>This is a convience constructor and maintains the password internally via a character
164         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
165         * in your code could have possible security implications as noted in the class JavaDoc.</p>
166         *
167         * @param username   the username submitted for authentication
168         * @param password   the password string submitted for authentication
169         * @param rememberMe if the user wishes their identity to be remembered across sessions
170         * @since 0.9
171         */
172        public UsernamePasswordToken(final String username, final String password, final boolean rememberMe) {
173            this(username, password != null ? password.toCharArray() : null, rememberMe, null);
174        }
175    
176        /**
177         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, if the user
178         * wishes their identity to be remembered across sessions, and the inetAddress from where the attempt is ocurring.
179         *
180         * @param username   the username submitted for authentication
181         * @param password   the password character array submitted for authentication
182         * @param rememberMe if the user wishes their identity to be remembered across sessions
183         * @param host       the host name or IP string from where the attempt is occuring
184         * @since 1.0
185         */
186        public UsernamePasswordToken(final String username, final char[] password,
187                                     final boolean rememberMe, final String host) {
188    
189            this.username = username;
190            this.password = password;
191            this.rememberMe = rememberMe;
192            this.host = host;
193        }
194    
195    
196        /**
197         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, if the user
198         * wishes their identity to be remembered across sessions, and the inetAddress from where the attempt is ocurring.
199         * <p/>
200         * <p>This is a convience constructor and maintains the password internally via a character
201         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
202         * in your code could have possible security implications as noted in the class JavaDoc.</p>
203         *
204         * @param username   the username submitted for authentication
205         * @param password   the password string submitted for authentication
206         * @param rememberMe if the user wishes their identity to be remembered across sessions
207         * @param host       the host name or IP string from where the attempt is occuring
208         * @since 1.0
209         */
210        public UsernamePasswordToken(final String username, final String password,
211                                     final boolean rememberMe, final String host) {
212            this(username, password != null ? password.toCharArray() : null, rememberMe, host);
213        }
214    
215        /*--------------------------------------------
216        |  A C C E S S O R S / M O D I F I E R S    |
217        ============================================*/
218    
219        /**
220         * Returns the username submitted during an authentication attempt.
221         *
222         * @return the username submitted during an authentication attempt.
223         */
224        public String getUsername() {
225            return username;
226        }
227    
228        /**
229         * Sets the username for submission during an authentication attempt.
230         *
231         * @param username the username to be used for submission during an authentication attempt.
232         */
233        public void setUsername(String username) {
234            this.username = username;
235        }
236    
237    
238        /**
239         * Returns the password submitted during an authentication attempt as a character array.
240         *
241         * @return the password submitted during an authentication attempt as a character array.
242         */
243        public char[] getPassword() {
244            return password;
245        }
246    
247        /**
248         * Sets the password for submission during an authentication attempt.
249         *
250         * @param password the password to be used for submission during an authentication attemp.
251         */
252        public void setPassword(char[] password) {
253            this.password = password;
254        }
255    
256        /**
257         * Simply returns {@link #getUsername() getUsername()}.
258         *
259         * @return the {@link #getUsername() username}.
260         * @see org.apache.shiro.authc.AuthenticationToken#getPrincipal()
261         */
262        public Object getPrincipal() {
263            return getUsername();
264        }
265    
266        /**
267         * Returns the {@link #getPassword() password} char array.
268         *
269         * @return the {@link #getPassword() password} char array.
270         * @see org.apache.shiro.authc.AuthenticationToken#getCredentials()
271         */
272        public Object getCredentials() {
273            return getPassword();
274        }
275    
276        /**
277         * Returns the host name or IP string from where the authentication attempt occurs.  May be <tt>null</tt> if the
278         * host name/IP is unknown or explicitly omitted.  It is up to the Authenticator implementation processing this
279         * token if an authentication attempt without a host is valid or not.
280         * <p/>
281         * <p>(Shiro's default Authenticator allows <tt>null</tt> hosts to support localhost and proxy server environments).</p>
282         *
283         * @return the host from where the authentication attempt occurs, or <tt>null</tt> if it is unknown or
284         *         explicitly omitted.
285         * @since 1.0
286         */
287        public String getHost() {
288            return host;
289        }
290    
291        /**
292         * Sets the host name or IP string from where the authentication attempt occurs.  It is up to the Authenticator
293         * implementation processing this token if an authentication attempt without a host is valid or not.
294         * <p/>
295         * <p>(Shiro's default Authenticator
296         * allows <tt>null</tt> hosts to allow localhost and proxy server environments).</p>
297         *
298         * @param host the host name or IP string from where the attempt is occuring
299         * @since 1.0
300         */
301        public void setHost(String host) {
302            this.host = host;
303        }
304    
305        /**
306         * Returns <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered
307         * across sessions, <tt>false</tt> otherwise.  Unless overridden, this value is <tt>false</tt> by default.
308         *
309         * @return <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered
310         *         across sessions, <tt>false</tt> otherwise (<tt>false</tt> by default).
311         * @since 0.9
312         */
313        public boolean isRememberMe() {
314            return rememberMe;
315        }
316    
317        /**
318         * Sets if the submitting user wishes their identity (pricipal(s)) to be remembered across sessions.  Unless
319         * overridden, the default value is <tt>false</tt>, indicating <em>not</em> to be remembered across sessions.
320         *
321         * @param rememberMe value inidicating if the user wishes their identity (principal(s)) to be remembered across
322         *                   sessions.
323         * @since 0.9
324         */
325        public void setRememberMe(boolean 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        public void clear() {
338            this.username = null;
339            this.host = null;
340            this.rememberMe = false;
341    
342            if (this.password != 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 accidentially 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        public String toString() {
360            StringBuffer sb = new StringBuffer();
361            sb.append(getClass().getName());
362            sb.append(" - ");
363            sb.append(username);
364            sb.append(", rememberMe=").append(rememberMe);
365            if (host != null) {
366                sb.append(" (").append(host).append(")");
367            }
368            return sb.toString();
369        }
370    
371    }