Woking on implementing support for SIP

Improved retrieval of password ffrom the security authority.
cusax-fix
Emil Ivov 20 years ago
parent b914fc1fbc
commit 70fd5529d3

@ -6,18 +6,15 @@
*/
package net.java.sip.communicator.impl.protocol.sip.security;
import java.text.*;
import java.util.*;
import javax.sip.*;
import javax.sip.message.*;
import javax.sip.address.*;
import javax.sip.header.*;
import javax.sip.message.*;
import java.util.*;
import java.text.*;
import javax.sip.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
/**
* The class handles authentication challenges, caches user credentials and
@ -33,17 +30,37 @@ public class SipSecurityManager
private static final Logger logger
= Logger.getLogger(SipSecurityManager.class);
/**
* The SecurityAuthority instance that we could use to obtain new passwords
* for the user.
*/
private SecurityAuthority securityAuthority = null;
/**
* An instance of the header factory that we have to use to create our
* authentication headers.
*/
private HeaderFactory headerFactory = null;
/**
* Credentials cached so far.
*/
CredentialsCache cachedCredentials = new CredentialsCache();
private CredentialsCache cachedCredentials = new CredentialsCache();
public SipSecurityManager()
{
/**
* The ID of the account that this security manager instance is serving.
*/
private AccountID accountID = null;
/**
* Default constructor for the security manager.
*
* @param accountID the id of the account that this security manager is
* going to serve.
*/
public SipSecurityManager(AccountID accountID)
{
this.accountID = accountID;
}
/**
@ -99,21 +116,33 @@ public ClientTransaction handleChallenge(
Request reoriginatedRequest = (Request) challengedRequest.clone();
//remove the branch id so that we could use the request in a new
//transaction
removeBranchID(reoriginatedRequest);
ListIterator authHeaders = null;
if (challenge == null || reoriginatedRequest == null)
{
throw new NullPointerException(
"A null argument was passed to handle challenge.");
}
if (challenge.getStatusCode() == Response.UNAUTHORIZED)
{
authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME);
else if (challenge.getStatusCode() ==
Response.PROXY_AUTHENTICATION_REQUIRED)
}
else if (challenge.getStatusCode()
== Response.PROXY_AUTHENTICATION_REQUIRED)
{
authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME);
}
if (authHeaders == null)
{
throw new NullPointerException(
"Could not find WWWAuthenticate or ProxyAuthenticate headers");
}
//Remove all authorization headers from the request (we'll re-add them
//from cache)
@ -137,30 +166,62 @@ else if (challenge.getStatusCode() ==
authHeader = (WWWAuthenticateHeader) authHeaders.next();
String realm = authHeader.getRealm();
//Check whether we have cached credentials for authHeader's realm
//make sure that if such credentials exist they get removed. The
//challenge means that there's something wrong with them.
CredentialsCacheEntry ccEntry =
(CredentialsCacheEntry) cachedCredentials.remove(realm);
//Try to guess user name and facilitate user
UserCredentials defaultCredentials = new UserCredentials();
FromHeader from =
(FromHeader) reoriginatedRequest.getHeader(FromHeader.NAME);
URI uri = from.getAddress().getURI();
if (uri.isSipURI())
{
String user = ( (SipURI) uri).getUser();
defaultCredentials.setUserName(
user == null
? null //PropertiesDepot.getProperty("net.java.sip.communicator.sip.USER_NAME")
: user);
}
//Check whether we have cached credentials for authHeader's realm.
//We remove them with the intention to re-add them at the end of the
//method. If we fail to get to the end then it's best for the cache
//entry to remain outside since it might have caused the problem
CredentialsCacheEntry ccEntry = cachedCredentials.remove(realm);
boolean ccEntryHasSeenTran = false;
if (ccEntry != null)
ccEntryHasSeenTran = ccEntry.processResponse(branchID);
ccEntryHasSeenTran = ccEntry.popBranchID(branchID);
String storedPassword = SipActivator.getProtocolProviderFactory()
.loadPassword(accountID);
if(ccEntry == null)
{
//we haven't yet authentified this realm since we were started.
if(storedPassword != null)
{
//use the stored password to authenticate
ccEntry = createCcEntryWithStoredPassword(storedPassword);
}
else
{
//obtain new credentials
logger.trace("We don't seem to have a good pass! Get one.");
ccEntry = createCcEntryWithNewCredentials(realm);
}
}
else
{
//we have already authentified against this realm since we were
//started. this authentication is either for a different request
//or the previous authentication used a wrong pass.
if (ccEntryHasSeenTran)
{
//this is the transaction that created the cc entry. if we
//need to authenticate the same transaction then the
//credentials we supplied the first time we wrong.
//remove password and ask user again.
SipActivator.getProtocolProviderFactory().storePassword(
accountID, null);
ccEntry = createCcEntryWithNewCredentials(realm);
}
else
{
//we have a cache entry and it has not seen this transaction
//lets use it again.
//(this "else" is here for readability only)
logger.trace( "We seem to have a pass in the cache. "
+"Let's try with it.");
}
}
//get a new pass
if (ccEntry == null // we don't have credentials for the specified
@ -170,46 +231,27 @@ else if (challenge.getStatusCode() ==
// just a request to reencode
{
logger.debug(
"We don't seem to have a good pass! Get one.");
if (ccEntry == null)
ccEntry = new CredentialsCacheEntry();
ccEntry.userCredentials =
getSecurityAuthority().obtainCredentials(
realm,
defaultCredentials);
//put the returned user name in the properties file
//so that it appears as a default one next time user is prompted for pass
// PropertiesDepot.setProperty("net.java.sip.communicator.sip.USER_NAME",
// ccEntry.userCredentials.getUserName()) ;
// PropertiesDepot.storeProperties();
}
//encode and send what we have
else if (ccEntry != null
&& (!ccEntryHasSeenTran || authHeader.isStale()))
{
logger.debug(
"We seem to have a pass in the cache. Let's try with it.");
}
//if user canceled or sth else went wrong
if (ccEntry.userCredentials == null)
{
throw new OperationFailedException(
"Unable to authenticate with realm " + realm
, OperationFailedException.GENERAL_ERROR);
}
AuthorizationHeader authorization =
this.getAuthorization(
reoriginatedRequest.getMethod(),
reoriginatedRequest.getRequestURI().toString(),
reoriginatedRequest.getContent() == null ? "" :
( reoriginatedRequest.getContent() == null )? "" :
reoriginatedRequest.getContent().toString(),
authHeader,
ccEntry.userCredentials);
ccEntry.processRequest(retryTran.getBranchId());
ccEntry.pushBranchID(retryTran.getBranchId());
cachedCredentials.cacheEntry(realm, ccEntry);
logger.debug("Created authorization header: " +
@ -312,9 +354,14 @@ private AuthorizationHeader getAuthorization(
authorization.setParameter("uri", uri);
authorization.setResponse(response);
if (authHeader.getAlgorithm() != null)
{
authorization.setAlgorithm(authHeader.getAlgorithm());
}
if (authHeader.getOpaque() != null)
{
authorization.setOpaque(authHeader.getOpaque());
}
authorization.setResponse(response);
}
@ -340,4 +387,85 @@ public void cacheCredentials(String realm, UserCredentials credentials)
this.cachedCredentials.cacheEntry(realm, ccEntry);
}
/**
* Removes all via headers from <tt>request</tt> and replaces them with a
* new one, equal to the one that was top most.
*
* @param request the Request whose branchID we'd like to remove.
*
* @throws ParseException in case the host port or transport in the original
* request were malformed
* @throws InvalidArgumentException if the port in the original via header
* was invalid.
*/
private void removeBranchID(Request request)
throws ParseException, InvalidArgumentException
{
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
request.removeHeader(ViaHeader.NAME);
ViaHeader newViaHeader = headerFactory.createViaHeader(
viaHeader.getHost()
, viaHeader.getPort()
, viaHeader.getTransport()
, null);
request.setHeader(newViaHeader);
}
/**
* Obtains user credentials from the security suthority for the speicified
* <tt>realm</tt> and creates a new CredentialsCacheEntry with them.
*
* @param realm the realm that we'd like to obtain a
* <tt>CredentialsCacheEntry</tt> for.
*
* @return a newly created <tt>CredentialsCacheEntry</tt> corresponding to
* the specified <tt>realm</tt>.
*/
private CredentialsCacheEntry createCcEntryWithNewCredentials(String realm)
{
CredentialsCacheEntry ccEntry = new CredentialsCacheEntry();
UserCredentials defaultCredentials = new UserCredentials();
defaultCredentials.setUserName(accountID.getUserID());
ccEntry.userCredentials =
getSecurityAuthority().obtainCredentials(
realm,
defaultCredentials);
//store the password if the user wants us to
if(ccEntry.userCredentials.isPasswordPersistent())
SipActivator.getProtocolProviderFactory().storePassword(
accountID
, ccEntry.userCredentials.getPasswordAsString());
return ccEntry;
}
/**
* Creaes a new credentials cache entry using <tt>password</tt>.
*
* @param password the password that we'd like to use in our the credentials
* associated with the new <tt>CredentialsCacheEntry</tt>.
*
* @return a newly created <tt>CredentialsCacheEntry</tt> using
* <tt>password</tt>.
*/
private CredentialsCacheEntry createCcEntryWithStoredPassword(
String password)
{
CredentialsCacheEntry ccEntry = new CredentialsCacheEntry();
ccEntry.userCredentials = new UserCredentials();
ccEntry.userCredentials.setUserName(accountID.getUserID());
ccEntry.userCredentials.setPassword(password.toCharArray());
return ccEntry;
}
}

Loading…
Cancel
Save