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     * @since 0.1
044     */
045    public class UsernamePasswordToken implements HostAuthenticationToken, RememberMeAuthenticationToken {
046    
047        /*--------------------------------------------
048        |             C O N S T A N T S             |
049        ============================================*/
050    
051        /*--------------------------------------------
052        |    I N S T A N C E   V A R I A B L E S    |
053        ============================================*/
054        /**
055         * The username
056         */
057        private String username;
058    
059        /**
060         * The password, in char[] format
061         */
062        private char[] password;
063    
064        /**
065         * Whether or not 'rememberMe' should be enabled for the corresponding login attempt;
066         * default is <code>false</code>
067         */
068        private boolean rememberMe = false;
069    
070        /**
071         * The location from where the login attempt occurs, or <code>null</code> if not known or explicitly
072         * omitted.
073         */
074        private String host;
075    
076        /*--------------------------------------------
077        |         C O N S T R U C T O R S           |
078        ============================================*/
079    
080        /**
081         * JavaBeans compatible no-arg constructor.
082         */
083        public UsernamePasswordToken() {
084        }
085    
086        /**
087         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted
088         * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and a
089         * <tt>rememberMe</tt> default of <tt>false</tt>.
090         *
091         * @param username the username submitted for authentication
092         * @param password the password character array submitted for authentication
093         */
094        public UsernamePasswordToken(final String username, final char[] password) {
095            this(username, password, false, null);
096        }
097    
098        /**
099         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted
100         * during an authentication attempt, with a <tt>null</tt> {@link #getHost() host} and
101         * a <tt>rememberMe</tt> default of <tt>false</tt>
102         * <p/>
103         * <p>This is a convience constructor and maintains the password internally via a character
104         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
105         * in your code could have possible security implications as noted in the class JavaDoc.</p>
106         *
107         * @param username the username submitted for authentication
108         * @param password the password string submitted for authentication
109         */
110        public UsernamePasswordToken(final String username, final String password) {
111            this(username, password != null ? password.toCharArray() : null, false, null);
112        }
113    
114        /**
115         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the
116         * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt>
117         *
118         * @param username the username submitted for authentication
119         * @param password the password string submitted for authentication
120         * @param host     the host name or IP string from where the attempt is occuring
121         * @since 0.2
122         */
123        public UsernamePasswordToken(final String username, final char[] password, final String host) {
124            this(username, password, false, host);
125        }
126    
127        /**
128         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, the
129         * inetAddress from where the attempt is occurring, and a default <tt>rememberMe</tt> value of <tt>false</tt>
130         * <p/>
131         * <p>This is a convience constructor and maintains the password internally via a character
132         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
133         * in your code could have possible security implications as noted in the class JavaDoc.</p>
134         *
135         * @param username the username submitted for authentication
136         * @param password the password string submitted for authentication
137         * @param host     the host name or IP string from where the attempt is occuring
138         * @since 1.0
139         */
140        public UsernamePasswordToken(final String username, final String password, final String host) {
141            this(username, password != null ? password.toCharArray() : null, false, host);
142        }
143    
144        /**
145         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user
146         * wishes their identity to be remembered across sessions.
147         *
148         * @param username   the username submitted for authentication
149         * @param password   the password string submitted for authentication
150         * @param rememberMe if the user wishes their identity to be remembered across sessions
151         * @since 0.9
152         */
153        public UsernamePasswordToken(final String username, final char[] password, final boolean rememberMe) {
154            this(username, password, rememberMe, null);
155        }
156    
157        /**
158         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, as well as if the user
159         * wishes their identity to be remembered across sessions.
160         * <p/>
161         * <p>This is a convience constructor and maintains the password internally via a character
162         * array, i.e. <tt>password.toCharArray();</tt>.  Note that storing a password as a String
163         * in your code could have possible security implications as noted in the class JavaDoc.</p>
164         *
165         * @param username   the username submitted for authentication
166         * @param password   the password string submitted for authentication
167         * @param rememberMe if the user wishes their identity to be remembered across sessions
168         * @since 0.9
169         */
170        public UsernamePasswordToken(final String username, final String password, final boolean rememberMe) {
171            this(username, password != null ? password.toCharArray() : null, rememberMe, null);
172        }
173    
174        /**
175         * Constructs a new UsernamePasswordToken encapsulating the username and password submitted, if the user
176         * wishes their identity to be remembered across sessions, and the inetAddress from where the attempt is ocurring.
177         *
178         * @param username   the username submitted for authentication
179         * @param password   the password character array submitted for authentication
180         * @param rememberMe if the user wishes their identity to be remembered across sessions
181         * @param host       the host name or IP string from where the attempt is occuring
182         * @since 1.0
183         */
184        public UsernamePasswordToken(final String username, final char[] password,
185                                     final boolean rememberMe, final String host) {
186    
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 ocurring.
197         * <p/>
198         * <p>This is a convience 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 occuring
206         * @since 1.0
207         */
208        public UsernamePasswordToken(final String username, final String password,
209                                     final boolean rememberMe, final String host) {
210            this(username, password != null ? password.toCharArray() : null, rememberMe, host);
211        }
212    
213        /*--------------------------------------------
214        |  A C C E S S O R S / M O D I F I E R S    |
215        ============================================*/
216    
217        /**
218         * Returns the username submitted during an authentication attempt.
219         *
220         * @return the username submitted during an authentication attempt.
221         */
222        public String getUsername() {
223            return username;
224        }
225    
226        /**
227         * Sets the username for submission during an authentication attempt.
228         *
229         * @param username the username to be used for submission during an authentication attempt.
230         */
231        public void setUsername(String username) {
232            this.username = username;
233        }
234    
235    
236        /**
237         * Returns the password submitted during an authentication attempt as a character array.
238         *
239         * @return the password submitted during an authentication attempt as a character array.
240         */
241        public char[] getPassword() {
242            return password;
243        }
244    
245        /**
246         * Sets the password for submission during an authentication attempt.
247         *
248         * @param password the password to be used for submission during an authentication attemp.
249         */
250        public void setPassword(char[] password) {
251            this.password = password;
252        }
253    
254        /**
255         * Simply returns {@link #getUsername() getUsername()}.
256         *
257         * @return the {@link #getUsername() username}.
258         * @see org.apache.shiro.authc.AuthenticationToken#getPrincipal()
259         */
260        public Object getPrincipal() {
261            return getUsername();
262        }
263    
264        /**
265         * Returns the {@link #getPassword() password} char array.
266         *
267         * @return the {@link #getPassword() password} char array.
268         * @see org.apache.shiro.authc.AuthenticationToken#getCredentials()
269         */
270        public Object getCredentials() {
271            return getPassword();
272        }
273    
274        /**
275         * Returns the host name or IP string from where the authentication attempt occurs.  May be <tt>null</tt> if the
276         * host name/IP is unknown or explicitly omitted.  It is up to the Authenticator implementation processing this
277         * token if an authentication attempt without a host is valid or not.
278         * <p/>
279         * <p>(Shiro's default Authenticator allows <tt>null</tt> hosts to support localhost and proxy server environments).</p>
280         *
281         * @return the host from where the authentication attempt occurs, or <tt>null</tt> if it is unknown or
282         *         explicitly omitted.
283         * @since 1.0
284         */
285        public String getHost() {
286            return host;
287        }
288    
289        /**
290         * Sets the host name or IP string from where the authentication attempt occurs.  It is up to the Authenticator
291         * implementation processing this token if an authentication attempt without a host is valid or not.
292         * <p/>
293         * <p>(Shiro's default Authenticator
294         * allows <tt>null</tt> hosts to allow localhost and proxy server environments).</p>
295         *
296         * @param host the host name or IP string from where the attempt is occuring
297         * @since 1.0
298         */
299        public void setHost(String host) {
300            this.host = host;
301        }
302    
303        /**
304         * Returns <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered
305         * across sessions, <tt>false</tt> otherwise.  Unless overridden, this value is <tt>false</tt> by default.
306         *
307         * @return <tt>true</tt> if the submitting user wishes their identity (principal(s)) to be remembered
308         *         across sessions, <tt>false</tt> otherwise (<tt>false</tt> by default).
309         * @since 0.9
310         */
311        public boolean isRememberMe() {
312            return rememberMe;
313        }
314    
315        /**
316         * Sets if the submitting user wishes their identity (pricipal(s)) to be remembered across sessions.  Unless
317         * overridden, the default value is <tt>false</tt>, indicating <em>not</em> to be remembered across sessions.
318         *
319         * @param rememberMe value inidicating if the user wishes their identity (principal(s)) to be remembered across
320         *                   sessions.
321         * @since 0.9
322         */
323        public void setRememberMe(boolean rememberMe) {
324            this.rememberMe = rememberMe;
325        }
326    
327        /*--------------------------------------------
328        |               M E T H O D S               |
329        ============================================*/
330    
331        /**
332         * Clears out (nulls) the username, password, rememberMe, and inetAddress.  The password bytes are explicitly set to
333         * <tt>0x00</tt> before nulling to eliminate the possibility of memory access at a later time.
334         */
335        public void clear() {
336            this.username = null;
337            this.host = null;
338            this.rememberMe = false;
339    
340            if (this.password != null) {
341                for (int i = 0; i < password.length; i++) {
342                    this.password[i] = 0x00;
343                }
344                this.password = null;
345            }
346    
347        }
348    
349        /**
350         * Returns the String representation.  It does not include the password in the resulting
351         * string for security reasons to prevent accidentially printing out a password
352         * that might be widely viewable).
353         *
354         * @return the String representation of the <tt>UsernamePasswordToken</tt>, omitting
355         *         the password.
356         */
357        public String toString() {
358            StringBuilder sb = new StringBuilder();
359            sb.append(getClass().getName());
360            sb.append(" - ");
361            sb.append(username);
362            sb.append(", rememberMe=").append(rememberMe);
363            if (host != null) {
364                sb.append(" (").append(host).append(")");
365            }
366            return sb.toString();
367        }
368    
369    }