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 */
019package 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 */
045public 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}