1 22 package org.jboss.security.srp.jaas; 23 24 import java.rmi.Naming ; 25 import java.security.Principal ; 26 import java.util.Hashtable ; 27 import java.util.Map ; 28 import java.util.Set ; 29 import java.util.ArrayList ; 30 import java.io.Serializable ; 31 import javax.naming.InitialContext ; 32 import javax.security.auth.Subject ; 33 import javax.security.auth.callback.CallbackHandler ; 34 import javax.security.auth.callback.Callback ; 35 import javax.security.auth.callback.NameCallback ; 36 import javax.security.auth.callback.PasswordCallback ; 37 import javax.security.auth.callback.TextInputCallback ; 38 import javax.security.auth.callback.UnsupportedCallbackException ; 39 import javax.security.auth.login.LoginException ; 40 import javax.security.auth.spi.LoginModule ; 41 42 import org.jboss.logging.Logger; 43 import org.jboss.security.Util; 44 import org.jboss.security.auth.callback.ByteArrayCallback; 45 import org.jboss.security.srp.SRPClientSession; 46 import org.jboss.security.srp.SRPParameters; 47 import org.jboss.security.srp.SRPServerInterface; 48 49 78 public class SRPLoginModule implements LoginModule 79 { 80 private Subject subject; 81 private CallbackHandler handler; 82 private Map sharedState; 83 private Hashtable jndiEnv; 84 private String principalClassName; 85 private String srpServerRmiUrl; 86 private String srpServerJndiName; 87 private String username; 88 private char[] password; 89 private SRPServerInterface srpServer; 90 private SRPParameters params; 91 private Principal userPrincipal; 92 private Integer sessionID; 93 private byte[] sessionKey; 94 private byte[] abytes; 95 private Object auxChallenge; 96 private boolean externalRandomA; 97 private boolean hasAuxChallenge; 98 private boolean multipleSessions; 99 private boolean loginFailed; 100 private Logger log; 101 102 103 public SRPLoginModule() 104 { 105 } 106 107 127 public void initialize(Subject subject, CallbackHandler handler, Map sharedState, 128 Map options) 129 { 130 log = Logger.getLogger(getClass()); 131 this.jndiEnv = new Hashtable (options); 132 this.subject = subject; 133 this.handler = handler; 134 this.sharedState = sharedState; 135 principalClassName = (String ) options.get("principalClassName"); 136 if( principalClassName != null ) 137 log.warn("The principalClassName is no longer used, its always SRPPrincipal"); 138 srpServerJndiName = (String ) options.get("srpServerJndiName"); 139 srpServerRmiUrl = (String ) options.get("srpServerRmiUrl"); 140 String tmp = (String ) options.get("externalRandomA"); 141 if( tmp != null ) 142 externalRandomA = Boolean.valueOf(tmp).booleanValue(); 143 multipleSessions = false; 144 tmp = (String ) options.get("multipleSessions"); 145 if( tmp != null ) 146 multipleSessions = Boolean.valueOf(tmp).booleanValue(); 147 tmp = (String ) options.get("hasAuxChallenge"); 148 if( tmp != null ) 149 hasAuxChallenge = Boolean.valueOf(tmp).booleanValue(); 150 151 154 jndiEnv.remove("principalClassName"); 155 jndiEnv.remove("srpServerJndiName"); 156 jndiEnv.remove("srpServerRmiUrl"); 157 jndiEnv.remove("externalRandomA"); 158 jndiEnv.remove("multipleSessions"); 159 jndiEnv.remove("hasAuxChallenge"); 160 161 } 162 163 167 public boolean login() throws LoginException 168 { 169 boolean trace = log.isTraceEnabled(); 170 loginFailed = true; 171 getUserInfo(); 172 if( srpServerJndiName != null ) 174 { 175 srpServer = loadServerFromJndi(srpServerJndiName); 176 } 177 else if( srpServerRmiUrl != null ) 178 { 179 srpServer = loadServer(srpServerRmiUrl); 180 } 181 else 182 { 183 throw new LoginException ("No option specified to access a SRPServerInterface instance"); 184 } 185 if( srpServer == null ) 186 throw new LoginException ("Failed to access a SRPServerInterface instance"); 187 188 byte[] M1, M2; 189 SRPClientSession client = null; 190 try 191 { if( trace ) 193 log.trace("Getting SRP parameters for username: "+username); 194 Util.init(); 195 Object [] sessionInfo = srpServer.getSRPParameters(username, multipleSessions); 196 params = (SRPParameters) sessionInfo[0]; 197 sessionID = (Integer ) sessionInfo[1]; 198 if( sessionID == null ) 199 sessionID = new Integer (0); 200 if( trace ) 201 { 202 log.trace("SessionID: "+sessionID); 203 log.trace("N: "+Util.tob64(params.N)); 204 log.trace("g: "+Util.tob64(params.g)); 205 log.trace("s: "+Util.tob64(params.s)); 206 log.trace("cipherAlgorithm: "+params.cipherAlgorithm); 207 log.trace("hashAlgorithm: "+params.hashAlgorithm); 208 } 209 byte[] hn = Util.newDigest().digest(params.N); 210 if( trace ) 211 log.trace("H(N): "+Util.tob64(hn)); 212 byte[] hg = Util.newDigest().digest(params.g); 213 if( trace ) 214 { 215 log.trace("H(g): "+Util.tob64(hg)); 216 log.trace("Creating SRPClientSession"); 217 } 218 219 if( abytes != null ) 220 client = new SRPClientSession(username, password, params, abytes); 221 else 222 client = new SRPClientSession(username, password, params); 223 if( trace ) 224 log.trace("Generating client public key"); 225 226 byte[] A = client.exponential(); 227 if( trace ) 228 log.trace("Exchanging public keys"); 229 byte[] B = srpServer.init(username, A, sessionID.intValue()); 230 if( trace ) 231 log.trace("Generating server challenge"); 232 M1 = client.response(B); 233 234 if( trace ) 235 log.trace("Exchanging challenges"); 236 sessionKey = client.getSessionKey(); 237 if( auxChallenge != null ) 238 { 239 auxChallenge = encryptAuxChallenge(auxChallenge, params.cipherAlgorithm, 240 params.cipherIV, sessionKey); 241 M2 = srpServer.verify(username, M1, auxChallenge, sessionID.intValue()); 242 } 243 else 244 { 245 M2 = srpServer.verify(username, M1, sessionID.intValue()); 246 } 247 } 248 catch(Exception e) 249 { 250 log.warn("Failed to complete SRP login", e); 251 throw new LoginException ("Failed to complete SRP login, msg="+e.getMessage()); 252 } 253 254 if( trace ) 255 log.trace("Verifying server response"); 256 if( client.verify(M2) == false ) 257 throw new LoginException ("Failed to validate server reply"); 258 if( trace ) 259 log.trace("Login succeeded"); 260 261 userPrincipal = new SRPPrincipal(username, sessionID); 263 sharedState.put("javax.security.auth.login.name", userPrincipal); 264 sharedState.put("javax.security.auth.login.password", M1); 265 loginFailed = false; 266 return true; 267 } 268 269 277 public boolean commit() throws LoginException 278 { 279 if( loginFailed == true ) 280 return false; 281 282 subject.getPrincipals().add(userPrincipal); 284 Set privateCredentials = subject.getPrivateCredentials(); 285 privateCredentials.add(sessionKey); 286 if( sessionID != null ) 287 privateCredentials.add(sessionID); 288 if( params.cipherAlgorithm != null ) 289 { 290 Object secretKey = createSecretKey(params.cipherAlgorithm, sessionKey); 291 privateCredentials.add(secretKey); 292 } 293 privateCredentials.add(params); 294 295 return true; 296 } 297 298 public boolean abort() throws LoginException 299 { 300 username = null; 301 password = null; 302 return true; 303 } 304 305 310 public boolean logout() throws LoginException 311 { 312 try 313 { 314 if( subject.isReadOnly() == false ) 315 { Set s = subject.getPrincipals(userPrincipal.getClass()); 317 s.remove(userPrincipal); 318 subject.getPrivateCredentials().remove(sessionKey); 319 } 320 if( srpServer != null ) 321 { 322 srpServer.close(username, sessionID.intValue()); 323 } 324 } 325 catch(Exception e) 326 { 327 throw new LoginException ("Failed to remove user principal, "+e.getMessage()); 328 } 329 return true; 330 } 331 332 334 private void getUserInfo() throws LoginException 335 { 336 String _username = (String ) sharedState.get("javax.security.auth.login.name"); 338 char[] _password = null; 339 if( _username != null ) 340 { 341 Object pw = sharedState.get("javax.security.auth.login.password"); 342 if( pw instanceof char[] ) 343 _password = (char[]) pw; 344 else if( pw != null ) 345 _password = pw.toString().toCharArray(); 346 } 347 348 if( _username != null && _password != null ) 350 { 351 username = _username; 352 password = _password; 353 return; 354 } 355 356 if( handler == null ) 358 throw new LoginException ("No CallbackHandler provied to SRPLoginModule"); 359 360 NameCallback nc = new NameCallback ("Username: ", "guest"); 361 PasswordCallback pc = new PasswordCallback ("Password: ", false); 362 ByteArrayCallback bac = new ByteArrayCallback("Public key random number: "); 363 TextInputCallback tic = new TextInputCallback ("Auxillary challenge token: "); 364 ArrayList tmpList = new ArrayList (); 365 tmpList.add(nc); 366 tmpList.add(pc); 367 if( externalRandomA == true ) 368 tmpList.add(bac); 369 if( hasAuxChallenge == true ) 370 tmpList.add(tic); 371 Callback [] callbacks = new Callback [tmpList.size()]; 372 tmpList.toArray(callbacks); 373 try 374 { 375 handler.handle(callbacks); 376 username = nc.getName(); 377 _password = pc.getPassword(); 378 if( _password != null ) 379 password = _password; 380 pc.clearPassword(); 381 if( externalRandomA == true ) 382 abytes = bac.getByteArray(); 383 if( hasAuxChallenge == true ) 384 this.auxChallenge = tic.getText(); 385 } 386 catch(java.io.IOException e) 387 { 388 throw new LoginException (e.toString()); 389 } 390 catch(UnsupportedCallbackException uce) 391 { 392 throw new LoginException ("UnsupportedCallback: " + uce.getCallback().toString()); 393 } 394 } 395 396 private SRPServerInterface loadServerFromJndi(String jndiName) 397 { 398 SRPServerInterface server = null; 399 try 400 { 401 InitialContext ctx = new InitialContext (jndiEnv); 402 server = (SRPServerInterface) ctx.lookup(jndiName); 403 } 404 catch(Exception e) 405 { 406 log.error("Failed to lookup("+jndiName+")", e); 407 } 408 return server; 409 } 410 private SRPServerInterface loadServer(String rmiUrl) 411 { 412 SRPServerInterface server = null; 413 try 414 { 415 server = (SRPServerInterface) Naming.lookup(rmiUrl); 416 } 417 catch(Exception e) 418 { 419 log.error("Failed to lookup("+rmiUrl+")", e); 420 } 421 return server; 422 } 423 424 427 private Object encryptAuxChallenge(Object challenge, String cipherAlgorithm, 428 byte[] cipherIV, Object key) 429 throws LoginException 430 { 431 if( cipherAlgorithm == null ) 432 return challenge; 433 Object sealedObject = null; 434 try 435 { 436 Serializable data = (Serializable ) challenge; 437 Object tmpKey = Util.createSecretKey(cipherAlgorithm, key); 438 sealedObject = Util.createSealedObject(cipherAlgorithm, tmpKey, cipherIV, data); 439 } 440 catch(Exception e) 441 { 442 log.error("Failed to encrypt aux challenge", e); 443 throw new LoginException ("Failed to encrypt aux challenge"); 444 } 445 return sealedObject; 446 } 447 448 452 private Object createSecretKey(String cipherAlgorithm, Object key) throws LoginException 453 { 454 Object secretKey = null; 455 try 456 { 457 secretKey = Util.createSecretKey(cipherAlgorithm, key); 458 } 459 catch(Exception e) 460 { 461 log.error("Failed to create SecretKey", e); 462 throw new LoginException ("Failed to create SecretKey"); 463 } 464 return secretKey; 465 } 466 } 467 | Popular Tags |