| 1 17 package org.apache.geronimo.security.realm.providers; 18 19 import java.io.Serializable ; 20 import java.util.Map ; 21 import java.util.HashMap ; 22 import java.util.LinkedList ; 23 import java.util.Iterator ; 24 import javax.security.auth.Subject ; 25 import javax.security.auth.callback.Callback ; 26 import javax.security.auth.callback.CallbackHandler ; 27 import javax.security.auth.callback.NameCallback ; 28 import javax.security.auth.login.LoginException ; 29 import javax.security.auth.login.FailedLoginException ; 30 import javax.security.auth.spi.LoginModule ; 31 32 58 public class RepeatedFailureLockoutLoginModule implements LoginModule { 59 public static final String FAILURE_COUNT_OPTION = "failureCount"; 60 public static final String FAILURE_PERIOD_OPTION = "failurePeriodSecs"; 61 public static final String LOCKOUT_DURATION_OPTION = "lockoutDurationSecs"; 62 private static final HashMap userData = new HashMap (); 63 private CallbackHandler handler; 64 private String username; 65 private int failureCount = 5; 66 private int failurePeriod = 5 * 60 * 1000; 67 private int lockoutDuration = 30 * 60 * 1000; 68 69 72 public void initialize(Subject subject, CallbackHandler callbackHandler, 73 Map sharedState, Map options) { 74 String fcString = (String ) options.get(FAILURE_COUNT_OPTION); 75 if(fcString != null) { 76 fcString = fcString.trim(); 77 if(!fcString.equals("")) { 78 failureCount = Integer.parseInt(fcString); 79 } 80 } 81 String fpString = (String ) options.get(FAILURE_PERIOD_OPTION); 82 if(fpString != null) { 83 fpString = fpString.trim(); 84 if(!fpString.equals("")) { 85 failurePeriod = Integer.parseInt(fpString) * 1000; 86 } 87 } 88 String ldString = (String ) options.get(LOCKOUT_DURATION_OPTION); 89 if(ldString != null) { 90 ldString = ldString.trim(); 91 if(!ldString.equals("")) { 92 lockoutDuration = Integer.parseInt(ldString) * 1000; 93 } 94 } 95 handler = callbackHandler; 96 } 97 98 101 public boolean login() throws LoginException { 102 NameCallback user = new NameCallback ("User name:"); 103 Callback [] callbacks = new Callback []{user}; 104 try { 105 handler.handle(callbacks); 106 } catch (Exception e) { 107 throw new LoginException ("Unable to process callback: "+e); 108 } 109 if(callbacks.length != 1) { 110 throw new IllegalStateException ("Number of callbacks changed by server!"); 111 } 112 user = (NameCallback ) callbacks[0]; 113 username = user.getName(); 114 if(username != null) { 115 LoginHistory history; 116 synchronized (userData) { 117 history = (LoginHistory) userData.get(username); 118 } 119 if(history != null && !history.isLoginAllowed(lockoutDuration, failurePeriod, failureCount)) { 120 username = null; 121 throw new FailedLoginException ("Maximum login failures exceeded; try again later"); 122 } 123 } else { 124 return false; } 126 return true; 127 } 128 129 132 public boolean commit() throws LoginException { 133 return username != null; 134 } 135 136 140 public boolean abort() throws LoginException { 141 if(username != null) { LoginHistory history; 143 synchronized (userData) { 144 history = (LoginHistory) userData.get(username); 145 if(history == null) { 146 history = new LoginHistory(username); 147 userData.put(username, history); 148 } 149 } 150 history.addFailure(); 151 username = null; 152 return true; 153 } else { 154 return false; 155 } 156 } 157 158 161 public boolean logout() throws LoginException { 162 username = null; 163 handler = null; 164 return true; 165 } 166 167 171 private static class LoginHistory implements Serializable { 172 private String user; 173 private LinkedList data = new LinkedList (); 174 private long lockExpires = -1; 175 176 public LoginHistory(String user) { 177 this.user = user; 178 } 179 180 public String getUser() { 181 return user; 182 } 183 184 188 public synchronized boolean isLoginAllowed(int lockoutLengthMillis, int failureAgeMillis, int maxFailures) { 189 long now = System.currentTimeMillis(); 190 cleanup(now - failureAgeMillis); 191 if(lockExpires > now) { 192 return false; 193 } 194 if(data.size() >= maxFailures) { 195 lockExpires = ((Long )data.getLast()).longValue() + lockoutLengthMillis; 196 if(lockExpires > now) { 197 return false; 198 } 199 } 200 return true; 201 } 202 203 206 public synchronized void addFailure() { 207 data.add(new Long (System.currentTimeMillis())); 208 } 209 210 214 public synchronized void cleanup(long ignoreOlderThan) { 215 for (Iterator it = data.iterator(); it.hasNext();) { 216 Long time = (Long ) it.next(); 217 if(time.longValue() < ignoreOlderThan) { 218 it.remove(); 219 } else { 220 break; 221 } 222 } 223 } 224 } 225 } 226 | Popular Tags |