b2bua icon indicating copy to clipboard operation
b2bua copied to clipboard

Get Radius attributes for authentication request from SIP Header

Open twmobius opened this issue 4 years ago • 3 comments

Hi @sobomax,

I wanted to add the sip realm in the authentication radius request (without perform digest authentication), and I've been looking through RadiusAuthorization; there is an extra_attributes parameter in the do_auth method which is not used anywhere and got me thinking.

Similarly to pass_headers parameters it would be nice to have an option to define a sip header from which b2bua will get specific radius attributes and add them to the Authentication request (via the extra_attributes property)

So I've modified the b2bua a bit to support exactly that. The patch adds an -x option, from which the user can add a sip header for b2bua to read radius attributes.

So for example, opensips might do something like:

append_hf('X-Test-Header: h323-ivr-out=SomeProperty=1\r\n');
$du = 'b2bua.ip'

route(RELAY);

sippy would have to run with -x x-test-header parameter and in the authentication request the header contents is added to the radius request. Obviously it's up to the administrator/ matching dictionary to supply valid radius key/ value pairs for this to work.

I am providing the patch in this comment, I don't know if you would be willing to add it to the b2bua source code. If you are, I'd be happy to supply you with a PR

Index: sippy/b2bua_radius.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sippy/b2bua_radius.py	(revision f1c375b3454445b66b88c4b3cdc365306bb0ef18)
+++ sippy/b2bua_radius.py	(date 1603809097780)
@@ -119,11 +119,12 @@
     rtp_proxy_session = None
     huntstop_scodes = None
     pass_headers = None
+    extra_attributes = None
     auth_proc = None
     proxied = False
     challenge = None
 
-    def __init__(self, remote_ip, source, global_config, pass_headers):
+    def __init__(self, remote_ip, source, global_config, pass_headers, extra_attributes):
         self.id = CallController.id
         CallController.id += 1
         self.global_config = global_config
@@ -137,6 +138,7 @@
         self.remote_ip = remote_ip
         self.source = source
         self.pass_headers = pass_headers
+        self.extra_attributes = extra_attributes
 
     def recvEvent(self, event, ua):
         if ua == self.uaA:
@@ -191,11 +193,12 @@
                 elif auth == None or auth.username == None or len(auth.username) == 0:
                     self.username = self.remote_ip
                     self.auth_proc = self.global_config['_radius_client'].do_auth(self.remote_ip, self.cli, self.cld, self.cGUID, \
-                      self.cId, self.remote_ip, self.rDone)
+                      self.cId, self.remote_ip, self.rDone, extra_attributes=self.extra_attributes)
                 else:
                     self.username = auth.username
                     self.auth_proc = self.global_config['_radius_client'].do_auth(auth.username, self.cli, self.cld, self.cGUID, 
-                      self.cId, self.remote_ip, self.rDone, auth.realm, auth.nonce, auth.uri, auth.response)
+                      self.cId, self.remote_ip, self.rDone, auth.realm, auth.nonce, auth.uri, auth.response,
+                      extra_attributes=self.extra_attributes)
                 return
             if self.state not in (CCStateARComplete, CCStateConnected, CCStateDisconnecting) or self.uaO == None:
                 return
@@ -465,7 +468,27 @@
                 hfs = req.getHFs(header)
                 if len(hfs) > 0:
                     pass_headers.extend(hfs)
-            cc = CallController(remote_ip, source, self.global_config, pass_headers)
+
+            extra_attributes = None
+
+            if 'auth_extra_header' in self.global_config:
+                header = self.global_config['auth_extra_header']
+
+                hfs = req.getHFs(header)
+
+                if len(hfs) > 0:
+                    extra_attributes = []
+
+                    for header in hfs:
+                        kvPairs = header.body.body.split(';')
+
+                        for pair in kvPairs:
+                            [key, _, value] = pair.partition("=")
+
+                            if value != '':
+                                extra_attributes.append((key, value))
+
+            cc = CallController(remote_ip, source, self.global_config, pass_headers, extra_attributes)
             cc.challenge = challenge
             rval = cc.uaA.recvRequest(req, sip_t)
             self.ccmap.append(cc)
@@ -668,7 +691,7 @@
     global_config['_orig_argv'] = sys.argv[:]
     global_config['_orig_cwd'] = os.getcwd()
     try:
-        opts, args = getopt.getopt(sys.argv[1:], 'fDl:p:d:P:L:s:a:t:T:k:m:A:ur:F:R:h:c:M:HC:W:',
+        opts, args = getopt.getopt(sys.argv[1:], 'fDl:p:d:P:L:s:a:t:T:k:m:A:ur:F:R:h:c:M:HC:W:x:',
           global_config.get_longopts())
     except getopt.GetoptError:
         usage(global_config)
@@ -759,6 +782,9 @@
         if o == '-h':
             for a in a.split(','):
                 global_config.check_and_set('pass_header', a)
+            continue
+        if o == '-x':
+            global_config.check_and_set('auth_extra_header', a)
             continue
         if o == '-c':
             global_config.check_and_set('b2bua_socket', a)
Index: sippy/MyConfigParser.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sippy/MyConfigParser.py	(revision f1c375b3454445b66b88c4b3cdc365306bb0ef18)
+++ sippy/MyConfigParser.py	(date 1603808883519)
@@ -98,6 +98,8 @@
                              'and "SUBSCRIBE" messages. Address in the format ' \
                              '"host[:port]"'),
  'nat_traversal':     ('B', 'enable NAT traversal for signalling'), \
+ 'auth_extra_header': ('S', 'sip header containing radius parameters to pass ' \
+                            'to authentication request'), \
  'xmpp_b2bua_id':     ('I', 'ID passed to the XMPP socket server')}
 
 class MyConfigParser(RawConfigParser):

twmobius avatar Oct 27 '20 13:10 twmobius

I went a step further and added another parameter named parameter on the Routing h323-ivr-in response in the authentication that a user could supply a set of radius attribute-value pairs that b2bua later adds in the accounting messages.

So for example if the authorization response if of this sort:

h323-ivr-in = 'Routing:[email protected]:5060;credit-time=7200;expires=15;np_expires=5;bill-to=123@realm;parameters=h323-ivr-out=Test-Data:d=2,vr=1,ar=8'

both originate and answer, start, stop accounting will containing the header:

h323-ivr-out = 'Test-Data:d=2,vr=1,ar=8'

The idea is that when the billing engine performs authorisation for a call, it could provide information to the accounting events so that the engine could easily charge the call without having to recalculate everything from scratch.

Please let me know if you are interested in such feature additions on b2bua. :)

twmobius avatar Oct 29 '20 14:10 twmobius

Looks promising. I don't mind having this as a feature, would you please convert this to a PR?

Thanks!

-Max

On Thu., Oct. 29, 2020, 7:38 a.m. Paris, [email protected] wrote:

I went a step further and added another parameter named parameter on the Routing h323-ivr-in response in the authentication that a user could supply a set of radius attribute-value pairs that b2bua later adds in the accounting messages.

So for example if the authorization response if of this sort:

h323-ivr-in = 'Routing:[email protected]:5060 ;credit-time=7200;expires=15;np_expires=5;bill-to=123@realm ;parameters=h323-ivr-out=Test-Data:d=2,vr=1,ar=8'

both originate and answer, start, stop accounting will containing the header:

h323-ivr-out = 'Test-Data:d=2,vr=1,ar=8'

The idea is that when the billing engine performs authorisation for a call, it could provide information to the accounting events so that the engine could easily charge the call without having to recalculate everything from scratch.

Please let me know if you are interested in such feature additions on b2bua. :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/sippy/b2bua/issues/37#issuecomment-718796698, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABVMJTZKUTBGWG2UPC3PCLSNF47ZANCNFSM4TA2F7HQ .

sobomax avatar Oct 29 '20 21:10 sobomax

@sobomax there you go, I've split them up into two PRs one for each new feature.

twmobius avatar Oct 29 '20 23:10 twmobius