/* * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.mobicents.servlet.sip.security.authentication; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.util.Random; import org.apache.catalina.Authenticator; import org.apache.catalina.Context; import org.apache.catalina.authenticator.Constants; import org.apache.catalina.util.StringManager; import org.apache.log4j.Logger; import org.mobicents.servlet.sip.core.session.MobicentsSipSession; import org.mobicents.servlet.sip.message.SipServletRequestImpl; import org.mobicents.servlet.sip.message.SipServletResponseImpl; import org.mobicents.servlet.sip.startup.loading.SipLoginConfig; /** * Base authenticator class. Based on the catalina authenticator. * * @author Craig R. McClanahan * @author Vladimir Ralev modified to suit SIP */ public abstract class AuthenticatorBase implements Authenticator{ private static transient Logger log = Logger.getLogger(AuthenticatorBase.class); // ----------------------------------------------------- Instance Variables /** * The default message digest algorithm to use if we cannot use * the requested one. */ protected static final String DEFAULT_ALGORITHM = "MD5"; /** * The message digest algorithm to be used when generating session * identifiers. This must be an algorithm supported by the * <code>java.security.MessageDigest</code> class on your platform. */ protected String algorithm = DEFAULT_ALGORITHM; /** * Should we cache authenticated Principals if the request is part of * an HTTP session? */ protected boolean cache = true; /** * The Context to which this Valve is attached. */ protected Context context = null; /** * Return the MessageDigest implementation to be used when * creating session identifiers. */ protected MessageDigest digest = null; /** * A String initialization parameter used to increase the entropy of * the initialization of our random number generator. */ protected String entropy = null; /** * Descriptive information about this implementation. */ protected static final String info = "org.apache.catalina.authenticator.AuthenticatorBase/1.0"; /** * A random number generator to use when generating session identifiers. */ protected Random random = null; /** * The Java class name of the random number generator class to be used * when generating session identifiers. */ protected String randomClass = "java.security.SecureRandom"; /** * The string manager for this package. */ protected static final StringManager sm = StringManager.getManager(Constants.Package); // ------------------------------------------------------------- Properties /** * Return the message digest algorithm for this Manager. */ public String getAlgorithm() { return (this.algorithm); } /** * Set the message digest algorithm for this Manager. * * @param algorithm The new message digest algorithm */ public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } /** * Return the cache authenticated Principals flag. */ public boolean getCache() { return (this.cache); } /** * Set the cache authenticated Principals flag. * * @param cache The new cache flag */ public void setCache(boolean cache) { this.cache = cache; } /** * Return the entropy increaser value, or compute a semi-useful value * if this String has not yet been set. */ public String getEntropy() { // Calculate a semi-useful value if this has not been set if (this.entropy == null) setEntropy(this.toString()); return (this.entropy); } /** * Set the entropy increaser value. * * @param entropy The new entropy increaser value */ public void setEntropy(String entropy) { this.entropy = entropy; } /** * Return descriptive information about this Valve implementation. */ public String getInfo() { return (info); } /** * Return the random number generator class name. */ public String getRandomClass() { return (this.randomClass); } /** * Set the random number generator class name. * * @param randomClass The new random number generator class name */ public void setRandomClass(String randomClass) { this.randomClass = randomClass; } // --------------------------------------------------------- Public Methods /** * Authenticate the user making this request, based on the specified * login configuration. Return <code>true</code> if any specified * constraint has been satisfied, or <code>false</code> if we have * created a response challenge already. * * @param request Request we are processing * @param response Response we are creating * @param config Login configuration describing how authentication * should be performed * * @exception IOException if an input/output error occurs */ protected abstract boolean authenticate(SipServletRequestImpl request, SipServletResponseImpl response, SipLoginConfig config) throws IOException; /** * Return the MessageDigest object to be used for calculating * session identifiers. If none has been created yet, initialize * one the first time this method is called. */ protected synchronized MessageDigest getDigest() { if (this.digest == null) { try { this.digest = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { try { this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); } catch (NoSuchAlgorithmException f) { this.digest = null; } } } return (this.digest); } /** * Return the random number generator instance we should use for * generating session identifiers. If there is no such generator * currently defined, construct and seed a new one. */ protected synchronized Random getRandom() { if (this.random == null) { try { Class clazz = Class.forName(randomClass); this.random = (Random) clazz.newInstance(); long seed = System.currentTimeMillis(); char entropy[] = getEntropy().toCharArray(); for (int i = 0; i < entropy.length; i++) { long update = ((byte) entropy[i]) << ((i % 8) * 8); seed ^= update; } this.random.setSeed(seed); } catch (Exception e) { this.random = new java.util.Random(); } } return (this.random); } /** * Register an authenticated Principal and authentication type in our * request, in the current session (if there is one), and with our * SingleSignOn valve, if there is one. Set the appropriate cookie * to be returned. * * @param request The servlet request we are processing * @param response The servlet response we are generating * @param principal The authenticated Principal to be registered * @param authType The authentication type to be registered * @param username Username used to authenticate (if any) * @param password Password used to authenticate (if any) */ protected void register(SipServletRequestImpl request, SipServletResponseImpl response, Principal principal, String authType, String username, String password) { if (log.isDebugEnabled()) { // Bugzilla 39255: http://issues.apache.org/bugzilla/show_bug.cgi?id=39255 String name = (principal == null) ? "none" : principal.getName(); log.debug("Authenticated '" + name + "' with type '" + authType + "'"); } request.setUserPrincipal(principal); MobicentsSipSession session = request.getSipSession(); if(session != null) { session.setUserPrincipal(principal); } } public Context getContext() { return context; } public void setContext(Context context) { this.context = context; } }