Beispiel #1
0
        /// <summary>
        /// Gets specified realm SIP proxy credentials. Returns null if none exists for specified realm.
        /// </summary>
        /// <param name="request">SIP reques.</param>
        /// <param name="realm">Realm(domain).</param>
        /// <returns>Returns specified realm credentials or null if none.</returns>
        public static SIP_t_Credentials GetCredentials(SIP_Request request,string realm)
        {
            foreach(SIP_SingleValueHF<SIP_t_Credentials> authorization in request.ProxyAuthorization.HeaderFields){
                if(authorization.ValueX.Method.ToLower() == "digest"){
                    Auth_HttpDigest authDigest = new Auth_HttpDigest(authorization.ValueX.AuthData,request.RequestLine.Method);
                    if(authDigest.Realm.ToLower() == realm.ToLower()){
                        return authorization.ValueX;
                    }
                }
            }

            return null;
        }
Beispiel #2
0
        /// <summary>
        /// Authenticates user. Authenticate method chooses strongest possible authentication method supported by server, 
        /// preference order DIGEST-MD5 -> CRAM-MD5 -> LOGIN.
        /// </summary>
        /// <param name="userName">User login name.</param>
        /// <param name="password">Password.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when SMTP client is not connected or is already authenticated.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>userName</b> is null.</exception>
        /// <exception cref="SMTP_ClientException">Is raised when SMTP server returns error.</exception>
        public void Authenticate(string userName,string password)
        {
            if(this.IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(!this.IsConnected){
                throw new InvalidOperationException("You must connect first.");
            }
            if(this.IsAuthenticated){
                throw new InvalidOperationException("Session is already authenticated.");
            }
            if(string.IsNullOrEmpty(userName)){
                throw new ArgumentNullException("userName");
            }
            if(password == null){
                password = "";
            }

            // Choose authentication method, we consider LOGIN as default.
            string authMethod = "LOGIN";
            List<string> authMethods = new List<string>(this.SaslAuthMethods);
            if(authMethods.Contains("DIGEST-MD5")){
                authMethod = "DIGEST-MD5";
            }
            else if(authMethods.Contains("CRAM-MD5")){
                authMethod = "CRAM-MD5";
            }

            #region AUTH LOGIN

            if(authMethod == "LOGIN"){
                /* LOGIN
                      Example:
                        C: AUTH LOGIN<CRLF>
                        S: 334 VXNlcm5hbWU6<CRLF>   VXNlcm5hbWU6 = base64("USERNAME")
                        C: base64(username)<CRLF>
                        S: 334 UGFzc3dvcmQ6<CRLF>   UGFzc3dvcmQ6 = base64("PASSWORD")
                        C: base64(password)<CRLF>
                        S: 235 Ok<CRLF>
                */

                WriteLine("AUTH LOGIN");

                // Read server response.
                string line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("334")){
                    throw new SMTP_ClientException(line);
                }

                // Send user name to server.
                WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(userName)));

                // Read server response.
                line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("334")){
                    throw new SMTP_ClientException(line);
                }

                // Send password to server.
                WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(password)));

                // Read server response.
                line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("235")){
                    throw new SMTP_ClientException(line);
                }

                m_pAuthdUserIdentity = new GenericIdentity(userName,"LOGIN");
            }

            #endregion

            #region AUTH CRAM-MD5

            else if(authMethod == "CRAM-MD5"){
                /* CRAM-M5
                    Description:
                        HMACMD5 key is "password".

                    Example:
                        C: AUTH CRAM-MD5<CRLF>
                        S: 334 base64(md5_calculation_hash)<CRLF>
                        C: base64(username password_hash)<CRLF>
                        S: 235 Ok<CRLF>
                */

                WriteLine("AUTH CRAM-MD5");

                // Read server response.
                string line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("334")){
                    throw new SMTP_ClientException(line);
                }

                HMACMD5 kMd5         = new HMACMD5(Encoding.ASCII.GetBytes(password));
                string  passwordHash = Net_Utils.ToHex(kMd5.ComputeHash(Convert.FromBase64String(line.Split(' ')[1]))).ToLower();

                // Send authentication info to server.
                WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + " " + passwordHash)));

                // Read server response.
                line = ReadLine();
                // Response line must start with 235 or otherwise it's error response
                if(!line.StartsWith("235")){
                    throw new SMTP_ClientException(line);
                }

                m_pAuthdUserIdentity = new GenericIdentity(userName,"CRAM-MD5");
            }

            #endregion

            #region AUTH DIGEST-MD5

            else if(authMethod == "DIGEST-MD5"){
                /*
                    Example:
                        C: AUTH DIGEST-MD5<CRLF>
                        S: 334 base64(digestChallange)<CRLF>
                        C: base64(digestAuthorization)<CRLF>
                        S: 334 base64(serverResponse)<CRLF>
                        C: <CRLF>
                        S: 235 Ok<CRLF>
                */

                WriteLine("AUTH DIGEST-MD5");

                // Read server response.
                string line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("334")){
                    throw new SMTP_ClientException(line);
                }

                Auth_HttpDigest digestmd5 = new Auth_HttpDigest(Encoding.Default.GetString(Convert.FromBase64String(line.Split(' ')[1])),"AUTHENTICATE");
                digestmd5.CNonce = Auth_HttpDigest.CreateNonce();
                digestmd5.Uri = "smtp/" + digestmd5.Realm;
                digestmd5.UserName = userName;
                digestmd5.Password = password;

                // Send authentication info to server.
                WriteLine(Convert.ToBase64String(Encoding.ASCII.GetBytes(digestmd5.ToAuthorization(false))));

                // Read server response.
                line = ReadLine();
                // Response line must start with 334 or otherwise it's error response.
                if(!line.StartsWith("334")){
                    throw new SMTP_ClientException(line);
                }

                // Send empty line.
                WriteLine("");

                // Read server response.
                line = ReadLine();
                // Response line must start with 235 or otherwise it's error response.
                if(!line.StartsWith("235")){
                    throw new SMTP_ClientException(line);
                }

                m_pAuthdUserIdentity = new GenericIdentity(userName,"DIGEST-MD5");
            }

            #endregion
        }
Beispiel #3
0
        private void AUTH(string argsText)
        {
            /* Rfc 2554 AUTH --------------------------------------------------//
            Restrictions:
                 After an AUTH command has successfully completed, no more AUTH
                 commands may be issued in the same session.  After a successful
                 AUTH command completes, a server MUST reject any further AUTH
                 commands with a 503 reply.

            Remarks:
                If an AUTH command fails, the server MUST behave the same as if
                the client had not issued the AUTH command.
            */
            if(this.Authenticated){
                this.Socket.WriteLine("503 already authenticated");
                return;
            }

            try{
                //------ Parse parameters -------------------------------------//
                string userName = "";
                string password = "";
                AuthUser_EventArgs aArgs = null;

                string[] param = argsText.Split(new char[]{' '});
                switch(param[0].ToUpper())
                {
                    case "PLAIN":
                        this.Socket.WriteLine("504 Unrecognized authentication type.");
                        break;

                    case "LOGIN":

                        #region LOGIN authentication

                        //---- AUTH = LOGIN ------------------------------
                        /* Login
                            C: AUTH LOGIN
                            S: 334 VXNlcm5hbWU6
                            C: username_in_base64
                            S: 334 UGFzc3dvcmQ6
                            C: password_in_base64

                            or (initial-response argument included to avoid one 334 server response)

                            C: AUTH LOGIN username_in_base64
                            S: 334 UGFzc3dvcmQ6
                            C: password_in_base64

                            VXNlcm5hbWU6 base64_decoded= USERNAME
                            UGFzc3dvcmQ6 base64_decoded= PASSWORD
                        */
                        // Note: all strings are base64 strings eg. VXNlcm5hbWU6 = UserName.

                        // No user name included (initial-response argument)
                        if(param.Length == 1){
                            // Query UserName
                            this.Socket.WriteLine("334 VXNlcm5hbWU6");

                            string userNameLine = this.Socket.ReadLine();
                            // Encode username from base64
                            if(userNameLine.Length > 0){
                                userName = System.Text.Encoding.Default.GetString(Convert.FromBase64String(userNameLine));
                            }
                        }
                        // User name included, use it
                        else{
                            userName = System.Text.Encoding.Default.GetString(Convert.FromBase64String(param[1]));
                        }

                        // Query Password
                        this.Socket.WriteLine("334 UGFzc3dvcmQ6");

                        string passwordLine = this.Socket.ReadLine();
                        // Encode password from base64
                        if(passwordLine.Length > 0){
                            password = System.Text.Encoding.Default.GetString(Convert.FromBase64String(passwordLine));
                        }

                        aArgs = m_pServer.OnAuthUser(this,userName,password,"",AuthType.Plain);
                        if(aArgs.Validated){
                            this.Socket.WriteLine("235 Authentication successful.");

                            this.SetUserName(userName);
                        }
                        else{
                            this.Socket.WriteLine("535 Authentication failed");
                        }

                        #endregion

                        break;

                    case "CRAM-MD5":

                        #region CRAM-MD5 authentication

                        /* Cram-M5
                            C: AUTH CRAM-MD5
                            S: 334 <md5_calculation_hash_in_base64>
                            C: base64(username password_hash)
                        */

                        string md5Hash = "<" + Guid.NewGuid().ToString().ToLower() + ">";
                        this.Socket.WriteLine("334 " + Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(md5Hash)));

                        string reply = this.Socket.ReadLine();

                        reply = System.Text.Encoding.Default.GetString(Convert.FromBase64String(reply));
                        string[] replyArgs = reply.Split(' ');
                        userName = replyArgs[0];

                        aArgs = m_pServer.OnAuthUser(this,userName,replyArgs[1],md5Hash,AuthType.CRAM_MD5);
                        if(aArgs.Validated){
                            this.Socket.WriteLine("235 Authentication successful.");

                            this.SetUserName(userName);
                        }
                        else{
                            this.Socket.WriteLine("535 Authentication failed");
                        }

                        #endregion

                        break;

                    case "DIGEST-MD5":

                        #region DIGEST-MD5 authentication

                        /* RFC 2831 AUTH DIGEST-MD5
                         *
                        * Example:
                        *
                        * C: AUTH DIGEST-MD5
                        * S: 334 base64(realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth",algorithm=md5-sess)
                        * C: base64(username="******",realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",
                        *    nc=00000001,cnonce="OA6MHXh6VqTrRk",digest-uri="smtp/elwood.innosoft.com",
                        *    response=d388dad90d4bbd760a152321f2143af7,qop=auth)
                        * S: 334 base64(rspauth=ea40f60335c427b5527b84dbabcdfffd)
                        * C:
                        * S: 235 Authentication successful.
                        */

                        string nonce  = Auth_HttpDigest.CreateNonce();
                        string opaque = Auth_HttpDigest.CreateOpaque();
                        Auth_HttpDigest digest = new Auth_HttpDigest(this.BindInfo.HostName,nonce,opaque);
                        digest.Algorithm = "md5-sess";

                        this.Socket.WriteLine("334 " + AuthHelper.Base64en(digest.ToChallange(false)));

                        string clientResponse = AuthHelper.Base64de(this.Socket.ReadLine());
                        digest = new Auth_HttpDigest(clientResponse,"AUTHENTICATE");

                        // Check that realm,nonce and opaque in client response are same as we specified.
                        if(this.BindInfo.HostName != digest.Realm){
                            this.Socket.WriteLine("535 Authentication failed, 'realm' won't match.");
                            return;
                        }
                        if(nonce != digest.Nonce){
                            this.Socket.WriteLine("535 Authentication failed, 'nonce' won't match.");
                            return;
                        }
                        if(opaque != digest.Opaque){
                            this.Socket.WriteLine("535 Authentication failed, 'opaque' won't match.");
                            return;
                        }

                        userName = digest.UserName;

                        aArgs = m_pServer.OnAuthUser(this,userName,digest.Response,clientResponse,AuthType.DIGEST_MD5);
                        if(aArgs.Validated){
                            // Send server computed password hash
                            this.Socket.WriteLine("334 " + AuthHelper.Base64en("rspauth=" + aArgs.ReturnData));

                            // We must got empty line here
                            clientResponse = this.Socket.ReadLine();
                            if(clientResponse == ""){
                                this.Socket.WriteLine("235 Authentication successful.");

                                this.SetUserName(userName);
                            }
                            else{
                                this.Socket.WriteLine("535 Authentication failed, unexpected client response.");
                            }
                        }
                        else{
                            this.Socket.WriteLine("535 Authentication failed.");
                        }

                        #endregion

                        break;

                    default:
                        this.Socket.WriteLine("504 Unrecognized authentication type.");
                        break;
                }
                //-----------------------------------------------------------------//
            }
            catch{
                this.Socket.WriteLine("535 Authentication failed.");
            }
        }
Beispiel #4
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="requireSSL">Specifies if this mechanism is available to SSL connections only.</param>
        public AUTH_SASL_ServerMechanism_DigestMd5(bool requireSSL)
        {
            m_RequireSSL = requireSSL;

            m_Nonce = Auth_HttpDigest.CreateNonce();
        }
Beispiel #5
0
        /// <summary>
        /// This method is called when new request is received.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        internal void OnRequestReceived(SIP_RequestReceivedEventArgs e)
        {
            SIP_Request request = e.Request;

            if(request.RequestLine.Method == SIP_Methods.CANCEL){
                /* RFC 3261 9.2.
                    If the UAS did not find a matching transaction for the CANCEL
                    according to the procedure above, it SHOULD respond to the CANCEL
                    with a 481 (Call Leg/Transaction Does Not Exist).
                  
                    Regardless of the method of the original request, as long as the
                    CANCEL matched an existing transaction, the UAS answers the CANCEL
                    request itself with a 200 (OK) response.
                */

                SIP_ServerTransaction trToCancel = m_pProxy.Stack.TransactionLayer.MatchCancelToTransaction(e.Request);
                if(trToCancel != null){
                    trToCancel.Cancel();
                    //e.ServerTransaction.SendResponse(request.CreateResponse(SIP_ResponseCodes.x200_Ok));
                }
                else{
                    //e.ServerTransaction.SendResponse(request.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist));
                }
            }
            // We never should ge BYE here, because transport layer must match it to dialog.
            else if(request.RequestLine.Method == SIP_Methods.BYE){
                /* RFC 3261 15.1.2.
                    If the BYE does not match an existing dialog, the UAS core SHOULD generate a 481
                    (Call/Transaction Does Not Exist) response and pass that to the server transaction.
                */
                //e.ServerTransaction.SendResponse(request.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist));
            }
            // We never should ge ACK here, because transport layer must match it to dialog.
            else if(request.RequestLine.Method == SIP_Methods.ACK){
                // ACK is response less request, so we may not return error to it.
            }
            // B2BUA must respond to OPTIONS request, not to forward it.
            else if(request.RequestLine.Method == SIP_Methods.OPTIONS){     /*          
                SIP_Response response = e.Request.CreateResponse(SIP_ResponseCodes.x200_Ok);                
                // Add Allow to non ACK response.
                if(e.Request.RequestLine.Method != SIP_Methods.ACK){
                    response.Allow.Add("INVITE,ACK,OPTIONS,CANCEL,BYE,PRACK,MESSAGE,UPDATE");
                }
                // Add Supported to 2xx non ACK response.
                if(response.StatusCodeType == SIP_StatusCodeType.Success && e.Request.RequestLine.Method != SIP_Methods.ACK){
                    response.Supported.Add("100rel,timer");
                }
                e.ServerTransaction.SendResponse(response);*/
            }
            // We never should get PRACK here, because transport layer must match it to dialog.
            else if(request.RequestLine.Method == SIP_Methods.PRACK){
                //e.ServerTransaction.SendResponse(request.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist));
            }
            // We never should get UPDATE here, because transport layer must match it to dialog.
            else if(request.RequestLine.Method == SIP_Methods.UPDATE){
                //e.ServerTransaction.SendResponse(request.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist));
            }
            else{
                /* draft-marjou-sipping-b2bua-00 4.1.3.
                    When the UAS of the B2BUA receives an upstream SIP request, its
                    associated UAC generates a new downstream SIP request with its new
                    Via, Max-Forwards, Call-Id, CSeq, and Contact header fields. Route
                    header fields of the upstream request are copied in the downstream
                    request, except the first Route header if it is under the
                    responsibility of the B2BUA.  Record-Route header fields of the
                    upstream request are not copied in the new downstream request, as
                    Record-Route is only meaningful for the upstream dialog.  The UAC
                    SHOULD copy other header fields and body from the upstream request
                    into this downstream request before sending it.
                */

                SIP_Request b2buaRequest = e.Request.Copy();
                b2buaRequest.Via.RemoveAll();
                b2buaRequest.MaxForwards = 70;                
                b2buaRequest.CallID = SIP_t_CallID.CreateCallID().CallID;
                b2buaRequest.CSeq.SequenceNumber = 1;
                b2buaRequest.Contact.RemoveAll();
                // b2buaRequest.Contact.Add(m_pProxy.CreateContact(b2buaRequest.To.Address).ToStringValue());
                if(b2buaRequest.Route.Count > 0 && m_pProxy.IsLocalRoute(SIP_Uri.Parse(b2buaRequest.Route.GetTopMostValue().Address.Uri.ToString()))){
                    b2buaRequest.Route.RemoveTopMostValue();
                }                
                b2buaRequest.RecordRoute.RemoveAll();

                // Remove our Authorization header if it's there.
                foreach(SIP_SingleValueHF<SIP_t_Credentials> header in b2buaRequest.ProxyAuthorization.HeaderFields){
                    try{
                        Auth_HttpDigest digest = new Auth_HttpDigest(header.ValueX.AuthData,b2buaRequest.RequestLine.Method);
                        if(m_pProxy.Stack.Realm == digest.Realm){
                            b2buaRequest.ProxyAuthorization.Remove(header);
                        }
                    }
                    catch{
                        // We don't care errors here. This can happen if remote server xxx auth method here and
                        // we don't know how to parse it, so we leave it as is.
                    }
                }

                //--- Add/replace default fields. ------------------------------------------
                b2buaRequest.Allow.RemoveAll();
                b2buaRequest.Supported.RemoveAll();
                // Accept to non ACK,BYE request.
                if(request.RequestLine.Method != SIP_Methods.ACK && request.RequestLine.Method != SIP_Methods.BYE){
                    b2buaRequest.Allow.Add("INVITE,ACK,OPTIONS,CANCEL,BYE,PRACK");
                }
                // Supported to non ACK request. 
                if(request.RequestLine.Method != SIP_Methods.ACK){
                    b2buaRequest.Supported.Add("100rel,timer");
                }
                // Remove Require: header.
                b2buaRequest.Require.RemoveAll();

                // RFC 4028 7.4. For re-INVITE and UPDATE we need to add Session-Expires and Min-SE: headers.
                if(request.RequestLine.Method == SIP_Methods.INVITE || request.RequestLine.Method == SIP_Methods.UPDATE){
                    b2buaRequest.SessionExpires = new SIP_t_SessionExpires(m_pProxy.Stack.SessionExpries,"uac");
                    b2buaRequest.MinSE = new SIP_t_MinSE(m_pProxy.Stack.MinimumSessionExpries);
                }

                // Forward request.
                //m_pProxy.ForwardRequest(true,e,b2buaRequest,false);
            }
        }
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="auth">Authentication context.</param>
 public SIP_AuthenticateEventArgs(Auth_HttpDigest auth)
 {
     m_pAuth = auth;
 }
Beispiel #7
0
 public DataSet AuthUser(string userName, string passwData, string authData, AuthType authType)
 {
     this.m_UpdSync.AddMethod();
     DataSet dataSet = new DataSet();
     DataTable dataTable = dataSet.Tables.Add("Result");
     dataTable.Columns.Add("Result");
     dataTable.Columns.Add("ReturnData");
     DataRow dataRow = dataTable.NewRow();
     dataRow["Result"] = "false";
     dataRow["ReturnData"] = "";
     dataTable.Rows.Add(dataRow);
     DataSet result;
     try
     {
         foreach (DataRow dataRow2 in this.dsUsers.Tables["Users"].Rows)
         {
             if (Convert.ToBoolean(dataRow2["Enabled"]) && dataRow2["USERNAME"].ToString().ToLower() == userName.ToLower())
             {
                 string text = dataRow2["PASSWORD"].ToString().ToLower();
                 if (authType != AuthType.Plain)
                 {
                     if (authType == AuthType.DIGEST_MD5)
                     {
                         Auth_HttpDigest auth_HttpDigest = new Auth_HttpDigest(authData, "AUTHENTICATE");
                         if (auth_HttpDigest.Authenticate(userName, text))
                         {
                             dataRow["Result"] = "true";
                             dataRow["ReturnData"] = auth_HttpDigest.CalculateResponse(userName, text);
                             result = dataSet;
                             return result;
                         }
                     }
                 }
                 else
                 {
                     if (text == passwData.ToLower())
                     {
                         dataRow["Result"] = "true";
                         result = dataSet;
                         return result;
                     }
                 }
                 result = dataSet;
                 return result;
             }
         }
         result = dataSet;
     }
     catch (Exception ex)
     {
         throw ex;
     }
     finally
     {
         this.m_UpdSync.RemoveMethod();
     }
     return result;
 }
Beispiel #8
0
		/// <summary>
		/// Authenticates user.
		/// </summary>
		/// <param name="userName">User name.</param>
		/// <param name="passwData">Password data.</param>
		/// <param name="authData">Authentication specific data(as tag).</param>
		/// <param name="authType">Authentication type.</param>
		/// <returns></returns>
		public DataSet AuthUser(string userName,string passwData,string authData,AuthType authType)
		{
			DataSet retVal = new DataSet();
			DataTable dt = retVal.Tables.Add("Result");
			dt.Columns.Add("Result");
			dt.Columns.Add("ReturnData");
			DataRow drx = dt.NewRow();
			drx["Result"] = "false";
			drx["ReturnData"] = "";
			dt.Rows.Add(drx);

			using(WSqlCommand sqlCmd = new WSqlCommand(m_ConStr,"lspr_GetUserProperties")){
				sqlCmd.AddParameter("_userName",NpgsqlDbType.Varchar,userName);
						
				DataSet ds = sqlCmd.Execute();
				ds.Tables[0].TableName = "Users";

				if(ds.Tables["Users"].Rows.Count > 0){
					string password = ds.Tables["Users"].Rows[0]["PASSWORD"].ToString().ToLower();

					switch(authType)
					{
						case AuthType.APOP:
							if(AuthHelper.Apop(password,authData) == passwData){
								drx["Result"] = "true";
								return retVal;
							}
							break;

						case AuthType.CRAM_MD5:	
							if(AuthHelper.Cram_Md5(password,authData) == passwData){
								drx["Result"] = "true";
								return retVal;
							}
							break;

						case AuthType.DIGEST_MD5:	
							Auth_HttpDigest digest = new Auth_HttpDigest(authData,"AUTHENTICATE");
                            if(digest.Authenticate(userName,password)){
                                drx["Result"]     = "true";
								drx["ReturnData"] = digest.CalculateResponse(userName,password);
                                                      
								return retVal;
                            }
							break;

						case AuthType.Plain:
							if(password == passwData.ToLower()){
								drx["Result"] = "true";
								return retVal;
							}
							break;						
					}
				}
			}			

			return retVal;
		}
Beispiel #9
0
// REMOVE ME:
		#region method AuthUser

		/// <summary>
		/// Authenticates user.
		/// </summary>
		/// <param name="userName">User name.</param>
		/// <param name="passwData">Password data.</param>
		/// <param name="authData">Authentication specific data(as tag).</param>
		/// <param name="authType">Authentication type.</param>
		/// <returns></returns>
		public DataSet AuthUser(string userName,string passwData,string authData,AuthType authType)
		{
			m_UpdSync.AddMethod();

			DataSet retVal = new DataSet();
			DataTable dt = retVal.Tables.Add("Result");
			dt.Columns.Add("Result");
			dt.Columns.Add("ReturnData");
			DataRow drx = dt.NewRow();
			drx["Result"] = "false";
			drx["ReturnData"] = "";
			dt.Rows.Add(drx);

			try{
				// See if user with specified name exists
				foreach(DataRow dr in dsUsers.Tables["Users"].Rows){					
					if(Convert.ToBoolean(dr["Enabled"]) && dr["USERNAME"].ToString().ToLower() == userName.ToLower()){
						string password = dr["PASSWORD"].ToString().ToLower();

						switch(authType)
						{/*
							case AuthType.APOP:
								if(AuthHelper.Apop(password,authData) == passwData){
									drx["Result"] = "true";
									return retVal;
								}
								break;

							case AuthType.CRAM_MD5:	
								if(AuthHelper.Cram_Md5(password,authData) == passwData){
									drx["Result"] = "true";
									return retVal;
								}
								break;*/

							case AuthType.DIGEST_MD5:
	                            Auth_HttpDigest digest = new Auth_HttpDigest(authData,"AUTHENTICATE");
                                if(digest.Authenticate(userName,password)){
                                    drx["Result"]     = "true";
									drx["ReturnData"] = digest.CalculateResponse(userName,password);
                                                      
									return retVal;
                                }
								break;

							case AuthType.Plain:
								if(password == passwData.ToLower()){
									drx["Result"] = "true";
									return retVal;
								}
								break;
						}

						return retVal;
					}
				}

				return retVal;
			}
			catch(Exception x){
				throw x;
			}
			finally{
				m_UpdSync.RemoveMethod();
			}
		}
Beispiel #10
0
        /// <summary>
        /// Continues authentication process.
        /// </summary>
        /// <param name="clientResponse">Client sent SASL response.</param>
        /// <returns>Retunrns challange response what must be sent to client or null if authentication has completed.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>clientResponse</b> is null reference.</exception>
        public override string Continue(string clientResponse)
        {
            if (clientResponse == null)
            {
                throw new ArgumentNullException("clientResponse");
            }

            /* RFC 2831.
             *  The base64-decoded version of the SASL exchange is:
             *
             *  S: realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth",
             *     algorithm=md5-sess,charset=utf-8
             *  C: charset=utf-8,username="******",realm="elwood.innosoft.com",
             *     nonce="OA6MG9tEQGm2hh",nc=00000001,cnonce="OA6MHXh6VqTrRk",
             *     digest-uri="imap/elwood.innosoft.com",
             *     response=d388dad90d4bbd760a152321f2143af7,qop=auth
             *  S: rspauth=ea40f60335c427b5527b84dbabcdfffd
             *  C:
             *  S: ok
             *
             *  The password in this example was "secret".
             */

            if (m_State == 0)
            {
                m_State++;

                return("realm=\"" + m_Realm + "\",nonce=\"" + m_Nonce + "\",qop=\"auth\",algorithm=md5-sess,charset=utf-8");
            }
            else if (m_State == 1)
            {
                m_State++;

                Auth_HttpDigest auth = new Auth_HttpDigest(clientResponse, "AUTHENTICATE");
                auth.Qop       = "auth";
                auth.Algorithm = "md5-sess";

                // Check realm and nonce value.
                if (m_Realm != auth.Realm || m_Nonce != auth.Nonce)
                {
                    return("rspauth=\"\"");
                }

                m_UserName = auth.UserName;
                AUTH_e_UserInfo result = OnGetUserInfo(auth.UserName);
                if (result.UserExists)
                {
                    if (auth.Authenticate(result.UserName, result.Password))
                    {
                        m_IsAuthenticated = true;

                        return("rspauth=" + auth.CalculateRspAuth(result.UserName, result.Password));
                    }
                }

                return("rspauth=\"\"");
            }
            else
            {
                m_IsCompleted = true;
            }

            return(null);
        }
        /// <summary>
        /// Handles REGISTER method.
        /// </summary>
        /// <param name="request">SIP REGISTER request.</param>
        public void Register(SIP_Request request)
        {
            /* RFC 3261 10.3 Processing REGISTER Requests.
                1. The registrar inspects the Request-URI to determine whether it
                    has access to bindings for the domain identified in the Request-URI.

                2. To guarantee that the registrar supports any necessary extensions,
                   the registrar MUST process the Require header field.

                3. A registrar SHOULD authenticate the UAC.

                4. The registrar SHOULD determine if the authenticated user is
                   authorized to modify registrations for this address-of-record.

                5. The registrar extracts the address-of-record from the To header
                   field of the request.  If the address-of-record is not valid
                   for the domain in the Request-URI, the registrar MUST send a
                   404 (Not Found) response and skip the remaining steps.

                6. The registrar checks whether the request contains the Contact
                   header field.  If not, it skips to the last step.  If the
                   Contact header field is present, the registrar checks if there
                   is one Contact field value that contains the special value "*"
                   and an Expires field.  If the request has additional Contact
                   fields or an expiration time other than zero, the request is
                   invalid, and the server MUST return a 400 (Invalid Request).

                7. The registrar now processes each contact address in the Contact
                   eader field in turn.

                   If Expire paremeter specified, check that it isnt smaller than server minimum
                   allowed expire value. If smaller return error 423 (Interval Too Brief) and add
                   header field Min-Expires. If no expire parameter, user server default value.

                8. The registrar returns a 200 (OK) response.  The response MUST contain Contact
                   header field values enumerating all current bindings. Each Contact value MUST
                   feature an "expires" parameter indicating its expiration interval chosen by the
                   registrar. The response SHOULD include a Date header field.

            */

            SocketEx socket = request.Socket;

            // 3. -------------------------------------------------------------------------
            // User didn't supplied credentials.
            if(request.Authorization.Count == 0){
                SIP_Response notAuthenticatedResponse = request.CreateResponse(SIP_ResponseCodes.Unauthorized);
                notAuthenticatedResponse.WWWAuthenticate.Add("digest realm=\"\",qop=\"auth\",nonce=\"" + m_pProxy.Stack.DigestNonceManager.CreateNonce() + "\",opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");

                // Send response
                m_pProxy.Stack.TransportLayer.SendResponse(socket,notAuthenticatedResponse);
                return;
            }

            // Check that client supplied supported authentication method.
            string authenticationData = "";
            // digest
            if(request.Authorization.GetFirst().ValueX.Method.ToLower() == "digest"){
                authenticationData = request.Authorization.GetFirst().ValueX.AuthData;
            }
            // Not supported authentication.
            else{
                m_pProxy.Stack.TransportLayer.SendResponse(socket,request.CreateResponse(SIP_ResponseCodes.Not_Implemented + " authentication method"));
                return;
            }

            Auth_HttpDigest auth = new Auth_HttpDigest(authenticationData,request.Method);
            // Check nonce validity
            if(!m_pProxy.Stack.DigestNonceManager.NonceExists(auth.Nonce)){
                SIP_Response notAuthenticatedResponse = request.CreateResponse(SIP_ResponseCodes.Unauthorized);
                notAuthenticatedResponse.WWWAuthenticate.Add("digest realm=\"\",qop=\"auth\",nonce=\"" + m_pProxy.Stack.DigestNonceManager.CreateNonce() + "\",opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");

                // Send response
                m_pProxy.Stack.TransportLayer.SendResponse(socket,notAuthenticatedResponse);
                return;
            }
            // Valid nonce, consume it so that nonce can't be used any more.
            else{
                m_pProxy.Stack.DigestNonceManager.RemoveNonce(auth.Nonce);
            }

            SIP_ServerProxyCore.AuthenticateEventArgs eArgs = m_pProxy.OnAuthenticate(auth);
            // Authenticate failed.
            if(!eArgs.Authenticated){
                SIP_Response notAuthenticatedResponse = request.CreateResponse(SIP_ResponseCodes.Unauthorized);
                notAuthenticatedResponse.WWWAuthenticate.Add("digest realm=\"\",qop=\"auth\",nonce=\"" + m_pProxy.Stack.DigestNonceManager.CreateNonce() + "\",opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"");

                // Send response
                m_pProxy.Stack.TransportLayer.SendResponse(socket,notAuthenticatedResponse);
                return;
            }
            //----------------------------------------------------------------------------

            // 5. Get TO:.
            string registrationName = SipUtils.ParseAddress(request.To.ToStringValue()).ToLower();

            // 4. Check if user can register specified address.
            // User is not allowed to register specified address.
            if(!m_pProxy.OnCanRegister(auth.UserName,registrationName)){
                m_pProxy.Stack.TransportLayer.SendResponse(socket,request.CreateResponse(SIP_ResponseCodes.Forbidden));
                return;
            }

            //--- 6. And 7. --------------------------------------------------------
            SIP_t_ContactParam[] contacts = request.Contact.GetAllValues();
            if(request.Header.Contains("Contact:")){
                SIP_t_ContactParam starContact = null;
                foreach(SIP_t_ContactParam contact in contacts){
                    // We have STAR contact, store it.
                    if(starContact == null && contact.IsStarContact){
                        starContact = contact;
                    }

                    //--- Handle minimum expires time --------------------------------------------
                    // Get contact expires time, if not specified, get header expires time.
                    int expires = contact.Expires;
                    if(expires < 1){
                        expires = request.Expires;
                    }
                    // We don't check that for STAR contact and if contact expires parameter = 0.
                    if(!contact.IsStarContact && contact.Expires != 0 && expires < m_pProxy.Stack.MinimumExpireTime){
                        // RFC 3261 20.23 must add Min-Expires
                        SIP_Response sipExpiresResponse = request.CreateResponse(SIP_ResponseCodes.Interval_Too_Brief);

                        // The response SHOULD include a Date header field.
                        sipExpiresResponse.Header.Add("Date:",DateTime.Now.ToString("r"));

                        // Send response
                        m_pProxy.Stack.TransportLayer.SendResponse(socket,sipExpiresResponse);
                        return;
                    }
                    //---------------------------------------------------------------------------
                }

                // We have STAR contact. Check that STAR contact meets all RFC rules.
                if(starContact != null){
                    // We may have only 1 STAR Contact and expires must be 0.
                    if(contacts.Length > 1 || starContact.Expires != 0){
                        m_pProxy.Stack.TransportLayer.SendResponse(socket,request.CreateResponse(SIP_ResponseCodes.Bad_Request + ". Invalid STAR Contact: combination or parameter. For more info see RFC 3261 10.3.6."));
                        return;
                    }
                    // We have valid STAR Contact:.
                    //else{
                    //}
                }
            }

            // Add or get SIP registration
            SIP_Registration registration = null;
            lock(m_pRegistrations){
                if(!m_pRegistrations.Contains(registrationName)){
                    // Add SIP registration.
                    registration = new SIP_Registration(auth.UserName,registrationName);
                    m_pRegistrations.Add(registration);
                }
                // Update SIP registration contacts
                else{
                    registration = m_pRegistrations[registrationName];
                }
            }

            // Update registration contacts
            registration.UpdateContacts(contacts,request.Expires);
            //--------------------------------------------------------------------

            // 8. --- Make and send SIP respone ----------------------------------
            SIP_Response sipResponse = request.CreateResponse(SIP_ResponseCodes.Ok);

            // The response SHOULD include a Date header field.
            sipResponse.Date = DateTime.Now;

            // List Registered Contacts
            sipResponse.Header.RemoveAll("Contact:");
            foreach(SIP_RegistrationContact contact in registration.Contacts){
                sipResponse.Header.Add("Contact:",contact.Contact.ToStringValue());
            }

            // Add Authentication-Info:, then client knows next nonce.
            sipResponse.AuthenticationInfo.Add("qop=\"auth\",nextnonce=\"" + m_pProxy.Stack.DigestNonceManager.CreateNonce() + "\"");

            // Send response
            m_pProxy.Stack.TransportLayer.SendResponse(socket,sipResponse);
            //-----------------------------------------------------------------------
        }
        /// <summary>
        /// Creates authorization for each challange in <b>response</b>.
        /// </summary>
        /// <param name="request">SIP request where to add authorization values.</param>
        /// <param name="response">SIP response which challanges to authorize.</param>
        /// <param name="credentials">Credentials for authorization.</param>
        /// <returns>Returns true if all challanges were authorized. If any of the challanges was not authorized, returns false.</returns>
        private bool Authorize(SIP_Request request,SIP_Response response,NetworkCredential[] credentials)
        {
            if(request == null){
                throw new ArgumentNullException("request");
            }
            if(response == null){
                throw new ArgumentNullException("response");
            }
            if(credentials == null){
                throw new ArgumentNullException("credentials");
            }

            bool allAuthorized = true;

            #region WWWAuthenticate

            foreach(SIP_t_Challenge challange in response.WWWAuthenticate.GetAllValues()){
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach(NetworkCredential c in credentials){
                    if(c.Domain.ToLower() == authDigest.Realm.ToLower()){
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if(credential == null){
                    allAuthorized = false;
                }
                // Authorize challange.
                else{
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce   = Auth_HttpDigest.CreateNonce();
                    authDigest.Uri      = request.RequestLine.Uri.ToString();

                    request.Authorization.Add(authDigest.ToAuthorization());
                }
            }

            #endregion

            #region ProxyAuthenticate

            foreach(SIP_t_Challenge challange in response.ProxyAuthenticate.GetAllValues()){
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach(NetworkCredential c in credentials){
                    if(c.Domain.ToLower() == authDigest.Realm.ToLower()){
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if(credential == null){
                    allAuthorized = false;
                }
                // Authorize challange.
                else{
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce   = Auth_HttpDigest.CreateNonce();
                    authDigest.Uri      = request.RequestLine.Uri.ToString();

                    request.ProxyAuthorization.Add(authDigest.ToAuthorization());                    
                }
            }

            #endregion

            return allAuthorized;
        }
Beispiel #13
0
        /// <summary>
        /// Authenticates SIP request. This method also sends all needed replys to request sender.
        /// </summary>
        /// <param name="e">Request event arguments.</param>
        /// <param name="userName">If authentication sucessful, then authenticated user name is stored to this variable.</param>
        /// <returns>Returns true if request was authenticated.</returns>
        internal bool AuthenticateRequest(SIP_RequestReceivedEventArgs e,out string userName)
        {            
            userName = null;
         
            SIP_t_Credentials credentials = SIP_Utils.GetCredentials(e.Request,m_pStack.Realm);
            // No credentials for our realm.
            if(credentials == null){
                SIP_Response notAuthenticatedResponse = m_pStack.CreateResponse(SIP_ResponseCodes.x407_Proxy_Authentication_Required,e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(new Auth_HttpDigest(m_pStack.Realm,m_pStack.DigestNonceManager.CreateNonce(),m_Opaque).ToChallange());
                    
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }
                                       
            Auth_HttpDigest auth = new Auth_HttpDigest(credentials.AuthData,e.Request.RequestLine.Method);
            // Check opaque validity.
            if(auth.Opaque != m_Opaque){
                SIP_Response notAuthenticatedResponse = m_pStack.CreateResponse(SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Opaque value won't match !",e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(new Auth_HttpDigest(m_pStack.Realm,m_pStack.DigestNonceManager.CreateNonce(),m_Opaque).ToChallange());

                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }
            // Check nonce validity.
            if(!m_pStack.DigestNonceManager.NonceExists(auth.Nonce)){
                SIP_Response notAuthenticatedResponse = m_pStack.CreateResponse(SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Invalid nonce value !",e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(new Auth_HttpDigest(m_pStack.Realm,m_pStack.DigestNonceManager.CreateNonce(),m_Opaque).ToChallange());

                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }
            // Valid nonce, consume it so that nonce can't be used any more. 
            else{
                m_pStack.DigestNonceManager.RemoveNonce(auth.Nonce);
            }

            SIP_AuthenticateEventArgs eArgs = this.OnAuthenticate(auth);
            // Authenticate failed.
            if(!eArgs.Authenticated){
                SIP_Response notAuthenticatedResponse = m_pStack.CreateResponse(SIP_ResponseCodes.x407_Proxy_Authentication_Required + ": Authentication failed.",e.Request);
                notAuthenticatedResponse.ProxyAuthenticate.Add(new Auth_HttpDigest(m_pStack.Realm,m_pStack.DigestNonceManager.CreateNonce(),m_Opaque).ToChallange());
                    
                // Send response
                e.ServerTransaction.SendResponse(notAuthenticatedResponse);
                return false;
            }

            userName = auth.UserName;

            return true;
        }
Beispiel #14
0
        /// <summary>
        /// Is called by SIP proxy or registrar server when it needs to authenticate user.
        /// </summary>
        /// <param name="auth">Authentication context.</param>
        /// <returns></returns>
        internal SIP_AuthenticateEventArgs OnAuthenticate(Auth_HttpDigest auth)
        {
            SIP_AuthenticateEventArgs eArgs = new SIP_AuthenticateEventArgs(auth);
            if(this.Authenticate != null){
                this.Authenticate(eArgs);
            }

            return eArgs;
        }