Browse code

uac_auth: added UAS authentication of requests (internal API)

Stefan Sayer authored on 01/08/2013 15:54:16
Showing 7 changed files
... ...
@@ -47,6 +47,7 @@ EXPORT_SESSION_EVENT_HANDLER_FACTORY(UACAuthFactory, MOD_NAME);
47 47
 EXPORT_PLUGIN_CLASS_FACTORY(UACAuthFactory, MOD_NAME);
48 48
 
49 49
 UACAuthFactory* UACAuthFactory::_instance=0;
50
+string UACAuth::server_nonce_secret = "CKASLDĀ§$>NLKJSLDKFJ"; // replaced on load
50 51
 
51 52
 UACAuthFactory* UACAuthFactory::instance()
52 53
 {
... ...
@@ -57,7 +58,7 @@ UACAuthFactory* UACAuthFactory::instance()
57 58
 
58 59
 void UACAuthFactory::invoke(const string& method, const AmArg& args, AmArg& ret)
59 60
 {
60
-  if(method == "getHandler"){
61
+  if (method == "getHandler") {
61 62
     CredentialHolder* c = dynamic_cast<CredentialHolder*>(args.get(0).asObject());
62 63
     DialogControl* cc = dynamic_cast<DialogControl*>(args.get(1).asObject());
63 64
 
... ...
@@ -69,14 +70,43 @@ void UACAuthFactory::invoke(const string& method, const AmArg& args, AmArg& ret)
69 70
       ERROR("wrong types in call to getHandler.  (c=%ld, cc= %ld)\n", 
70 71
 	    (unsigned long)c, (unsigned long)cc);
71 72
     }
72
-  }
73
-  else
73
+  } else if (method == "checkAuth") {
74
+
75
+    // params: Request realm user pwd
76
+    if (args.size() < 4) {
77
+      ERROR("missing arguments to uac_auth checkAuth function, expected Request realm user pwd\n");
78
+      throw AmArg::TypeMismatchException();
79
+    }
80
+
81
+    AmSipRequest* req = dynamic_cast<AmSipRequest*>(args.get(0).asObject());
82
+    if (NULL == req)
83
+      throw AmArg::TypeMismatchException();
84
+    UACAuth::checkAuthentication(req, args.get(1).asCStr(),
85
+				 args.get(2).asCStr(),
86
+				 args.get(3).asCStr(), ret);
87
+  } else 
74 88
     throw AmDynInvoke::NotImplemented(method);
75 89
 }
76 90
 
77 91
 
78 92
 int UACAuthFactory::onLoad()
79 93
 {
94
+  string secret;
95
+  AmConfigReader conf;
96
+  string cfg_file_path = AmConfig::ModConfigPath + "uac_auth.conf";
97
+  if(conf.loadFile(cfg_file_path)){
98
+    WARN("Could not open '%s', assuming that default values are fine\n",
99
+	 cfg_file_path.c_str());
100
+    secret = AmSession::getNewId(); // ?? TODO: is this cryptoproof?
101
+  } else {
102
+    secret = conf.getParameter("server_secret");
103
+    if (secret.size()<5) {
104
+      ERROR("server_secret in '%s' too short!\n", cfg_file_path.c_str());
105
+      return -1;
106
+    }
107
+  }
108
+
109
+  UACAuth::setServerSecret(secret);
80 110
   return 0;
81 111
 }
82 112
 
... ...
@@ -263,21 +293,32 @@ void w_MD5Update(MD5_CTX *ctx, const string& s) {
263 293
   MD5Update(ctx, a, s.length());
264 294
 }
265 295
 
266
-
296
+// supr gly
267 297
 string UACAuth::find_attribute(const string& name, const string& header) {
268
-  string res;
269 298
   size_t pos1 = header.find(name);
270
-  if (pos1!=string::npos) {
271
-    pos1+=name.length();
272
-    pos1 = header.find_first_not_of(" =\"", pos1);
273
-    if (pos1 != string::npos) {
274
-      size_t pos2 = header.find_first_of(",\"", pos1);
275
-      if (pos2 != string::npos) {
276
-	res = header.substr(pos1, pos2-pos1);
277
-      }
299
+
300
+  while (true) {
301
+    if (pos1 == string::npos)
302
+      return "";
303
+    
304
+    if (!pos1 || header[pos1-1] == ',' || header[pos1-1] == ' ')
305
+      break;
306
+
307
+    pos1 = header.find(name, pos1+1);
308
+  }
309
+
310
+  pos1+=name.length();
311
+  pos1 = header.find_first_not_of(" =\"", pos1);
312
+  if (pos1 != string::npos) {
313
+    size_t pos2 = header.find_first_of(",\"", pos1);
314
+    if (pos2 != string::npos) {
315
+      return header.substr(pos1, pos2-pos1);
316
+    } else {
317
+      return header.substr(pos1); // end of hdr
278 318
     }
279 319
   }
280
-  return res;
320
+
321
+  return "";
281 322
 }
282 323
 
283 324
 bool UACAuth::parse_header(const string& auth_hdr, UACAuthDigestChallenge& challenge) {
... ...
@@ -376,9 +417,9 @@ bool UACAuth::do_auth(const UACAuthDigestChallenge& challenge,
376 417
   }
377 418
 
378 419
   /* do authentication */
379
-  uac_calc_HA1( challenge, cnonce, ha1);
420
+  uac_calc_HA1( challenge, credential, cnonce, ha1);
380 421
   uac_calc_HA2( method, uri, challenge, qop_auth_int ? hentity : NULL, ha2);
381
-  uac_calc_response( ha1, ha2, challenge, cnonce, qop_value, response);
422
+  uac_calc_response( ha1, ha2, challenge, cnonce, qop_value, nonce_count, response);
382 423
   DBG("calculated response = %s\n", response);
383 424
 
384 425
   // compile auth response
... ...
@@ -409,19 +450,23 @@ bool UACAuth::do_auth(const UACAuthDigestChallenge& challenge,
409 450
  * calculate H(A1)
410 451
  */
411 452
 void UACAuth::uac_calc_HA1(const UACAuthDigestChallenge& challenge,
453
+			   const UACAuthCred* _credential,
412 454
 			   string cnonce,
413 455
 			   HASHHEX sess_key)
414 456
 {
457
+  if (NULL == _credential)
458
+    return;
459
+
415 460
   MD5_CTX Md5Ctx;
416 461
   HASH HA1;
417 462
 
418 463
   MD5Init(&Md5Ctx);
419
-  w_MD5Update(&Md5Ctx, credential->user);
464
+  w_MD5Update(&Md5Ctx, _credential->user);
420 465
   w_MD5Update(&Md5Ctx, ":");
421 466
   // use realm from challenge 
422 467
   w_MD5Update(&Md5Ctx, challenge.realm); 
423 468
   w_MD5Update(&Md5Ctx, ":");
424
-  w_MD5Update(&Md5Ctx, credential->pwd);
469
+  w_MD5Update(&Md5Ctx, _credential->pwd);
425 470
   MD5Final(HA1, &Md5Ctx);
426 471
 
427 472
   // MD5sess ...not supported
... ...
@@ -486,7 +531,7 @@ void UACAuth::uac_calc_hentity( const string& body, HASHHEX hentity )
486 531
  */
487 532
 void UACAuth::uac_calc_response(HASHHEX ha1, HASHHEX ha2,
488 533
 				const UACAuthDigestChallenge& challenge, const string& cnonce,
489
-				const string& qop_value, HASHHEX response)
534
+				const string& qop_value, unsigned int nonce_count, HASHHEX response)
490 535
 {
491 536
   unsigned char hc[1]; hc[0]=':';
492 537
   MD5_CTX Md5Ctx;
... ...
@@ -498,6 +543,7 @@ void UACAuth::uac_calc_response(HASHHEX ha1, HASHHEX ha2,
498 543
   w_MD5Update(&Md5Ctx, challenge.nonce);
499 544
   MD5Update(&Md5Ctx, hc, 1);
500 545
 
546
+
501 547
   if (!qop_value.empty()) {
502 548
       
503 549
     w_MD5Update(&Md5Ctx, int2hex(nonce_count,true));
... ...
@@ -512,3 +558,176 @@ void UACAuth::uac_calc_response(HASHHEX ha1, HASHHEX ha2,
512 558
   MD5Final(RespHash, &Md5Ctx);
513 559
   cvt_hex(RespHash, response);
514 560
 }
561
+
562
+/** calculate nonce: time-stamp H(time-stamp private-key) */
563
+string UACAuth::calcNonce() {
564
+  string result;
565
+  HASHHEX hash;
566
+  MD5_CTX Md5Ctx;
567
+  HASH RespHash;
568
+
569
+  time_t now = time(NULL);
570
+  result = int2hex(now);
571
+  
572
+  MD5Init(&Md5Ctx);
573
+  w_MD5Update(&Md5Ctx, result);
574
+  w_MD5Update(&Md5Ctx, server_nonce_secret);
575
+  MD5Final(RespHash, &Md5Ctx);
576
+  cvt_hex(RespHash, hash);
577
+
578
+  return result+string((const char*)hash);
579
+}
580
+
581
+/** check nonce integrity. @return true if correct */
582
+bool UACAuth::checkNonce(const string& nonce) {
583
+  HASHHEX hash;
584
+  MD5_CTX Md5Ctx;
585
+  HASH RespHash;
586
+
587
+#define INT_HEX_LEN int(2*sizeof(int))
588
+
589
+  if (nonce.size() != INT_HEX_LEN+HASHHEXLEN) {
590
+    DBG("wrong nonce length (expected %u, got %zd)\n", INT_HEX_LEN+HASHHEXLEN, nonce.size());
591
+    return false;
592
+  }
593
+
594
+  MD5Init(&Md5Ctx);
595
+  w_MD5Update(&Md5Ctx, nonce.substr(0,INT_HEX_LEN));
596
+  w_MD5Update(&Md5Ctx, server_nonce_secret);
597
+  MD5Final(RespHash, &Md5Ctx);
598
+  cvt_hex(RespHash, hash);
599
+
600
+  return !strncmp((const char*)hash, &nonce[INT_HEX_LEN], HASHHEXLEN);
601
+}
602
+
603
+void UACAuth::setServerSecret(const string& secret) {
604
+  server_nonce_secret = secret;
605
+  DBG("Server Nonce secret set\n");
606
+}
607
+
608
+void UACAuth::checkAuthentication(const AmSipRequest* req, const string& realm, const string& user,
609
+				  const string& pwd, AmArg& ret) {
610
+  if (req->method == SIP_METH_ACK || req->method == SIP_METH_CANCEL) {
611
+    DBG("letting pass %s request without authentication\n", req->method.c_str());
612
+    ret.push(200);
613
+    ret.push("OK");
614
+    ret.push("");
615
+    return;
616
+  }
617
+
618
+  string auth_hdr = getHeader(req->hdrs, "Authorization");
619
+  bool authenticated = false;
620
+
621
+  if (auth_hdr.size()) {
622
+    UACAuthDigestChallenge r_challenge;
623
+
624
+    r_challenge.realm = find_attribute("realm", auth_hdr);
625
+    r_challenge.nonce = find_attribute("nonce", auth_hdr);
626
+    r_challenge.qop = find_attribute("qop", auth_hdr);
627
+    string r_response = find_attribute("response", auth_hdr);
628
+    string r_username = find_attribute("username", auth_hdr);
629
+    string r_uri = find_attribute("uri", auth_hdr);
630
+    string r_cnonce = find_attribute("cnonce", auth_hdr);
631
+
632
+    DBG("got realm '%s' nonce '%s', qop '%s', response '%s', username '%s' uri '%s' cnonce '%s'\n",
633
+	r_challenge.realm.c_str(), r_challenge.nonce.c_str(), r_challenge.qop.c_str(),
634
+	r_response.c_str(), r_username.c_str(), r_uri.c_str(), r_cnonce.c_str() );
635
+
636
+    if (r_response.size() != HASHHEXLEN) {
637
+      DBG("Auth: response length mismatch (wanted %u hex chars): '%s'\n", HASHHEXLEN, r_response.c_str());
638
+      goto auth_end;
639
+    }
640
+
641
+    if (realm != r_challenge.realm) {
642
+      DBG("Auth: realm mismatch: required '%s' vs '%s'\n", realm.c_str(), r_challenge.realm.c_str());
643
+      goto auth_end;
644
+    }
645
+
646
+    if (user != r_username) {
647
+      DBG("Auth: user mismatch: '%s' vs '%s'\n", user.c_str(), r_username.c_str());
648
+      goto auth_end;
649
+    }
650
+
651
+    if (!checkNonce(r_challenge.nonce)) {
652
+      DBG("Auth: incorrect nonce '%s'\n", r_challenge.nonce.c_str());
653
+      goto auth_end;
654
+    }
655
+
656
+    // we don't check the URI
657
+    // if (r_uri != req->r_uri) {
658
+    //   DBG("Auth: incorrect URI in request: '%s'\n", r_challenge.nonce.c_str());
659
+    //   goto auth_end;
660
+    // }
661
+
662
+    UACAuthCred credential;
663
+    credential.user = user;
664
+    credential.pwd = pwd;
665
+
666
+    unsigned int client_nonce_count = 1;
667
+
668
+    HASHHEX ha1;
669
+    HASHHEX ha2;
670
+    HASHHEX hentity;
671
+    HASHHEX response;
672
+    bool    qop_auth=false;
673
+    bool    qop_auth_int=false;
674
+    string  qop_value;
675
+
676
+    if(!r_challenge.qop.empty()){
677
+
678
+      if (r_challenge.qop == "auth")
679
+	qop_auth = true;
680
+      else if (r_challenge.qop == "auth-int")
681
+	qop_auth_int = true;
682
+
683
+      if(qop_auth || qop_auth_int) {
684
+
685
+	// get nonce count from request
686
+	string nonce_count_str = find_attribute("nc", auth_hdr);
687
+	if (str2i(nonce_count_str, client_nonce_count)) {
688
+	  DBG("Error parsing nonce_count '%s'\n", nonce_count_str.c_str());
689
+	  goto auth_end;
690
+	}
691
+
692
+	DBG("got client_nonce_count %u\n", client_nonce_count);
693
+
694
+	// auth-int? calculate hentity
695
+	if(qop_auth_int){
696
+	  string body_str;
697
+	  if(!req->body.empty()) req->body.print(body_str);
698
+	  uac_calc_hentity(body_str, hentity);
699
+	  qop_value = "auth-int";
700
+	} else {
701
+	  qop_value = "auth";
702
+	}
703
+
704
+      }
705
+    }
706
+
707
+    uac_calc_HA1(r_challenge, &credential, r_cnonce, ha1);
708
+    uac_calc_HA2(req->method, r_uri, r_challenge, qop_auth_int ? hentity : NULL, ha2);
709
+    uac_calc_response( ha1, ha2, r_challenge, r_cnonce, qop_value, client_nonce_count, response);
710
+    DBG("calculated our response vs request: '%s' vs '%s'", response, r_response.c_str());
711
+
712
+    if (!strncmp((const char*)response, r_response.c_str(), HASHHEXLEN)) {
713
+      DBG("Auth: authentication successfull\n");
714
+      authenticated = true;
715
+    } else {
716
+      DBG("Auth: authentication NOT successfull\n");
717
+    }
718
+  }
719
+
720
+ auth_end: 
721
+  if (authenticated) {
722
+    ret.push(200);
723
+    ret.push("OK");
724
+    ret.push("");
725
+  } else {
726
+    ret.push(401);
727
+    ret.push("Unauthorized");
728
+    ret.push(SIP_HDR_COLSP(SIP_HDR_WWW_AUTHENTICATE) "Digest "
729
+	     "realm=\""+realm+"\", "
730
+	     "qop=\"auth,auth-int\", "
731
+	     "nonce=\""+calcNonce()+"\"\r\n");
732
+  }
733
+}
... ...
@@ -98,6 +98,8 @@ struct SIPRequestInfo {
98 98
 /** \brief SessionEventHandler for implementing uac authentication */
99 99
 class UACAuth : public AmSessionEventHandler
100 100
 {
101
+  static string server_nonce_secret;
102
+
101 103
   std::map<unsigned int, SIPRequestInfo> sent_requests;
102 104
 
103 105
   UACAuthCred* credential;
... ...
@@ -111,24 +113,26 @@ class UACAuth : public AmSessionEventHandler
111 113
 
112 114
   bool nonce_reuse; // reused nonce?
113 115
 
114
-  std::string find_attribute(const std::string& name, const std::string& header);
115
-  bool parse_header(const std::string& auth_hdr, UACAuthDigestChallenge& challenge);
116
+  static std::string find_attribute(const std::string& name, const std::string& header);
117
+  static bool parse_header(const std::string& auth_hdr, UACAuthDigestChallenge& challenge);
116 118
 
117
-  void uac_calc_HA1(const UACAuthDigestChallenge& challenge,
118
-		    std::string cnonce,
119
-		    HASHHEX sess_key);
119
+  static void uac_calc_HA1(const UACAuthDigestChallenge& challenge,
120
+			   const UACAuthCred* _credential,
121
+			   std::string cnonce,
122
+			   HASHHEX sess_key);
120 123
 
121
-  void uac_calc_HA2( const std::string& method, const std::string& uri,
122
-		     const UACAuthDigestChallenge& challenge,
123
-		     HASHHEX hentity,
124
-		     HASHHEX HA2Hex );
124
+  static void uac_calc_HA2( const std::string& method, const std::string& uri,
125
+			    const UACAuthDigestChallenge& challenge,
126
+			    HASHHEX hentity,
127
+			    HASHHEX HA2Hex );
125 128
 
126
-  void uac_calc_hentity( const std::string& body, HASHHEX hentity );
129
+  static void uac_calc_hentity( const std::string& body, HASHHEX hentity );
127 130
 	
128
-  void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
129
-			  const UACAuthDigestChallenge& challenge,
130
-			  const std::string& cnonce, const string& qop_value, 
131
-			  HASHHEX response);
131
+  static void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
132
+				 const UACAuthDigestChallenge& challenge,
133
+				 const std::string& cnonce, const string& qop_value,
134
+				 unsigned int nonce_count, 
135
+				 HASHHEX response);
132 136
 	
133 137
   /**
134 138
    *  do auth on cmd with nonce in auth_hdr if possible
... ...
@@ -160,6 +164,13 @@ class UACAuth : public AmSessionEventHandler
160 164
 			  AmBasicSipDialog::Status old_status);
161 165
   virtual bool onSendRequest(AmSipRequest& req, int& flags);
162 166
   virtual bool onSendReply(const AmSipRequest& req, AmSipReply& reply, int& flags);
167
+
168
+  static string calcNonce();
169
+  static bool checkNonce(const string& nonce);
170
+  static void checkAuthentication(const AmSipRequest* req, const string& realm,
171
+				  const string& user, const string& pwd, AmArg& ret);
172
+
173
+  static void setServerSecret(const string& secret);
163 174
 };
164 175
 
165 176
 
... ...
@@ -9,6 +9,9 @@ CORE_HDRS=$(CORE_SRCS:.cpp=.h)
9 9
 CORE_OBJS=$(CORE_SRCS:.cpp=.o)
10 10
 CORE_DEPS=$(subst ../,,$(CORE_SRCS:.cpp=.d))
11 11
 
12
+AUTH_DIR=../plug-in/uac_auth
13
+AUTH_OBJS=$(AUTH_DIR)/UACAuth.o
14
+
12 15
 SRCS=$(wildcard *.cpp)
13 16
 HDRS=$(SRCS:.cpp=.h)
14 17
 OBJS=$(SRCS:.cpp=.o)
... ...
@@ -48,6 +51,9 @@ deps: $(DEPS)
48 51
 .PHONY: core_deps
49 52
 core_deps: $(CORE_DEPS)
50 53
 
54
+AUTH_OBJS: $(AUTH_DIR)/UACAuth.cpp $(AUTH_DIR)/UACAuth.h
55
+	cd $(AUTH_DIR) ; $(MAKE) AUTH_OBJS
56
+
51 57
 COREPATH=..
52 58
 include ../../Makefile.defs
53 59
 
... ...
@@ -64,7 +70,7 @@ include ../../Makefile.defs
64 70
 $(NAME): $(OBJS) $(CORE_OBJS) $(SIP_STACK) $(LIBRESAMPLE) ../../Makefile.defs
65 71
 	-@echo ""
66 72
 	-@echo "making $(NAME)"
67
-	$(LD) -o $(NAME) $(OBJS) $(CORE_OBJS) $(SIP_STACK) $(LIBRESAMPLE) $(LDFLAGS) $(EXTRA_LDFLAGS)
73
+	$(LD) -o $(NAME) $(OBJS) $(CORE_OBJS) $(SIP_STACK) $(LIBRESAMPLE) $(LDFLAGS) $(EXTRA_LDFLAGS) $(AUTH_OBJS)
68 74
 
69 75
 
70 76
 ifeq '$(NAME)' '$(MAKECMDGOALS)'
... ...
@@ -21,6 +21,8 @@ FCT_BGN() {
21 21
   init_logging();
22 22
   log_stderr=true;
23 23
   log_level=3;
24
+
25
+  FCTMF_SUITE_CALL(test_auth);
24 26
   FCTMF_SUITE_CALL(test_headers);
25 27
   FCTMF_SUITE_CALL(test_uriparser);
26 28
   FCTMF_SUITE_CALL(test_jsonarg);
27 29
new file mode 100644
... ...
@@ -0,0 +1,48 @@
1
+#include "fct.h"
2
+
3
+#include "log.h"
4
+
5
+#include "AmSipHeaders.h"
6
+#include "AmSipMsg.h"
7
+#include "AmUtils.h"
8
+#include "plug-in/uac_auth/UACAuth.h"
9
+
10
+FCTMF_SUITE_BGN(test_auth) {
11
+
12
+    FCT_TEST_BGN(nonce_gen) {
13
+
14
+      string secret = "1234secret";
15
+      string nonce = UACAuth::calcNonce(secret);
16
+      //      DBG("nonce '%s'\n", nonce.c_str());    
17
+      fct_chk( UACAuth::checkNonce(nonce, secret));
18
+    } FCT_TEST_END();
19
+
20
+    FCT_TEST_BGN(nonce_wrong_secret) {
21
+      string secret = "1234secret";
22
+      string nonce = UACAuth::calcNonce(secret);
23
+      fct_chk( !UACAuth::checkNonce(nonce, secret+"asd"));
24
+    } FCT_TEST_END();
25
+
26
+    FCT_TEST_BGN(nonce_wrong_nonce) {
27
+      string secret = "1234secret";
28
+      string nonce = UACAuth::calcNonce(secret);
29
+      nonce[0]=0;
30
+      nonce[1]=0;
31
+      fct_chk( !UACAuth::checkNonce(nonce, secret));
32
+    } FCT_TEST_END();
33
+
34
+    FCT_TEST_BGN(nonce_wrong_nonce) {
35
+      string secret = "1234secret";
36
+      string nonce = UACAuth::calcNonce(secret);
37
+      nonce+="hallo";
38
+      fct_chk( !UACAuth::checkNonce(nonce, secret));
39
+    } FCT_TEST_END();
40
+
41
+    FCT_TEST_BGN(nonce_wrong_nonce2) {
42
+      string secret = "1234secret";
43
+      string nonce = UACAuth::calcNonce(secret);
44
+      nonce[nonce.size()-1]=nonce[nonce.size()-2];
45
+      fct_chk( !UACAuth::checkNonce(nonce, secret));
46
+    } FCT_TEST_END();
47
+
48
+} FCTMF_SUITE_END();
0 49
new file mode 100644
... ...
@@ -0,0 +1 @@
1
+ 
... ...
@@ -1,4 +1,4 @@
1
-uac_auth Client authentication 
1
+uac_auth Client / Server authentication 
2 2
 
3 3
 how to use uac_auth
4 4
 --------------------
... ...
@@ -30,3 +30,61 @@ How to
30 30
 
31 31
 see announce_auth app for example application
32 32
 
33
+
34
+How to use server auth
35
+----------------------
36
+
37
+To authenticate a request, use the "checkAuth" DI function.
38
+
39
+ Arguments:
40
+     args[0] - ArgObject pointing to the Request (AmSipRequest object)
41
+     args[1] - realm
42
+     args[2] - user
43
+     args[3] - password
44
+ Return values:
45
+     ret[0] - code: 200 for successful auth, 401 for unsuccessful (ie.
46
+     ret[1] - reason string
47
+     ret[2] - optional auth header
48
+
49
+Limitations
50
+-----------
51
+
52
+- URI in auth hdr is not checked
53
+- multiple Authorization headers are probably not properly processed (only the first one is used)
54
+
55
+code example:
56
+
57
+    AmDynInvokeFactory* fact = 
58
+      AmPlugIn::instance()->getFactory4Di("uac_auth");
59
+    if (NULL != fact) {
60
+      AmDynInvoke* di_inst = fact->getInstance();
61
+      if(di_inst) {
62
+	AmArg di_args, di_ret;
63
+	try {
64
+	  di_args.push(AmArg((AmObject*)&req));
65
+	  di_args.push("myrealm");
66
+	  di_args.push("myuser");
67
+	  di_args.push("mypwd");
68
+	  di_inst->invoke("checkAuth", di_args, di_ret);
69
+	  
70
+	  if (di_ret.size() >= 3) {
71
+	    if (di_ret[0].asInt() != 200) {
72
+	      DBG("Auth: replying %u %s - hdrs: '%s'\n",
73
+		  di_ret[0].asInt(), di_ret[1].asCStr(), di_ret[2].asCStr());
74
+	      dlg->reply(req, di_ret[0].asInt(), di_ret[1].asCStr(), NULL, di_ret[2].asCStr());
75
+	      return;
76
+	    } else {
77
+	      DBG("Successfully authenticated request.\n");
78
+	    }
79
+	  }
80
+	} catch (const AmDynInvoke::NotImplemented& ni) {
81
+	  ERROR("not implemented DI function 'checkAuth'\n");
82
+	} catch (const AmArg::OutOfBoundsException& oob) {
83
+	  ERROR("out of bounds in  DI call 'checkAuth'\n");
84
+	} catch (const AmArg::TypeMismatchException& oob) {
85
+	  ERROR("type mismatch  in  DI call checkAuth\n");
86
+	} catch (...) {
87
+	  ERROR("unexpected Exception  in  DI call checkAuth\n");
88
+	}
89
+     }
90
+  }