KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > db > CmsLoginManager


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/db/CmsLoginManager.java,v $
3  * Date : $Date: 2005/06/23 11:11:24 $
4  * Version: $Revision: 1.6 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.db;
33
34 import org.opencms.file.CmsObject;
35 import org.opencms.main.OpenCms;
36 import org.opencms.security.CmsAuthentificationException;
37 import org.opencms.security.CmsRole;
38 import org.opencms.security.CmsRoleViolationException;
39 import org.opencms.security.Messages;
40
41 import java.util.Date JavaDoc;
42 import java.util.Hashtable JavaDoc;
43
44 /**
45  * Provides functions used to check the validity of a user login.<p>
46  *
47  * Stores invalid login attempts and disables a user account temporarily in case
48  * the configured threshold of invalid logins is reached.<p>
49  *
50  * The invalid login attempt storage operates on a combination of user name, login remote IP address and
51  * user type. This means that a user can be disabled for one remote IP, but still be enabled for
52  * another rempte IP.<p>
53  *
54  * Also allows to temporarily disallow logins (for example in case of maintainance work on the system).<p>
55  *
56  * @author Alexander Kandzior
57  *
58  * @version $Revision: 1.6 $
59  *
60  * @since 6.0.0
61  */

62 public class CmsLoginManager {
63
64     /**
65      * Contains the data stored for each user in the storage for invalid login attempts.<p>
66      */

67     private class CmsUserData {
68
69         /** The start time this account was disabled. */
70         private long m_disableTimeStart;
71
72         /** The count of the failed attempts. */
73         private int m_invalidLoginCount;
74
75         /**
76          * Creates a new user data instance.<p>
77          */

78         protected CmsUserData() {
79
80             // a new instance is creted only if there already was one failed attempt
81
m_invalidLoginCount = 1;
82         }
83
84         /**
85          * Returns the bad attempt count for this user.<p>
86          *
87          * @return the bad attempt count for this user
88          */

89         protected Integer JavaDoc getInvalidLoginCount() {
90
91             return new Integer JavaDoc(m_invalidLoginCount);
92         }
93
94         /**
95          * Returns the date this disabled user is released again.<p>
96          *
97          * @return the date this disabled user is released again
98          */

99         protected Date JavaDoc getReleaseDate() {
100
101             return new Date JavaDoc(m_disableTimeStart + m_disableMillis + 1);
102         }
103
104         /**
105          * Increases the bad attempt count, disables the data in case the
106          * configured threshold is reached.<p>
107          */

108         protected void increaseInvalidLoginCount() {
109
110             m_invalidLoginCount++;
111             if (m_invalidLoginCount >= m_maxBadAttempts) {
112                 // threshold for bad login attempts has been reached for this user
113
if (m_disableTimeStart == 0) {
114                     // only disable in case this user has not already been disabled
115
m_disableTimeStart = System.currentTimeMillis();
116                 }
117             }
118         }
119
120         /**
121          * Returns <code>true</code> in case this user has been temporarily disabled.<p>
122          *
123          * @return <code>true</code> in case this user has been temporarily disabled
124          */

125         protected boolean isDisabled() {
126
127             if (m_disableTimeStart > 0) {
128                 // check if the disable time is already over
129
long currentTime = System.currentTimeMillis();
130                 if ((currentTime - m_disableTimeStart) > m_disableMillis) {
131                     // disable time is over
132
m_disableTimeStart = 0;
133                 }
134             }
135             return m_disableTimeStart > 0;
136         }
137     }
138
139     /** Default lock time if treshold for bad login attempts is reached. */
140     public static final int DISABLE_MINUTES_DEFAULT = 15;
141
142     /** Default for bad login attempts. */
143     public static final int MAX_BAD_ATTEMPTS_DEFAULT = 3;
144
145     /** The milliseconds to disable an account if the threshold is reached. */
146     protected int m_disableMillis;
147
148     /** The minutes to disable an account if the threshold is reached. */
149     protected int m_disableMinutes;
150
151     /** The number of bad login attempts allowed before an account is temporarily disabled. */
152     protected int m_maxBadAttempts;
153
154     /** The storage for the bad login attempts. */
155     protected Hashtable JavaDoc m_storage;
156
157     /** The login message, setting this may also disable logins for non-Admin users. */
158     private CmsLoginMessage m_loginMessage;
159
160     /**
161      * Creates a new storage for invalid logins.<p>
162      *
163      * @param disableMinutes the minutes to disable an account if the threshold is reached
164      * @param maxBadAttempts the number of bad login attempts allowed before an account is temporarily disabled
165      */

166     public CmsLoginManager(int disableMinutes, int maxBadAttempts) {
167
168         m_maxBadAttempts = maxBadAttempts;
169         if (m_maxBadAttempts >= 0) {
170             // otherwise the invalid login storage is sisabled
171
m_disableMinutes = disableMinutes;
172             m_disableMillis = disableMinutes * 60 * 1000;
173             m_storage = new Hashtable JavaDoc();
174         }
175     }
176
177     /**
178      * Returns the key to use for looking up the user in the invalid login storage.<p>
179      *
180      * @param userName the name of the user
181      * @param type the type of the user
182      * @param remoteAddress the remore address (IP) from which the login attempt was made
183      *
184      * @return the key to use for looking up the user in the invalid login storage
185      */

186     private static String JavaDoc createStorageKey(String JavaDoc userName, int type, String JavaDoc remoteAddress) {
187
188         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
189         result.append(userName);
190         result.append('_');
191         result.append(type);
192         result.append('_');
193         result.append(remoteAddress);
194         return result.toString();
195     }
196
197     /**
198      * Checks if the threshold for the invalid logins has been reached for the given user.<p>
199      *
200      * In case the configured threshold is reached, an Exception is thrown.<p>
201      *
202      * @param userName the name of the user
203      * @param type the type of the user
204      * @param remoteAddress the remore address (IP) from which the login attempt was made
205      *
206      * @throws CmsAuthentificationException in case the threshold of invalid login attempts has been reached
207      */

208     public void checkInvalidLogins(String JavaDoc userName, int type, String JavaDoc remoteAddress) throws CmsAuthentificationException {
209
210         if (m_maxBadAttempts < 0) {
211             // invalid login storage is disabled
212
return;
213         }
214
215         String JavaDoc key = createStorageKey(userName, type, remoteAddress);
216         // look up the user in the storage
217
CmsUserData userData = (CmsUserData)m_storage.get(key);
218         if ((userData != null) && (userData.isDisabled())) {
219             // threshold of invalid logins is reached
220
throw new CmsAuthentificationException(Messages.get().container(
221                 Messages.ERR_LOGIN_FAILED_TEMP_DISABLED_5,
222                 new Object JavaDoc[] {
223                     userName,
224                     new Integer JavaDoc(type),
225                     remoteAddress,
226                     userData.getReleaseDate(),
227                     userData.getInvalidLoginCount()}));
228         }
229     }
230
231     /**
232      * Checks if a login is currently allowed.<p>
233      *
234      * In case no logins are allowed, an Exception is thrown.<p>
235      *
236      * @throws CmsAuthentificationException in case no logins are allowed
237      */

238     public void checkLoginAllowed() throws CmsAuthentificationException {
239
240         if ((m_loginMessage != null) && (m_loginMessage.isLoginCurrentlyForbidden())) {
241             // login message has been set and is active
242
throw new CmsAuthentificationException(Messages.get().container(
243                 Messages.ERR_LOGIN_FAILED_WITH_MESSAGE_1,
244                 m_loginMessage.getMessage()));
245         }
246     }
247
248     /**
249      * Returns the minutes an account gets disabled after too many failed login attempts.<p>
250      *
251      * @return the minutes an account gets disabled after too many failed login attempts
252      */

253     public int getDisableMinutes() {
254
255         return m_disableMinutes;
256     }
257
258     /**
259      * Returns the current login message that is displayed if a user logs in.<p>
260      *
261      * if <code>null</code> is returned, no login message has been currently set.<p>
262      *
263      * @return the current login message that is displayed if a user logs in
264      */

265     public CmsLoginMessage getLoginMessage() {
266
267         return m_loginMessage;
268     }
269
270     /**
271      * Returns the number of bad login attempts allowed before an account is temporarily disabled.<p>
272      *
273      * @return the number of bad login attempts allowed before an account is temporarily disabled
274      */

275     public int getMaxBadAttempts() {
276
277         return m_maxBadAttempts;
278     }
279
280     /**
281      * Removes the current login message.<p>
282      *
283      * This operation requires that the current user has role permissions of <code>{@link CmsRole#ADMINISTRATOR}</code>.<p>
284      *
285      * @param cms the current OpenCms user context
286      *
287      * @throws CmsRoleViolationException in case the current user does not have the required role permissions
288      */

289     public void removeLoginMessage(CmsObject cms) throws CmsRoleViolationException {
290
291         cms.checkRole(CmsRole.ADMINISTRATOR);
292         m_loginMessage = null;
293     }
294
295     /**
296      * Sets the login message to display if a user logs in.<p>
297      *
298      * This operation requires that the current user has role permissions of <code>{@link CmsRole#ADMINISTRATOR}</code>.<p>
299      *
300      * @param cms the current OpenCms user context
301      * @param message the message to set
302      *
303      * @throws CmsRoleViolationException in case the current user does not have the required role permissions
304      */

305     public void setLoginMessage(CmsObject cms, CmsLoginMessage message) throws CmsRoleViolationException {
306
307         if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) {
308             // during configuration phase no permission check id required
309
cms.checkRole(CmsRole.ADMINISTRATOR);
310         }
311         m_loginMessage = message;
312         if (m_loginMessage != null) {
313             m_loginMessage.setFrozen();
314         }
315     }
316
317     /**
318      * Adds an invalid attempt to login for the given user / IP to the storage.<p>
319      *
320      * In case the configured threshold is reached, the user is disabled for the configured time.<p>
321      *
322      * @param userName the name of the user
323      * @param type the type of the user
324      * @param remoteAddress the remore address (IP) from which the login attempt was made
325      */

326     protected void addInvalidLogin(String JavaDoc userName, int type, String JavaDoc remoteAddress) {
327
328         if (m_maxBadAttempts < 0) {
329             // invalid login storage is disabled
330
return;
331         }
332
333         String JavaDoc key = createStorageKey(userName, type, remoteAddress);
334         // look up the user in the storage
335
CmsUserData userData = (CmsUserData)m_storage.get(key);
336         if (userData != null) {
337             // user data already contained in storage
338
userData.increaseInvalidLoginCount();
339         } else {
340             // create an new data object for this user
341
userData = new CmsUserData();
342             m_storage.put(key, userData);
343         }
344     }
345
346     /**
347      * Removes all invalid attempts to login for the given user / IP.<p>
348      *
349      * @param userName the name of the user
350      * @param type the type of the user
351      * @param remoteAddress the remore address (IP) from which the login attempt was made
352      */

353     protected void removeInvalidLogins(String JavaDoc userName, int type, String JavaDoc remoteAddress) {
354
355         if (m_maxBadAttempts < 0) {
356             // invalid login storage is disabled
357
return;
358         }
359
360         String JavaDoc key = createStorageKey(userName, type, remoteAddress);
361         // just remove the user from the storage
362
m_storage.remove(key);
363     }
364 }
Popular Tags