|
What this is
Other links
The source code/* $Id: OTPAuthenticator.java,v 1.1.1.1 2002/10/02 18:42:55 wastl Exp $ */ import net.wastl.webmail.server.*; import net.wastl.webmail.exceptions.*; import net.wastl.webmail.config.ConfigScheme; import org.webengruven.javaOTP.*; import org.webengruven.webmail.auth.*; import java.util.*; import java.security.NoSuchAlgorithmException; /** * OTPAuthenticator.java -- this class is an Authenticator for * Webmail/Java that uses One Time Passwords for authentication. Using the * new challenge/response authentication framework, this class will provide * authentication based on RFC1938 one time passes. * * @author Devin Kowatch * @version $Revision: 1.1.1.1 $ * * Copyright (C) 2000 Devin Kowatch */ /* This program is free software; you can redistribute it and/or * modify it under the terms of the Lesser GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Lesser GNU General Public License for more details. * * You should have received a copy of the Lesser GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ public class OTPAuthenticator extends OTPAuthenticatorIface { /** The version of OTPAuthenticator */ public final String VERSION = "1.2"; /** The default starting sequence for an OTP */ public final int START_SEQ = 499; /** The default hash algorithm for an OTP */ public final String DFLT_HASH = "MD5"; private final int CACHE_ACTIVE_ST = 0x01; private final int CACHE_NEW_ST = 0x02; /** Default Constructor */ public OTPAuthenticator() { super(); key = "OTP"; cache = new Hashtable(); } /** Get the AuthDisplayMngr for this class */ public AuthDisplayMngr getAuthDisplayMngr() { if (disp_mngr == null) { disp_mngr = new OTPAuthDisplayMngr(this); } return disp_mngr; } /** Get this class' version * @return A version string for this class */ public String getVersion() { return VERSION; } /** * (Re-)Initilize this authenticator. */ public void init(Storage store) { } /** Register this authenticator with the system. */ public void register(ConfigScheme store) { store.configAddChoice("AUTH", key, "Simple OTP Authentication. The" + " server admin must create the account," + " users can change passwords"); } /** * Get a new challenge for changing the password. This will be * displayed on the screen when the user tries to change their * password. * @param udata The users data, this may be needed when re-keying the * password. */ public String getNewChallenge(UserData udata) throws WebMailException { OTPState [] states = new OTPState[2]; OTPState st, new_st; String chal = null; Random rand = new Random(); OTPServer server = null; String pData = null; boolean newAccount = false; getFromCache(udata.getLogin(), CACHE_ACTIVE_ST | CACHE_NEW_ST, states); // for convience st = states[0]; new_st = states[1]; if (st == null) { // Not in the cache, lets see if they have logged in before pData = udata.getPasswordData(); if (pData != null && pData.length() > 0) { st = new OTPState(pData); } else { // later code expects st to be set st = new OTPState("","","",DFLT_HASH); newAccount = true; } } try { // setup the new seed and seq. if (new_st == null) { // Get a random value between (0, 10000], and pad to 4 chars. int randVal = rand.nextInt() % 9999; StringBuffer newSeed = new StringBuffer(10); newSeed.append(udata.getDomain().substring(0, 2)); if (randVal < 0) randVal = -randVal; if (randVal > 999) { // 4 digits already, no pad } else if (randVal > 99) { // 3 digits only, pad 1 newSeed.append("0"); } else if (randVal > 9) { // 2 digits only, pad 2 newSeed.append("00"); } else { // 1 digit only, pad 3 newSeed.append("000"); } newSeed.append(String.valueOf(randVal)); new_st = new OTPState(st); new_st.seed = newSeed.toString(); new_st.sequence = String.valueOf(START_SEQ); } // if this is a new account don't use an instance of OTPServer if (newAccount) { chal=OTPServer.getNewChallenge(new_st.seed,START_SEQ,DFLT_HASH); } else { server = new OTPServer(st); chal = server.getNewChallenge(new_st.seed, START_SEQ); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new WebMailException("bad hash algorithm for new OTP."); } // for new accounts, st is a dummy. As such it should not be // stored in the cache where it will cause problems by being used if (newAccount) { st = null; } // keep track of the new OTPState for changePassword() putIntoCache(udata.getLogin(), st, new_st); return chal; } /** Authenticate the user. */ public void authenticatePostUserData(UserData ud,String dom,String pass) throws InvalidPasswordException { String login = ud.getLogin(); OTPCacheNode n = (OTPCacheNode)cache.get(login); OTPState st; OTPServer server; String pData; try { st = getFromCache(login, CACHE_ACTIVE_ST); if (st == null) { pData = ud.getPasswordData(); if (pData == null || pData.length() == 0) { throw new InvalidPasswordException("no password data"); } st = new OTPState(pData); } server = new OTPServer(st); if (! server.checkOTP(pass)) throw new InvalidPasswordException("bad password"); /* Update the password data so next time we need a new pass */ st = server.getState(); ud.setPasswordData(st.getInfoString()); } catch (OTPFormatException e) { throw new InvalidPasswordException("bad OTP format"); } catch (NoSuchAlgorithmException e) { throw new InvalidPasswordException("bad hash"); } /* catch (Exception e) { throw new InvalidPasswordException("WTF?!?!?"); } */ // Done with n.active_st removeFromCache(login, CACHE_ACTIVE_ST); } /** Change the OTP Stream */ public void changePassword(UserData ud, String newpass, String vrfy) throws InvalidPasswordException { String login = ud.getLogin(); OTPState st = null; OTPServer server = null; String pData = null;; st = getFromCache(login, CACHE_NEW_ST); if (st == null) throw new InvalidPasswordException( "Don't know what challenge the new password is for."); if (! newpass.equalsIgnoreCase(vrfy)) throw new InvalidPasswordException( "the password and verify don't match"); st.otp = newpass; try { pData = ud.getPasswordData(); if (pData != null && pData.length() > 0) { // Get the old OTP first, so that we can compare. server = new OTPServer(new OTPState(pData) ); if (! server.reinitOTP(st, true)) throw new InvalidPasswordException( "The new OTP stream is the same as the old one."); } else { // We need to verify the format of the OTP server = new OTPServer(st); } } catch (OTPFormatException e) { throw new InvalidPasswordException("bad format in OTP"); } catch (NoSuchAlgorithmException e) { throw new InvalidPasswordException("Bad hash name"); } // We do this, so that the Hex rep. is stored. ud.setPasswordData(server.getState().getInfoString()); // remove this from the cache. (kill both so that the active state // is not stale removeFromCache(login, CACHE_NEW_ST | CACHE_ACTIVE_ST); } /** Get the challenge for this authentication. This will get passed some * user data and should return the approriate challenge string for that * user. */ public String getChallenge(UserData ud) throws WebMailException { OTPServer server; OTPState st = null; String login = ud.getLogin(); String chal = null; String pData = null; st = getFromCache(login, CACHE_ACTIVE_ST); if (st == null) { pData = ud.getPasswordData(); if (pData == null || pData.length() == 0) { // No password data has been set. throw new WebMailException("No password data available"); } st = new OTPState(pData); } try { server = new OTPServer(st); chal = server.getChallenge(); } catch (OTPFormatException e) { e.printStackTrace(); // this should never happen. } catch (NoSuchAlgorithmException e) { e.printStackTrace(); // this either } // final sanity check if (chal == null) { throw new WebMailException("failed to get the next challenge"); } // I'm expecting that we will be using this again soon. putIntoCache(login, st, null); return chal; } /*----------------------- Private Functions -------------------------*/ private void removeFromCache(String key, int type) { OTPCacheNode node; node = (OTPCacheNode)cache.get(key); if (node == null) { node = new OTPCacheNode(); } if ( (type & CACHE_ACTIVE_ST) != 0) { node.active_st = null; } if ( (type & CACHE_NEW_ST) != 0) { node.new_st = null; } if (node.new_st == null && node.active_st == null) { cache.remove(key); } else { cache.put(key, node); } } private void putIntoCache(String key, OTPState ast, OTPState nst) { OTPCacheNode node; node = (OTPCacheNode)cache.get(key); if (node == null) { node = new OTPCacheNode(ast, nst); } else { if (ast != null) { node.active_st = ast; } if (nst != null) { node.new_st = nst; } } cache.put(key, node); } private void getFromCache(String key, int type, OTPState []sts) { OTPCacheNode node; int i = 0; node = (OTPCacheNode)cache.get(key); if (node != null) { if ( (type & CACHE_ACTIVE_ST) != 0) { sts[i++] = node.active_st; } if ( (type & CACHE_NEW_ST) != 0) { sts[i] = node.new_st; } } } private OTPState getFromCache(String key, int type) { OTPCacheNode node; OTPState rtn; node = (OTPCacheNode)cache.get(key); rtn = null; if (node != null) { if ( (type & CACHE_ACTIVE_ST) != 0) { rtn = node.active_st; } else if ( (type & CACHE_NEW_ST) != 0) { rtn = node.new_st; } } return rtn; } private Hashtable cache; private OTPAuthDisplayMngr disp_mngr; } // OTPAuthenticator |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.