Skip to content

Commit

Permalink
Merge branch 'master' into restcomm-1995
Browse files Browse the repository at this point in the history
* master:
  Added extra log statements around the check of client Authorization header
  Updated External project version
  DigestAuthentication unit test
  Fixes for 8.4.0 release notes. This close RESTCOMM-2054
  Patch for race condition when SBC is enabled, where the Cancel from one of the forking branches will cause the initial call state to be marked as Canceled and thus the Bye wont be send at the end of the call. This refer to RESTCOMM-1932
  added release notes log,and link to main page
  • Loading branch information
Maria Farooq committed Apr 19, 2018
2 parents e34c18a + ec6a405 commit b2dd77b
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 1 deletion.
Expand Up @@ -144,4 +144,12 @@ public static String HA1(String username, String realm, String password){
ha1 = DigestAuthentication.H(username+":"+realm+":"+password, algorithm);
return ha1;
}


//USed for unit testing
public static String HA1(String username, String realm, String password, String algorithm){
String ha1 = "";
ha1 = DigestAuthentication.H(username+":"+realm+":"+password, algorithm);
return ha1;
}
}
@@ -0,0 +1,83 @@
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2018, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 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
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/

package org.restcomm.connect.commons;

import org.junit.Test;
import org.restcomm.connect.commons.dao.Sid;
import org.restcomm.connect.commons.util.DigestAuthentication;

import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertTrue;

public class DigestAuthenticationTest {

private String client = "alice0000000";
private String domain = "org0000000.restcomm.com";
private String password = "1234";
private String proxyAuthHeader = "Digest username=\"alice0000000\"," +
"realm=\"org0000000.restcomm.com\"," +
"cnonce=\"6b8b4567\"," +
"nc=00000001," +
"qop=auth,uri=\"sip:172.31.44.214:5080\"," +
"nonce=\"39656532346436332d633335612d346\"," +
"response=\"00e135e06e2474d1d0318fb66a2bc473\"," +
"algorithm=MD5\n";

@Test
public void testAuth(){
String hashedPass = DigestAuthentication.HA1(client, domain, password, "MD5");

assertTrue(permitted(proxyAuthHeader, "INVITE", hashedPass));

}

static boolean permitted(final String authorization, final String method, String clientPassword) {
final Map<String, String> map = authHeaderToMap(authorization);
String user = map.get("username");
final String algorithm = map.get("algorithm");
final String realm = map.get("realm");
final String uri = map.get("uri");
final String nonce = map.get("nonce");
final String nc = map.get("nc");
final String cnonce = map.get("cnonce");
final String qop = map.get("qop");
final String response = map.get("response");
final String password2 = clientPassword;
final String result = DigestAuthentication.response(algorithm, user, realm, "", password2, nonce, nc, cnonce,
method, uri, null, qop);
return result.equals(response);
}

private static Map<String, String> authHeaderToMap(final String header) {
final Map<String, String> map = new HashMap<String, String>();
final int endOfScheme = header.indexOf(" ");
map.put("scheme", header.substring(0, endOfScheme).trim());
final String[] tokens = header.substring(endOfScheme + 1).split(",");
for (final String token : tokens) {
final String[] values = token.trim().split("=",2); //Issue #935, split only for first occurrence of "="
map.put(values[0].toLowerCase(), values[1].replace("\"", ""));
}

return map;
}

}
Expand Up @@ -21,3 +21,6 @@ There is multiple ways to interact with Restcomm Connect to build applications
* The <<tutorials/index.adoc#tutorials,Restcomm Tutorials>> will help you in creating sample applications that cover common use cases in a variety of languages using the Restcomm API, RCML or Visual Designer. Download, test, and tweak for yourself.
* The <<configuration/index.adoc#Configuration,Configuration>> will help you in setting up Restcomm Connect on your own server or development environment to build powerful apps locally.
Find <<release-notes.adoc#Release Notes,Release Notes>> here
@@ -0,0 +1,54 @@
= Restcomm-Connect Release Notes

These notes group both Community and Telscale changes in a single document.

=== Tags

The folowing tags are used to categorize and state the scope of a change

* **security improvement** tags changes related to security
* **commercial** tags changes that are available only in the commercial RestcommOne product


//add release-notes with newer on top
== 8.4.0 version
=== New Features
// New features (whether major or minor) go here
* Clients passwords are now hashed in DB - **security improvement**
* Profiles allow arbitrary properties to be saved/retrieved.
* Added configurable SBC mode which if enabled will disable all NAT handling operations

=== Breaking Changes
// draws attention to functionality that is getting removed
* Accessing Olympus WebRTC from Console now requires to login again. This because of the new feature to hash passwords
* Removed default clients `alice` and `bob`

=== Bug Fixes
// any difference in functionality
* Dial Timeout does not cancel task when Callee is busy
* Configurable inbound/outbound SMPP encoding
* Race condition on sending BYE to incoming call for a dial fork scenario
* Fixed SDR event for SMS - **commercial**


=== Migration Notes
// Things to consider during migration from previous release
* Clients password are considered to be MD5 hashed in DB. Database migration
scripts are available in **commercial** version. Database migration script will ensure existing clients passwords are properly migrated.

=== External Dependencies Updates
// any dependencies
* Console updated to version **__8.4.0__**
** Integrated Feature Access Control (FAC) limitations
** Updated Console Look & Feel to match new Restcomm branding
** Implemented new Sign In page in Console
** Use Designer location in Console from configuration file
* Designer updated to version **__1.2.0-131__**
** Integrated Feature Access Control (FAC) limitations
** Improved Designer performance with better xstream usage
** Designer Look & Feel to match new Restcomm branding
* Olympus WebRTC Demo updated to version **__1.1.0-167__**
** Fixed an issue in WebRTC Demo jain-sip library, parsing some headers
** Improve WebRTC Demo UX by showing incoming call screen on top even if caller is not the selected contact
** Add additional configuration to WebRTC Demo for specifying client-specific parameters
** Improve WebRTC Xirsys integration by checking for actual success response and using domain property as namespace (now required)
Expand Up @@ -1244,7 +1244,7 @@ private void onCallStateChanged(Object message, ActorRef sender) throws Transiti
case RINGING:
break;
case CANCELED:
if (is(initializingBridge) || is(acquiringOutboundCallInfo) || is(bridging) || is(bridged)) {
if (is(creatingBridge) || is(initializingBridge) || is(acquiringOutboundCallInfo) || is(bridging) || is(bridged)) {
//This is a canceled branch from a previous forking call. We need to destroy the branch
// removeDialBranch(message, sender);
callManager.tell(new DestroyCall(sender), self());
Expand Down
Expand Up @@ -31,6 +31,7 @@
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipURI;

import org.apache.log4j.Logger;
import org.restcomm.connect.dao.ClientsDao;
import org.restcomm.connect.dao.DaoManager;
import org.restcomm.connect.dao.entities.Client;
Expand All @@ -47,6 +48,7 @@
*
*/
public class CallControlHelper {
private static Logger logger = Logger.getLogger(CallControlHelper.class);

static boolean permitted(final String authorization, final String method, DaoManager daoManager, final Sid organizationSid) {
final Map<String, String> map = authHeaderToMap(authorization);
Expand All @@ -66,8 +68,16 @@ static boolean permitted(final String authorization, final String method, DaoMan
final String password2 = client.getPassword();
final String result = DigestAuthentication.response(algorithm, user, realm, "", password2, nonce, nc, cnonce,
method, uri, null, qop);
if (logger.isDebugEnabled()) {
String msg = String.format("Provided response [%s], generated response [%s]", response, result);
logger.debug(msg);
}
return result.equals(response);
} else {
if (logger.isDebugEnabled()) {
String msg = String.format("Authorization check failed, [if(client==null) evaluates %s] or [if(client.getStatus()==Client.ENABLED) evaluates %s]", client!=null, Client.ENABLED == client.getStatus());
logger.debug(msg);
}
return false;
}
}
Expand All @@ -85,6 +95,10 @@ public static boolean checkAuthentication(SipServletRequest request, DaoManager
final String authorization = request.getHeader("Proxy-Authorization");
final String method = request.getMethod();
if (authorization == null || !CallControlHelper.permitted(authorization, method, storage, organizationSid)) {
if (logger.isDebugEnabled()) {
String msg = String.format("Either authorization header is null [if(authorization==null) evaluates %s], or CallControlHelper.permitted() method failed, will send \"407 Proxy Authentication required\"", authorization==null);
logger.debug(msg);
}
authenticate(request, storage.getOrganizationsDao().getOrganization(organizationSid).getDomainName());
return false;
} else {
Expand Down

0 comments on commit b2dd77b

Please sign in to comment.