Example #1
0
        /// <summary>
        /// Authenticate request at Active Directory Domain with user-name and password
        /// </summary>
        private PacketCode ProcessActiveDirectoryAuthentication(PendingRequest request)
        {
            var userName = request.RequestPacket.UserName;
            var password = request.RequestPacket.UserPassword;

            if (string.IsNullOrEmpty(userName))
            {
                _logger.Warning($"Can't find User-Name in message Id={request.RequestPacket.Identifier} from {request.RemoteEndpoint}");
                return(PacketCode.AccessReject);
            }

            if (string.IsNullOrEmpty(password))
            {
                _logger.Warning($"Can't find User-Password in message Id={request.RequestPacket.Identifier} from {request.RemoteEndpoint}");
                return(PacketCode.AccessReject);
            }

            var isActiveDirectory = _configuration.FirstFactorAuthenticationSource == AuthenticationSource.ActiveDirectory;

            var ldapService = isActiveDirectory ?
                              _activeDirectoryService :
                              _ldapService;

            var isValid = ldapService.VerifyCredential(userName, password, request);

            return(isValid ? PacketCode.AccessAccept : PacketCode.AccessReject);
        }
Example #2
0
 /// <summary>
 /// Add authenticated request to local cache for otp/challenge
 /// </summary>
 private void AddStateChallengePendingRequest(string state, PendingRequest request)
 {
     if (!_stateChallengePendingRequests.TryAdd(state, request))
     {
         _logger.Error("Unable to cache request id={id}", request.RequestPacket.Identifier);
     }
 }
        private void RouterRequestProcessed(object sender, PendingRequest request)
        {
            if (request.ResponsePacket?.IsEapMessageChallenge == true)
            {
                //EAP authentication in process, just proxy response
                _logger.Debug($"Proxying EAP-Message Challenge to {request.RemoteEndpoint} Id={request.RequestPacket.Identifier}");
                Send(request.ResponsePacket, request.RemoteEndpoint);

                return; //stop processing
            }

            var requestPacket  = request.RequestPacket;
            var responsePacket = requestPacket.CreateResponsePacket(request.ResponseCode);

            if (request.ResponseCode == PacketCode.AccessAccept)
            {
                if (request.ResponsePacket != null) //copy from remote radius reply
                {
                    request.ResponsePacket.CopyTo(responsePacket);
                }
            }

            //proxy echo required
            if (requestPacket.Attributes.ContainsKey("Proxy-State"))
            {
                if (!responsePacket.Attributes.ContainsKey("Proxy-State"))
                {
                    responsePacket.Attributes.Add("Proxy-State", requestPacket.Attributes.SingleOrDefault(o => o.Key == "Proxy-State").Value);
                }
            }

            if (request.ResponseCode == PacketCode.AccessChallenge)
            {
                responsePacket.AddAttribute("Reply-Message", request.ReplyMessage ?? "Enter OTP code: ");
                responsePacket.AddAttribute("State", request.State); //state to match user authentication session
            }

            //add custom reply attributes
            if (request.ResponseCode == PacketCode.AccessAccept)
            {
                foreach (var attr in _configuration.RadiusReplyAttributes)
                {
                    //check condition
                    var matched = attr.Value.Where(val => val.IsMatch(request)).Select(val => val.Value);
                    if (matched.Any())
                    {
                        responsePacket.Attributes.Add(attr.Key, matched.ToList());
                    }
                }
            }

            Send(responsePacket, request.RemoteEndpoint);

            //request processed, clear all
            //GC.Collect();
        }
        public object[] GetValues(PendingRequest request)
        {
            if (IsMemberOf)
            {
                return(request.UserGroups.ToArray());
            }

            if (FromLdap)
            {
                return(new object[] { request.LdapAttrs[LdapAttributeName] });
            }

            return(new object[] { Value });
        }
Example #5
0
        /// <summary>
        /// Authenticate request at MultiFactor with user-name only
        /// </summary>
        private PacketCode ProcessSecondAuthenticationFactor(PendingRequest request)
        {
            var userName = request.RequestPacket.UserName;

            if (string.IsNullOrEmpty(userName))
            {
                _logger.Warning($"Can't find User-Name in message Id={request.RequestPacket.Identifier} from {request.RemoteEndpoint}");
                return(PacketCode.AccessReject);
            }

            var response = _multifactorApiClient.CreateSecondFactorRequest(request);

            return(response);
        }
Example #6
0
        /// <summary>
        /// Authenticate request at LDAP/Active Directory Domain with user-name and password
        /// </summary>
        private async Task <PacketCode> ProcessLdapAuthentication(PendingRequest request, ClientConfiguration clientConfig)
        {
            var userName = request.RequestPacket.UserName;
            var password = request.RequestPacket.UserPassword;

            if (string.IsNullOrEmpty(userName))
            {
                _logger.Warning("Can't find User-Name in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                return(PacketCode.AccessReject);
            }

            if (string.IsNullOrEmpty(password))
            {
                _logger.Warning("Can't find User-Password in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                return(PacketCode.AccessReject);
            }

            LdapService _service;

            switch (clientConfig.FirstFactorAuthenticationSource)
            {
            case AuthenticationSource.ActiveDirectory:
                _service = new ActiveDirectoryService(_serviceConfiguration, _logger);
                break;

            case AuthenticationSource.Ldap:
                _service = new LdapService(_serviceConfiguration, _logger);
                break;

            default:
                throw new NotImplementedException(clientConfig.FirstFactorAuthenticationSource.ToString());
            }

            //check all hosts
            var ldapUriList = clientConfig.ActiveDirectoryDomain.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            foreach (var ldapUri in ldapUriList)
            {
                var isValid = await _service.VerifyCredential(userName, password, ldapUri, request, clientConfig);

                if (isValid)
                {
                    return(PacketCode.AccessAccept);
                }
            }

            return(PacketCode.AccessReject);
        }
        /// <summary>
        /// Is match condition
        /// </summary>
        public bool IsMatch(PendingRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            //if exist ldap attr value
            if (FromLdap)
            {
                //if list of all groups
                if (IsMemberOf)
                {
                    return(request.UserGroups?.Count > 0);
                }

                //just attribute
                return(request.LdapAttrs?[LdapAttributeName] != null);
            }

            //if matched user name condition
            if (!string.IsNullOrEmpty(UserNameCondition))
            {
                var userName    = request.RequestPacket.UserName;
                var isCanonical = Utils.IsCanicalUserName(UserNameCondition);
                if (isCanonical)
                {
                    userName = Utils.CanonicalizeUserName(userName);
                }

                return(string.Compare(userName, UserNameCondition, StringComparison.InvariantCultureIgnoreCase) == 0);
            }

            //if matched user group condition
            if (!string.IsNullOrEmpty(UserGroupCondition))
            {
                var isInGroup = request
                                .UserGroups
                                .Any(g => string.Compare(g, UserGroupCondition, StringComparison.InvariantCultureIgnoreCase) == 0);

                return(isInGroup);
            }

            return(true); //without conditions
        }
Example #8
0
        private async Task <PacketCode> ProcessFirstAuthenticationFactor(PendingRequest request, ClientConfiguration clientConfig)
        {
            switch (clientConfig.FirstFactorAuthenticationSource)
            {
            case AuthenticationSource.ActiveDirectory:      //AD auth
            case AuthenticationSource.Ldap:                 //LDAP auth
                return(await ProcessLdapAuthentication(request, clientConfig));

            case AuthenticationSource.Radius:               //RADIUS auth
                return(await ProcessRadiusAuthentication(request, clientConfig));

            case AuthenticationSource.None:
                return(PacketCode.AccessAccept);            //first factor not required

            default:                                        //unknown source
                throw new NotImplementedException(clientConfig.FirstFactorAuthenticationSource.ToString());
            }
        }
Example #9
0
        private PacketCode ProcessFirstAuthenticationFactor(PendingRequest request)
        {
            switch (_configuration.FirstFactorAuthenticationSource)
            {
            case AuthenticationSource.ActiveDirectory:      //AD auth
            case AuthenticationSource.Ldap:                 //LDAP auth
                return(ProcessActiveDirectoryAuthentication(request));

            case AuthenticationSource.Radius:               //RADIUS auth
                return(ProcessRadiusAuthentication(request));

            case AuthenticationSource.None:
                return(PacketCode.AccessAccept);            //first factor not required

            default:                                        //unknown source
                throw new NotImplementedException(_configuration.FirstFactorAuthenticationSource.ToString());
            }
        }
        /// <summary>
        /// Parses a packet and gets a response packet from the handler
        /// </summary>
        internal void ParseAndProcess(byte[] packetBytes, IPEndPoint remoteEndpoint)
        {
            var requestPacket = _radiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes(_configuration.RadiusSharedSecret));

            _logger.Debug($"Received {requestPacket.Code} from {remoteEndpoint} Id={requestPacket.Identifier}");

            if (_cacheService.IsRetransmission(requestPacket, remoteEndpoint))
            {
                _logger.Debug($"Retransmissed request from {remoteEndpoint} Id={requestPacket.Identifier}, ignoring");
                return;
            }

            var request = new PendingRequest {
                RemoteEndpoint = remoteEndpoint, RequestPacket = requestPacket
            };

            Task.Run(() => _router.HandleRequest(request));
        }
        /// <summary>
        /// Is match condition
        /// </summary>
        public bool IsMatch(PendingRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (string.IsNullOrEmpty(UserGroupCondition))
            {
                return(true); //always on
            }

            var isInGroup = request
                            .UserGroups
                            .Any(g => string.Compare(g, UserGroupCondition, StringComparison.InvariantCultureIgnoreCase) == 0);

            return(isInGroup);
        }
Example #12
0
        /// <summary>
        /// Authenticate request at Network Policy Server with user-name and password
        /// </summary>
        private PacketCode ProcessRadiusAuthentication(PendingRequest request)
        {
            try
            {
                //sending request as is to Network Policy Server
                using (var client = new RadiusClient(_configuration.ServiceClientEndpoint, _logger))
                {
                    _logger.Debug($"Sending Access-Request message with Id={request.RequestPacket.Identifier} to Network Policy Server {_configuration.NpsServerEndpoint}");

                    var requestBytes = _packetParser.GetBytes(request.RequestPacket);
                    var response     = client.SendPacketAsync(request.RequestPacket.Identifier, requestBytes, _configuration.NpsServerEndpoint, TimeSpan.FromSeconds(5)).Result;

                    if (response != null)
                    {
                        var responsePacket = _packetParser.Parse(response, request.RequestPacket.SharedSecret, request.RequestPacket.Authenticator);
                        _logger.Debug($"Received {responsePacket.Code} message with Id={responsePacket.Identifier} from Network Policy Server");

                        if (responsePacket.Code == PacketCode.AccessAccept)
                        {
                            var userName = request.RequestPacket.UserName;
                            _logger.Information($"User '{userName}' credential and status verified successfully at {_configuration.NpsServerEndpoint}");
                        }

                        request.ResponsePacket = responsePacket;
                        return(responsePacket.Code); //Code received from NPS
                    }
                    else
                    {
                        _logger.Warning($"Network Policy Server did not respond on message with Id={request.RequestPacket.Identifier}");
                        return(PacketCode.AccessReject); //reject by default
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Radius authentication error");
            }

            return(PacketCode.AccessReject); //reject by default
        }
Example #13
0
        /// <summary>
        /// Authenticate request at Remote Radius Server with user-name and password
        /// </summary>
        private async Task <PacketCode> ProcessRadiusAuthentication(PendingRequest request, ClientConfiguration clientConfig)
        {
            try
            {
                //sending request as is to Remote Radius Server
                using (var client = new RadiusClient(clientConfig.ServiceClientEndpoint, _logger))
                {
                    _logger.Debug($"Sending AccessRequest message with id={{id}} to Remote Radius Server {clientConfig.NpsServerEndpoint}", request.RequestPacket.Identifier);

                    var requestBytes = _packetParser.GetBytes(request.RequestPacket);
                    var response     = await client.SendPacketAsync(request.RequestPacket.Identifier, requestBytes, clientConfig.NpsServerEndpoint, TimeSpan.FromSeconds(5));

                    if (response != null)
                    {
                        var responsePacket = _packetParser.Parse(response, request.RequestPacket.SharedSecret, request.RequestPacket.Authenticator);
                        _logger.Debug("Received {code:l} message with id={id} from Remote Radius Server", responsePacket.Code.ToString(), responsePacket.Identifier);

                        if (responsePacket.Code == PacketCode.AccessAccept)
                        {
                            var userName = request.RequestPacket.UserName;
                            _logger.Information($"User '{{user:l}}' credential and status verified successfully at {clientConfig.NpsServerEndpoint}", userName);
                        }

                        request.ResponsePacket = responsePacket;
                        return(responsePacket.Code); //Code received from remote radius
                    }
                    else
                    {
                        _logger.Warning("Remote Radius Server did not respond on message with id={id}", request.RequestPacket.Identifier);
                        return(PacketCode.AccessReject); //reject by default
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Radius authentication error");
            }

            return(PacketCode.AccessReject); //reject by default
        }
Example #14
0
        /// <summary>
        /// Authenticate request at MultiFactor with user-name only
        /// </summary>
        private async Task <PacketCode> ProcessSecondAuthenticationFactor(PendingRequest request, ClientConfiguration clientConfig)
        {
            var userName = request.RequestPacket.UserName;

            if (string.IsNullOrEmpty(userName))
            {
                _logger.Warning("Can't find User-Name in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                return(PacketCode.AccessReject);
            }

            if (request.RequestPacket.IsVendorAclRequest == true)
            {
                //security check
                if (clientConfig.FirstFactorAuthenticationSource == AuthenticationSource.Radius)
                {
                    _logger.Information("Bypass second factor for user {user:l}", userName);
                    return(PacketCode.AccessAccept);
                }
            }

            var response = await _multifactorApiClient.CreateSecondFactorRequest(request, clientConfig);

            return(response);
        }
Example #15
0
        /// <summary>
        /// Verify one time password from user input
        /// </summary>
        private async Task <PacketCode> ProcessChallenge(PendingRequest request, ClientConfiguration clientConfig, string state)
        {
            var userName = request.RequestPacket.UserName;

            if (string.IsNullOrEmpty(userName))
            {
                _logger.Warning("Can't find User-Name in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                return(PacketCode.AccessReject);
            }

            PacketCode response;
            string     userAnswer;

            switch (request.RequestPacket.AuthenticationType)
            {
            case AuthenticationType.PAP:
                //user-password attribute holds second request challenge from user
                userAnswer = request.RequestPacket.GetString("User-Password");

                if (string.IsNullOrEmpty(userAnswer))
                {
                    _logger.Warning("Can't find User-Password with user response in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                    return(PacketCode.AccessReject);
                }

                break;

            case AuthenticationType.MSCHAP2:
                var msChapResponse = request.RequestPacket.GetAttribute <byte[]>("MS-CHAP2-Response");

                if (msChapResponse == null)
                {
                    _logger.Warning("Can't find MS-CHAP2-Response in message id={id} from {host:l}:{port}", request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                    return(PacketCode.AccessReject);
                }

                //forti behaviour
                var otpData = msChapResponse.Skip(2).Take(6).ToArray();
                userAnswer = Encoding.ASCII.GetString(otpData);

                break;

            default:
                _logger.Warning("Unable to process {auth} challange in message id={id} from {host:l}:{port}", request.RequestPacket.AuthenticationType, request.RequestPacket.Identifier, request.RemoteEndpoint.Address, request.RemoteEndpoint.Port);
                return(PacketCode.AccessReject);
            }

            response = await _multifactorApiClient.Challenge(request, clientConfig, userName, userAnswer, state);

            switch (response)
            {
            case PacketCode.AccessAccept:
                var stateChallengePendingRequest = GetStateChallengeRequest(state);
                if (stateChallengePendingRequest != null)
                {
                    request.UserGroups     = stateChallengePendingRequest.UserGroups;
                    request.ResponsePacket = stateChallengePendingRequest.ResponsePacket;
                    request.LdapAttrs      = stateChallengePendingRequest.LdapAttrs;
                }
                break;

            case PacketCode.AccessReject:
                RemoveStateChallengeRequest(state);
                break;
            }

            return(response);
        }
Example #16
0
        private void RouterRequestProcessed(object sender, PendingRequest request)
        {
            if (request.ResponsePacket?.IsEapMessageChallenge == true)
            {
                //EAP authentication in process, just proxy response
                _logger.Debug("Proxying EAP-Message Challenge to {host:l}:{port} id={id}", request.RemoteEndpoint.Address, request.RemoteEndpoint.Port, request.RequestPacket.Identifier);
                Send(request.ResponsePacket, request.RequestPacket?.UserName, request.RemoteEndpoint, request.ProxyEndpoint, true);

                return; //stop processing
            }

            if (request.RequestPacket.IsVendorAclRequest == true && request.ResponsePacket != null)
            {
                //ACL and other rules transfer, just proxy response
                _logger.Debug("Proxying #ACSACL# to {host:l}:{port} id={id}", request.RemoteEndpoint.Address, request.RemoteEndpoint.Port, request.RequestPacket.Identifier);
                Send(request.ResponsePacket, request.RequestPacket?.UserName, request.RemoteEndpoint, request.ProxyEndpoint, true);

                return; //stop processing
            }

            var requestPacket  = request.RequestPacket;
            var responsePacket = requestPacket.CreateResponsePacket(request.ResponseCode);

            switch (request.ResponseCode)
            {
            case PacketCode.AccessAccept:
                if (request.ResponsePacket != null)     //copy from remote radius reply
                {
                    request.ResponsePacket.CopyTo(responsePacket);
                }
                if (request.RequestPacket.Code == PacketCode.StatusServer)
                {
                    responsePacket.AddAttribute("Reply-Message", request.ReplyMessage);
                }

                var clientConfiguration = _serviceConfiguration.GetClient(request);
                //add custom reply attributes
                if (request.ResponseCode == PacketCode.AccessAccept)
                {
                    foreach (var attr in clientConfiguration.RadiusReplyAttributes)
                    {
                        //check condition
                        var matched = attr.Value.Where(val => val.IsMatch(request)).SelectMany(val => val.GetValues(request));
                        if (matched.Any())
                        {
                            var convertedValues = new List <object>();
                            foreach (var val in matched.ToList())
                            {
                                _logger.Debug("Added attribute '{attrname:l}:{attrval:l}' to reply", attr.Key, val);
                                convertedValues.Add(ConvertType(attr.Key, val));
                            }
                            responsePacket.Attributes.Add(attr.Key, convertedValues);
                        }
                    }
                }

                break;

            case PacketCode.AccessChallenge:
                responsePacket.AddAttribute("Reply-Message", request.ReplyMessage ?? "Enter OTP code: ");
                responsePacket.AddAttribute("State", request.State);     //state to match user authentication session

                break;

            case PacketCode.AccessReject:
                if (request.ResponsePacket != null)                             //copy from remote radius reply
                {
                    if (request.ResponsePacket.Code == PacketCode.AccessReject) //for mschap pwd change only
                    {
                        request.ResponsePacket.CopyTo(responsePacket);
                    }
                }
                break;

            default:
                throw new NotImplementedException(request.ResponseCode.ToString());
            }


            //proxy echo required
            if (requestPacket.Attributes.ContainsKey("Proxy-State"))
            {
                if (!responsePacket.Attributes.ContainsKey("Proxy-State"))
                {
                    responsePacket.Attributes.Add("Proxy-State", requestPacket.Attributes.SingleOrDefault(o => o.Key == "Proxy-State").Value);
                }
            }

            var debugLog = request.RequestPacket.Code == PacketCode.StatusServer;

            Send(responsePacket, request.RequestPacket?.UserName, request.RemoteEndpoint, request.ProxyEndpoint, debugLog);

            //request processed, clear all
            //GC.Collect();
        }
Example #17
0
        public void HandleRequest(PendingRequest request)
        {
            try
            {
                if (request.RequestPacket.Code != PacketCode.AccessRequest)
                {
                    _logger.Warning($"Unprocessable packet type: {request.RequestPacket.Code}");
                    return;
                }

                if (request.RequestPacket.Attributes.ContainsKey("State")) //Access-Challenge response
                {
                    var receivedState = request.RequestPacket.GetString("State");

                    if (_stateChallengePendingRequests.ContainsKey(receivedState))
                    {
                        //second request with Multifactor challenge
                        request.ResponseCode = ProcessChallenge(request, receivedState);
                        request.State        = receivedState; //state for Access-Challenge message if otp is wrong (3 times allowed)

                        RequestProcessed?.Invoke(this, request);
                        return; //stop authentication process after otp code verification
                    }
                }

                var firstFactorAuthenticationResultCode = ProcessFirstAuthenticationFactor(request);
                if (firstFactorAuthenticationResultCode != PacketCode.AccessAccept)
                {
                    //first factor authentication rejected
                    request.ResponseCode = firstFactorAuthenticationResultCode;
                    RequestProcessed?.Invoke(this, request);

                    //stop authencation process
                    return;
                }

                if (request.Bypass2Fa)
                {
                    //second factor not trquired
                    var userName = request.RequestPacket.UserName;
                    _logger.Information($"Bypass second factor for user {userName}");

                    request.ResponseCode = PacketCode.AccessAccept;
                    RequestProcessed?.Invoke(this, request);

                    //stop authencation process
                    return;
                }

                var secondFactorAuthenticationResultCode = ProcessSecondAuthenticationFactor(request);

                request.ResponseCode = secondFactorAuthenticationResultCode;

                if (request.ResponseCode == PacketCode.AccessChallenge)
                {
                    AddStateChallengePendingRequest(request.State, request);
                }

                RequestProcessed?.Invoke(this, request);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "HandleRequest");
            }
        }
Example #18
0
        public async Task HandleRequest(PendingRequest request, ClientConfiguration clientConfig)
        {
            try
            {
                if (request.RequestPacket.Code == PacketCode.StatusServer)
                {
                    //status
                    var uptime = (DateTime.Now - _startedAt);
                    request.ReplyMessage = $"Server up {uptime.Days} days {uptime.ToString("hh\\:mm\\:ss")}";
                    request.ResponseCode = PacketCode.AccessAccept;
                    RequestProcessed?.Invoke(this, request);
                    return;
                }

                if (request.RequestPacket.Code != PacketCode.AccessRequest)
                {
                    _logger.Warning("Unprocessable packet type: {code}", request.RequestPacket.Code);
                    return;
                }

                if (request.RequestPacket.Attributes.ContainsKey("State")) //Access-Challenge response
                {
                    var receivedState = request.RequestPacket.GetString("State");

                    if (_stateChallengePendingRequests.ContainsKey(receivedState))
                    {
                        //second request with Multifactor challenge
                        request.ResponseCode = await ProcessChallenge(request, clientConfig, receivedState);

                        request.State = receivedState;  //state for Access-Challenge message if otp is wrong (3 times allowed)

                        RequestProcessed?.Invoke(this, request);
                        return; //stop authentication process after otp code verification
                    }
                }

                var firstFactorAuthenticationResultCode = await ProcessFirstAuthenticationFactor(request, clientConfig);

                if (firstFactorAuthenticationResultCode != PacketCode.AccessAccept)
                {
                    //first factor authentication rejected
                    request.ResponseCode = firstFactorAuthenticationResultCode;
                    RequestProcessed?.Invoke(this, request);

                    //stop authencation process
                    return;
                }

                if (request.Bypass2Fa)
                {
                    //second factor not trquired
                    var userName = request.RequestPacket.UserName;
                    _logger.Information("Bypass second factor for user '{user:l}'", userName);

                    request.ResponseCode = PacketCode.AccessAccept;
                    RequestProcessed?.Invoke(this, request);

                    //stop authencation process
                    return;
                }

                var secondFactorAuthenticationResultCode = await ProcessSecondAuthenticationFactor(request, clientConfig);

                request.ResponseCode = secondFactorAuthenticationResultCode;

                if (request.ResponseCode == PacketCode.AccessChallenge)
                {
                    AddStateChallengePendingRequest(request.State, request);
                }

                RequestProcessed?.Invoke(this, request);
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "HandleRequest");
            }
        }
Example #19
0
        /// <summary>
        /// Parses a packet and gets a response packet from the handler
        /// </summary>
        internal void ParseAndProcess(byte[] packetBytes, IPEndPoint remoteEndpoint)
        {
            IPEndPoint proxyEndpoint = null;

            if (IsProxyProtocol(packetBytes, out var sourceEndpoint, out var requestWithoutProxyHeader))
            {
                packetBytes    = requestWithoutProxyHeader;
                proxyEndpoint  = remoteEndpoint;
                remoteEndpoint = sourceEndpoint;
            }

            ClientConfiguration clientConfiguration = null;

            if (RadiusPacketNasIdentifierParser.TryParse(packetBytes, out var nasIdentifier))
            {
                clientConfiguration = _serviceConfiguration.GetClient(nasIdentifier);
            }
            if (clientConfiguration == null)
            {
                clientConfiguration = _serviceConfiguration.GetClient(remoteEndpoint.Address);
            }

            if (clientConfiguration == null)
            {
                _logger.Warning("Received packet from unknown client {host:l}:{port}, ignoring", remoteEndpoint.Address, remoteEndpoint.Port);
                return;
            }

            var requestPacket    = _radiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes(clientConfiguration.RadiusSharedSecret));
            var isRetransmission = _cacheService.IsRetransmission(requestPacket, remoteEndpoint);

            if (isRetransmission)
            {
                _logger.Debug("Retransmissed request from {host:l}:{port} id={id} client '{client:l}', ignoring", remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name);
                return;
            }

            if (proxyEndpoint != null)
            {
                if (requestPacket.Code == PacketCode.StatusServer)
                {
                    _logger.Information("Received {code:l} from {host:l}:{port} proxied by {proxyhost:l}:{proxyport} id={id} client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name);
                }
                else
                {
                    _logger.Information("Received {code:l} from {host:l}:{port} proxied by {proxyhost:l}:{proxyport} id={id} user='******' client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, requestPacket.Identifier, requestPacket.UserName, clientConfiguration.Name);
                }
            }
            else
            {
                if (requestPacket.Code == PacketCode.StatusServer)
                {
                    _logger.Debug("Received {code:l} from {host:l}:{port} id={id} client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name);
                }
                else
                {
                    _logger.Information("Received {code:l} from {host:l}:{port} id={id} user='******' client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, requestPacket.UserName, clientConfiguration.Name);
                }
            }


            var request = new PendingRequest {
                RemoteEndpoint = remoteEndpoint, ProxyEndpoint = proxyEndpoint, RequestPacket = requestPacket
            };

            Task.Run(async() => await _router.HandleRequest(request, clientConfiguration));
        }