/*
* 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;
}
}