//
//
// Copyright (C) 2004 SIPfoundry Inc.
// Licensed by SIPfoundry under the LGPL license.
//
// Copyright (C) 2004 Pingtel Corp.
// Licensed to SIPfoundry under a Contributor Agreement.
//
// $$
//////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES
#include <assert.h>
// APPLICATION INCLUDES
#include "os/OsFS.h"
#include "os/OsConfigDb.h"
#include "os/OsQueuedEvent.h"
#include "os/OsSysLog.h"
#include "os/OsTimer.h"
#include "os/OsEventMsg.h"
#include "net/SipUserAgent.h"
#include "net/NetMd5Codec.h"
#include "sipdb/ResultSet.h"
#include "sipdb/CredentialDB.h"
#include "sipdb/PermissionDB.h"
#include "sipdb/AuthexceptionDB.h"
#include "digitmaps/UrlMapping.h"
#include "SipAaa.h"
// DEFINES
//#define TEST_PRINT 1
// MACROS
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
extern UtlString gUriKey;
extern UtlString gCallidKey;
extern UtlString gContactKey;
extern UtlString gQvalueKey;
extern UtlString gCseqKey;
extern UtlString gExpiresKey;
/* //////////////////////////// PUBLIC //////////////////////////////////// */
/* ============================ CREATORS ================================== */
// Constructor
SipAaa::SipAaa(SipUserAgent& sipUserAgent,
const char* authenticationRealm,
UtlString& routeName) :
OsServerTask("SipAaa-%d", NULL, 2000)
{
mpSipUserAgent = &sipUserAgent;
mRealm = authenticationRealm ? authenticationRealm : "";
// Initialize the outbound authorization rules
mpAuthorizationRules = new UrlMapping();
// The name to appear in the route header for the authproxy
mRouteName = routeName;
char signBuf[100];
// Construct the secret to be used in the route recognition hash.
// The signature should be the same after a restart or any calls
// that are up will have problems with mid-dialog transactions
// :TODO: this needs a secret value inserted, but a stable one.
UtlString viaHost;
int viaPort;
mpSipUserAgent->getViaInfo(OsSocket::UDP, viaHost, viaPort);
sprintf(signBuf, "%d:", viaPort);
mSignatureSecret = signBuf;
mSignatureSecret.append(viaHost);
/*
* Config files which are specific to a component
* (e.g. mappingrules.xml is to sipregistrar) Use the
* following logic:
* 1) If directory ../etc exists:
* The path to the data file is as follows
* ../etc/<data-file-name>
*
* 2) Else the path is assumed to be:
* ./<data-file-name>
*/
OsPath workingDirectory ;
if ( OsFileSystem::exists( CONFIG_ETC_DIR ) )
{
workingDirectory = CONFIG_ETC_DIR;
OsPath path(workingDirectory);
path.getNativePath(workingDirectory);
} else
{
OsPath path;
OsFileSystem::getWorkingDirectory(path);
path.getNativePath(workingDirectory);
}
UtlString fileName = workingDirectory + OsPathBase::separator + AUTH_RULES_FILENAME;
mpAuthorizationRules->loadMappings(fileName);
// Register to get incoming requests
OsMsgQ* queue = getMessageQueue();
sipUserAgent.addMessageObserver(
*queue,
"", // All methods
TRUE, // Requests,
FALSE, // Responses,
TRUE, // Incoming,
FALSE, // OutGoing,
"", // eventName,
NULL, // SipSession* pSession,
NULL); // observerData
// The period of time in seconds that nonces are valid
mNonceExpiration = 60 * 5; // five minutes
// Set up a periodic timer for nonce garbage collection
OsQueuedEvent* queuedEvent = new OsQueuedEvent(*queue, 0);
OsTimer* timer = new OsTimer(*queuedEvent);
// Once a minute
OsTime lapseTime(60,0);
timer->periodicEvery(lapseTime, lapseTime);
}
// Copy constructor
SipAaa::SipAaa(const SipAaa& rSipAaa)
{}
// Destructor
SipAaa::~SipAaa()
{}
/* ============================ MANIPULATORS ============================== */
UtlBoolean
SipAaa::handleMessage( OsMsg& eventMessage )
{
int msgType = eventMessage.getMsgType();
int msgSubType = eventMessage.getMsgSubType();
// Timer event
if( msgType == OsMsg::OS_EVENT
&& msgSubType == OsEventMsg::NOTIFY
)
{
// Garbage collect nonces
OsTime time;
OsDateTime::getCurTimeSinceBoot(time);
long now = time.seconds();
// Remove nonces more than 5 minutes old
long oldTime = now - mNonceExpiration;
mNonceDb.removeOldNonces(oldTime);
}
// SIP message event
else if ( msgType == OsMsg::PHONE_APP )
{
SipMessage* sipRequest = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage();
int messageType = ((SipMessageEvent&)eventMessage).getMessageStatus();
if ( messageType == SipMessageEvent::TRANSPORT_ERROR )
{
OsSysLog::add(FAC_SIP, PRI_ERR,
"SipAaa::handleMessage received transport error message") ;
}
else if ( sipRequest )
{
if ( sipRequest->isResponse() )
{
OsSysLog::add(FAC_AUTH, PRI_ERR, "ERROR: SipAaa::handleMessage received response");
}
else
{
UtlString callId;
sipRequest->getCallIdField(&callId);
UtlString myRouteUri;
UtlString targetUri;
UtlBoolean isNextHop = FALSE;
UtlString nextHopUri;
UtlString firstRouteUri;
UtlBoolean routeExists = sipRequest->getRouteUri(0, &firstRouteUri);
// If there is a route header just send it on its way
if ( routeExists )
{
# ifdef TEST_PRINT
osPrintf("SipAaa::handleMessage found a route\n");
# endif
// Check the URI. If the URI has lr the
// previous proxy was a strict router
UtlString requestUri;
sipRequest->getRequestUri(&requestUri);
Url routeUrlParser(requestUri, TRUE);
UtlString dummyValue;
UtlBoolean previousHopStrictRoutes =
routeUrlParser.getUrlParameter( "lr", dummyValue, 0 );
UtlBoolean uriIsMe = mpSipUserAgent->isMyHostAlias(routeUrlParser);
Url firstRouteUriUrl(firstRouteUri);
UtlBoolean firstRouteIsMe = mpSipUserAgent->isMyHostAlias(firstRouteUriUrl);
// If the URI is not this server and the
// URI is not marked as a loose route and
// the first route is not this server then
// this server was not in the routes and we
// really do not know if the route set is
// set up as loose or strict routing. We
// have to assume that it is strict routing.
if( !previousHopStrictRoutes
&& !uriIsMe
&& !firstRouteIsMe
)
{
previousHopStrictRoutes = TRUE;
}
// If the URI does not have the loose route
// tag and the URI is pointed to this server
// we assume the previous hop strict routed
else if(!previousHopStrictRoutes && uriIsMe)
{
previousHopStrictRoutes = TRUE;
}
if ( previousHopStrictRoutes )
{
# ifdef TEST_PRINT
osPrintf("SipAaa::handleMessage previous hop strict routed\n");
# endif
// If this is NOT my host and port in the URI
if(! uriIsMe)
{
OsSysLog::add(FAC_SIP, PRI_WARNING,
"SipAaa::handleMessage Strict route: %s not to this server",
requestUri.data());
// Put the route back on as this URI is
// not this server.
sipRequest->addRouteUri(requestUri);
myRouteUri = "";
}
else
{
myRouteUri = requestUri;
}
// We have to pop the last route and put it in the URI
UtlString contactUri;
int lastRouteIndex;
sipRequest->getLastRouteUri(contactUri, lastRouteIndex);
# ifdef TEST_PRINT
osPrintf("SipAaa::handleMessage setting new URI: %s\n",
contactUri.data());
# endif
sipRequest->removeRouteUri(lastRouteIndex, &contactUri);
# ifdef TEST_PRINT
osPrintf("SipAaa::handleMessage route removed: %s\n",
contactUri.data());
# endif
// Put the last route in a the URI
Url newUri(contactUri);
newUri.getUri(contactUri);
sipRequest->changeRequestUri(contactUri);
# ifdef TEST_PRINT
UtlString bytes;
int len;
sipRequest->getBytes(&bytes, &len);
osPrintf("SipAaa: \nStrict\n%s\nNow Loose\n",
bytes.data());
// Where are we going?
// These are used for authorization
targetUri = contactUri;
isNextHop = sipRequest->getRouteUri(0, &nextHopUri);
if ( !isNextHop )
{
nextHopUri = "";
}
# endif
}
else
{
# ifdef TEST_PRINT
osPrintf("SipAaa::handleMessage previous hop loose routed\n");
# endif
// If this route is to me, pop it off
if(firstRouteIsMe)
{
// THis is a loose router pop my route off
UtlString dummyUri;
sipRequest->removeRouteUri(0, &dummyUri);
myRouteUri = firstRouteUri;
}
else
{
myRouteUri = "";
OsSysLog::add(FAC_SIP, PRI_WARNING, "SipAaa::handleMessage Loose route: %s not to this server",
firstRouteUri.data());
}
// Where are we going?
// These are used for authorization
targetUri = requestUri;
isNextHop = sipRequest->getRouteUri(0, &nextHopUri);
if ( !isNextHop )
nextHopUri = "";
}
} else
{
// There is no route check if it is mapped to something local
OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipAaa::handleMessage no route found") ;
UtlString uri;
sipRequest->getRequestUri(&uri);
// Where are we going?
// These are used for authorization
myRouteUri = "";
targetUri = uri;
isNextHop = FALSE;
nextHopUri = "";
}
// Get some info about the request
// (method, to, from & tags)
UtlString method;
sipRequest->getRequestMethod(&method);
Url fromUrl;
Url toUrl;
sipRequest->getFromUrl(fromUrl);
sipRequest->getToUrl(toUrl);
UtlString fromTag;
UtlString toTag;
fromUrl.getFieldParameter("tag", fromTag);
toUrl.getFieldParameter("tag", toTag);
// If there is a route to me and this is not
// the inital call setup (e.g. to tag is set)
UtlBoolean routeSignatureIsValid = FALSE;
UtlBoolean toMatches = FALSE;
UtlBoolean fromMatches = FALSE;
UtlString routePermission;
UtlString routeTag;
UtlString routeSignature;
if(!myRouteUri.isNull() && !toTag.isNull())
{
Url myRouteUrl(myRouteUri);
myRouteUrl.getUrlParameter("a", routePermission);
myRouteUrl.getUrlParameter("t", routeTag);
myRouteUrl.getUrlParameter("s", routeSignature);
// The authentication and authorization only applies
// to one direction.
UtlString validRouteSignature;
if(toTag.compareTo(routeTag) == 0)
{
toMatches = TRUE;
calcRouteSignature(routePermission,
callId,
toTag,
validRouteSignature);
}
else if(fromTag.compareTo(routeTag) == 0)
{
fromMatches = TRUE;
calcRouteSignature(routePermission,
callId,
fromTag,
validRouteSignature);
}
// If the calculated signature and the one in the route
// match, the route and permission are valid
if(validRouteSignature.compareTo(routeSignature) == 0)
{
routeSignatureIsValid = TRUE;
OsSysLog::add(FAC_SIP, PRI_DEBUG,
"SipAaa::handleMessage Authorized by route signature call-id: %s signature a: %s t: %s s: %s",
callId.data(), routePermission.data(),
routeTag.data(), routeSignature.data()
);
}
else
{
OsSysLog::add(FAC_SIP, PRI_WARNING,
"SipAaa::handleMessage Invalid route signature call-id: %s signature a: %s t: %s s: %s",
callId.data(), routePermission.data(),
routeTag.data(), routeSignature.data()
);
}
}
// Check if we need to authenticate and authorize the originator.
ResultSet permissions;
UtlBoolean isPstnNumber;
if ( mpAuthorizationRules // there are authrules configured
&& method.compareTo(SIP_ACK_METHOD) != 0 // We do not authenticate ACKs
)
{
// We have a valid route with a signature
if(routeSignatureIsValid)
{
// We can use the permission from the route field.
// Request from the caller that required authorization
if(fromMatches && !routePermission.isNull())
{
// Need to authenticate
UtlHashMap record;
UtlString* permissionKey = new UtlString("permission");
UtlString* permissionValue = new UtlString(routePermission);
record.insertKeyAndValue(permissionKey,permissionValue);
permissions.addValue(record);
}
// Request from the original callee
// or Request from the caller that requires
// no authentication
else // if(toMatches) or no permissions
{
// No authentication or authorization
// required
if (!fromMatches)
{
OsSysLog::add(
FAC_SIP, PRI_INFO,
"SipAaa::handleMessage upstream request call-id: %s, not authenticating",
callId.data());
}
else if(routePermission.isNull())
{
OsSysLog::add(
FAC_SIP, PRI_INFO,
"SipAaa::handleMessage signed route call-id: %s with no authentication required",
callId.data());
}
else
{
OsSysLog::add(
FAC_SIP, PRI_INFO,
"SipAaa::handleMessage request call-id %s to unrestricted entity with signed route",
callId.data());
}
}
}
else // route signature is not valid
{
Url targetUrl(targetUri);
mpAuthorizationRules->getPermissionRequired(
targetUrl, isPstnNumber, permissions);
// There was no authorization required for contact
// Try the next hop as well
if ( isNextHop && permissions.getSize()==0 )
{
Url nextHopUrl( nextHopUri );
mpAuthorizationRules->getPermissionRequired (
nextHopUrl, isPstnNumber, permissions );
}
}
}
UtlBoolean needsAuthentication;
// We always have to route now so that we can sign
// the route
UtlBoolean needsRecordRouting = TRUE;
if(permissions.getSize() > 0)
{
needsRecordRouting = TRUE;
UtlString rulePermission;
if(permissions.getSize() == 1)
{
UtlString permissionKey("permission");
UtlHashMap record;
permissions.getIndex(0, record);
rulePermission = *((UtlString*)record.findValue(&permissionKey));
}
// If exactly one permission is required and it is
// RecordRoute, there is no need to authenticate.
if(rulePermission.compareTo("RecordRoute", UtlString::ignoreCase) == 0)
{
needsAuthentication = FALSE;
}
else
{
// Forwarding calls to the PSTN gateway workaround
// if incoming calls (fromUrl) match a an entry in the
// AuthexceptionDB then we do not require authentication
UtlString requestUri;
sipRequest->getRequestUri( &requestUri );
Url requestUrl ( requestUri, TRUE );
UtlString userid;
requestUrl.getUserId(userid);
if ( AuthexceptionDB::getInstance()->isException( userid ) )
{
needsAuthentication = FALSE;
}
else
{
needsAuthentication = TRUE;
}
}
}
else
{
needsAuthentication = FALSE;
}
// Authenticate if we need to
SipMessage authResponse;
UtlString authUser;
UtlString matchedPermission;
if ( needsAuthentication
&& ( !isAuthenticated(*sipRequest, authUser, authResponse)
|| !isAuthorized( *sipRequest, permissions, authUser,
authResponse, matchedPermission )
)
)
{ // Either not authenticated or not authorized
mpSipUserAgent->setServerHeader(authResponse);
mpSipUserAgent->send(authResponse);
}
else
{
// Otherwise route it on Record route if authenticated
if ( needsRecordRouting )
{
Url routeUrl(mRouteName);
if(mRouteName.isNull())
{
UtlString uriString;
int port;
mpSipUserAgent->getViaInfo(OsSocket::UDP, uriString, port );
# ifdef TEST_PRINT
osPrintf("SipAaa:handleMessage Record-Route address: %s port: %d\n",
uriString.data(), port);
# endif
routeUrl.setHostAddress(uriString.data());
routeUrl.setHostPort(port);
}
# ifdef TEST_PRINT
else
{
osPrintf("SipAaa:handleMessage Record-Route mRouteName: %s\n",
mRouteName.data());
}
# endif
routeUrl.setUrlParameter("lr", "");
UtlString signature;
// Preserve the signature if it is valid
if(routeSignatureIsValid)
{
routeUrl.setUrlParameter("a", routePermission);
routeUrl.setUrlParameter("t", routeTag);
routeUrl.setUrlParameter("s", routeSignature);
}
// We only add the signature on the initial dialog request
else if(toTag.isNull() && !matchedPermission.isNull())
{
calcRouteSignature(matchedPermission,
callId,
fromTag,
signature);
routeUrl.setUrlParameter("a", matchedPermission);
routeUrl.setUrlParameter("t", fromTag);
routeUrl.setUrlParameter("s", signature);
}
// Check to see if we have already added a record-route
// This is a minor optimization. It avoids the spiral
// on the mid-dialog transactions and keeps the message
// a little smaller.
UtlString previousRRoute;
UtlBoolean newRRouteIsUnique = TRUE;
if(sipRequest->getRecordRouteUri(0, &previousRRoute))
{
// If the host, port and user ID are the same the
// record-route to be added and the top most record-route
// already in the request.
Url prevRRouteUrl(previousRRoute);
if(prevRRouteUrl.isUserHostPortEqual(routeUrl))
{
UtlString prevPermission;
UtlString prevFromTag;
UtlString prevSignature;
// If the permission, from tag and signature
// of the existing record-route matches the one
// to be added, mark it as not unique so that
// we do not add it again
if(prevRRouteUrl.getUrlParameter("a", prevPermission) &&
prevPermission.compareTo(matchedPermission) == 0 &&
prevRRouteUrl.getUrlParameter("t", prevFromTag) &&
prevFromTag.compareTo(fromTag) == 0 &&
prevRRouteUrl.getUrlParameter("s", prevSignature) &&
prevSignature.compareTo(signature) == 0)
{
newRRouteIsUnique = FALSE;
}
}
}
if(newRRouteIsUnique)
{
//routeUrl.setAngleBrackets();
UtlString recordRoute = routeUrl.toString();
sipRequest->addRecordRouteUri(recordRoute);
}
}
// Decrement max forwards
int maxForwards;
if ( sipRequest->getMaxForwards(maxForwards) )
{
maxForwards--;
} else
{
maxForwards = mpSipUserAgent->getMaxForwards();
}
sipRequest->setMaxForwards(maxForwards);
sipRequest->resetTransport();
mpSipUserAgent->send(*sipRequest);
}
}
}
}
return(TRUE);
}
// Assignment operator
SipAaa&
SipAaa::operator=(const SipAaa& rhs)
{
if ( this == &rhs ) // handle the assignment to self case
return *this;
return *this;
}
/* ============================ ACCESSORS ================================= */
/* ============================ INQUIRY =================================== */
/* //////////////////////////// PROTECTED ///////////////////////////////// */
/* //////////////////////////// PRIVATE /////////////////////////////////// */
UtlBoolean SipAaa::isAuthenticated(
const SipMessage& sipRequest,
UtlString& authUser,
SipMessage& authResponse)
{
UtlBoolean authenticated = FALSE;
UtlString requestUser;
UtlString requestRealm;
UtlString requestNonce;
UtlString requestUri;
int requestAuthIndex;
UtlString callId;
Url fromUrl;
UtlString fromTag;
OsTime time;
OsDateTime::getCurTimeSinceBoot(time);
long nonceExpires = mNonceExpiration;
authUser.remove(0);
sipRequest.getCallIdField(&callId);
sipRequest.getFromUrl(fromUrl);
fromUrl.getFieldParameter("tag", fromTag);
// loop through all credentials in the request
for ( ( authenticated = FALSE, requestAuthIndex = 0 );
( ! authenticated
&& sipRequest.getDigestAuthorizationData(&requestUser,
&requestRealm,
&requestNonce,
NULL,
NULL,
&requestUri,
HttpMessage::PROXY,
requestAuthIndex)
);
requestAuthIndex++
)
{
if ( mRealm.compareTo(requestRealm) == 0 ) // case sensitive
{
OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SipAaa:isAuthenticated: checking user '%s'",
requestUser.data());
// Ignore this credential if it is not a current valid nonce
if (mNonceDb.isNonceValid(requestNonce, callId, fromTag,
requestUri, mRealm, nonceExpires))
{
Url userUrl;
UtlString authTypeDB;
UtlString passTokenDB;
// then get the credentials for this user and realm
if(CredentialDB::getInstance()->getCredential(requestUser,
mRealm,
userUrl,
passTokenDB,
authTypeDB)
)
{
# ifdef TEST_PRINT
// THIS SHOULD NOTE BE LOGGED IN PRODUCTION
// For security reasons we do not want to put passtokens
// into the log.
OsSysLog::add(FAC_AUTH, PRI_DEBUG,
"SipAaa::isAuthenticated found credential "
"user: \"%s\" passToken: \"%s\"",
requestUser.data(), passTokenDB.data());
# endif
authenticated = sipRequest.verifyMd5Authorization(requestUser.data(),
passTokenDB.data(),
requestNonce,
requestRealm.data(),
requestUri,
HttpMessage::PROXY );
if ( authenticated )
{
userUrl.toString(authUser);
OsSysLog::add(FAC_AUTH, PRI_DEBUG,
"SipAaa::isAuthenticated(): authenticated as '%s'",
authUser.data());
}
else
{
OsSysLog::add(FAC_AUTH, PRI_DEBUG,
"SipAaa::isAuthenticated() authentication failed as '%s'",
requestUser.data());
}
}
// Did not find credentials in DB
else
{
OsSysLog::add(FAC_AUTH, PRI_INFO,
"SipAaa::isAuthenticated() No credentials found for user: '%s'",
requestUser.data());
}
}
else // Is not a valid nonce
{
OsSysLog::add(FAC_AUTH, PRI_INFO,
"SipAaa::isAuthenticated() "
"Invalid NONCE: %s found "
"call-id: %s from tag: %s uri: %s realm: %s expiration: %ld",
requestNonce.data(), callId.data(), fromTag.data(),
requestUri.data(), mRealm.data(), nonceExpires);
}
}
else
{
// wrong realm - meant for some other proxy on the path, so ignore it
}
} // looping through credentials
if ( !authenticated )
{
OsSysLog::add(FAC_AUTH, PRI_INFO,
"SipAaa::isAuthenticated() Request not authenticated for user: '%s'",
requestUser.data());
UtlString newNonce;
UtlString challangeRequestUri;
sipRequest.getRequestUri(&challangeRequestUri);
mNonceDb.createNewNonce(callId,
fromTag,
challangeRequestUri,
mRealm,
newNonce);
authResponse.setRequestUnauthorized(&sipRequest,
HTTP_DIGEST_AUTHENTICATION,
mRealm,
newNonce, // nonce
NULL, // opaque - not used
HttpMessage::PROXY);
}
return(authenticated);
}
UtlBoolean
SipAaa::isAuthorized(
const ResultSet& requiredPermissions,
const ResultSet& grantedPermissions,
UtlString& matchedPermission,
UtlString& unmatchedPermissions)
{
UtlBoolean authorized = FALSE;
UtlString identityKey("identity");
UtlString permissionKey("permission");
int numGrantedPermissions = grantedPermissions.getSize();
for (int i = 0; i < numGrantedPermissions; i++)
{
UtlHashMap grantedRecord;
grantedPermissions.getIndex(i, grantedRecord);
UtlString rowUri = *((UtlString*)grantedRecord.findValue(&identityKey));
UtlString grantedRowPermission = *((UtlString*)grantedRecord.findValue(&permissionKey));
OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SipAaa::isAuthorized found uri: %s permission: %s",
rowUri.data(), grantedRowPermission.data());
// Search through the input permissions set for a match
int numRequiredPermissions = requiredPermissions.getSize();
if (numRequiredPermissions > 0)
{
UtlString permDB;
for (int j = 0; j < numRequiredPermissions; j++)
{
UtlHashMap requiredRecord;
requiredPermissions.getIndex(j, requiredRecord);
permDB = *((UtlString*)requiredRecord.findValue(&permissionKey));
if (permDB.compareTo(grantedRowPermission, UtlString::ignoreCase) == 0 ||
permDB.compareTo("ValidUser", UtlString::ignoreCase) == 0 ||
permDB.compareTo("RecordRoute", UtlString::ignoreCase) == 0)
{
matchedPermission.append(permDB);
authorized = TRUE;
break;
} else
{
// only the first time we need to fill in the string
// to get the names of permissions to send back when there is an error
if (i == 0)
{
if (!unmatchedPermissions.isNull())
{
unmatchedPermissions.append("+");
}
unmatchedPermissions.append(permDB);
}
}
permDB.remove(0);
} // end 2nd for loop require permissions
}
} //end 1st for loop over granted permission
// If authorization failed, then fill in unmatchedPermissions with all required
// permissions, since none of them matched
if (!authorized)
{
UtlHashMap requiredPermRecord;
int numRequiredPermissions = requiredPermissions.getSize();
for (int i = 0; i < numRequiredPermissions; i++)
{
requiredPermissions.getIndex(i, requiredPermRecord);
UtlString* requirePermPtr =
((UtlString*)requiredPermRecord.findValue(&permissionKey));
if (requirePermPtr)
{
if (!unmatchedPermissions.isNull())
{
unmatchedPermissions.append("+");
}
unmatchedPermissions.append(*requirePermPtr);
}
}
}
return authorized;
}
UtlBoolean
SipAaa::isAuthorized (
const SipMessage& sipRequest,
const ResultSet& requiredPermissions,
const char* authUser,
SipMessage& authResponse,
UtlString& matchedPermission)
{
UtlString userUrlString(authUser ? authUser : "");
if ( userUrlString.index("@") < 0 )
{
userUrlString.append("@");
userUrlString.append(mRealm);
}
Url userUrl(userUrlString);
// get all permissions associated with this user
ResultSet grantedPermissions;
PermissionDB::getInstance()->getPermissions(userUrl, grantedPermissions);
UtlString unmatchedPermissions;
UtlBoolean authorized =
isAuthorized(requiredPermissions, grantedPermissions, matchedPermission, unmatchedPermissions);
OsSysLog::add(FAC_AUTH, PRI_DEBUG, "SipAaa::isAuthorized user: %s %s for %s",
authUser && *authUser ? authUser : "none",
authorized ? "authorized" : "not authorized",
matchedPermission.data());
if (!authorized)
{
UtlString errorText("Not authorized for ");
errorText += unmatchedPermissions;
authResponse.setResponseData(&sipRequest,
SIP_FORBIDDEN_CODE,
errorText.data());
}
return authorized;
}
void SipAaa::calcRouteSignature(UtlString& matchedPermission,
UtlString& callId,
UtlString& fromTag,
UtlString& signature)
{
UtlString signatureData(mSignatureSecret);
signatureData.append(":");
signatureData.append(matchedPermission);
signatureData.append(":");
signatureData.append(callId);
signatureData.append(":");
signatureData.append(fromTag);
NetMd5Codec::encode(signatureData, signature);
}
/* ============================ FUNCTIONS ================================= */
syntax highlighted by Code2HTML, v. 0.9.1