2019-06-14 16:14:24 +00:00
/ *
*
* ( c ) Copyright Ascensio System Limited 2010 - 2018
*
* This program is freeware . You can redistribute it and / or modify it under the terms of the GNU
* General Public License ( GPL ) version 3 as published by the Free Software Foundation ( https : //www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7 ( a ) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non - infringement of any third - party rights .
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY ; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE . For more details , see GNU GPL at https : //www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales @onlyoffice . com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices , as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3 ( b ) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software . If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons , you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute .
* Pursuant to Section 7 § 3 ( e ) we decline to grant you any rights under trademark law for use of our trademarks .
*
* /
using System ;
using System.Linq ;
using System.Net ;
using System.Web ;
2020-02-17 08:58:14 +00:00
using ASC.Common ;
2019-06-14 16:14:24 +00:00
using ASC.Common.Logging ;
using ASC.Core ;
2019-11-08 12:21:51 +00:00
using ASC.Core.Common.Settings ;
2020-02-17 08:58:14 +00:00
2019-07-02 15:30:31 +00:00
using Microsoft.AspNetCore.Http ;
2019-06-14 16:14:24 +00:00
using Microsoft.AspNetCore.Http.Extensions ;
2019-09-20 15:08:45 +00:00
using Microsoft.Extensions.Configuration ;
2019-10-17 15:55:35 +00:00
using Microsoft.Extensions.Options ;
2019-06-14 16:14:24 +00:00
namespace ASC.IPSecurity
{
2020-10-19 15:53:15 +00:00
[Scope]
2019-09-20 15:08:45 +00:00
public class IPSecurity
2019-06-14 16:14:24 +00:00
{
2019-10-17 15:55:35 +00:00
private readonly ILog Log ;
2019-06-14 16:14:24 +00:00
2019-09-20 15:08:45 +00:00
public bool IpSecurityEnabled { get ; }
2019-06-14 16:14:24 +00:00
2020-08-12 09:58:08 +00:00
private IHttpContextAccessor HttpContextAccessor { get ; }
private AuthContext AuthContext { get ; }
private TenantManager TenantManager { get ; }
private IPRestrictionsService IPRestrictionsService { get ; }
private SettingsManager SettingsManager { get ; }
2019-09-20 15:08:45 +00:00
private readonly string CurrentIpForTest ;
2019-10-17 15:55:35 +00:00
public IPSecurity (
IConfiguration configuration ,
IHttpContextAccessor httpContextAccessor ,
AuthContext authContext ,
TenantManager tenantManager ,
IPRestrictionsService iPRestrictionsService ,
2019-11-08 12:21:51 +00:00
SettingsManager settingsManager ,
2019-11-06 15:03:09 +00:00
IOptionsMonitor < ILog > options )
2019-06-14 16:14:24 +00:00
{
2019-10-17 15:55:35 +00:00
Log = options . Get ( "ASC.IPSecurity" ) ;
2019-09-20 15:08:45 +00:00
HttpContextAccessor = httpContextAccessor ;
AuthContext = authContext ;
2019-09-20 15:53:27 +00:00
TenantManager = tenantManager ;
2019-10-10 08:52:21 +00:00
IPRestrictionsService = iPRestrictionsService ;
2019-11-08 12:21:51 +00:00
SettingsManager = settingsManager ;
2019-09-20 15:08:45 +00:00
CurrentIpForTest = configuration [ "ipsecurity:test" ] ;
var hideSettings = ( configuration [ "web:hide-settings" ] ? ? "" ) . Split ( new [ ] { ',' , ';' , ' ' } ) ;
IpSecurityEnabled = ! hideSettings . Contains ( "IpSecurity" , StringComparer . CurrentCultureIgnoreCase ) ;
2019-06-14 16:14:24 +00:00
}
2019-09-20 15:53:27 +00:00
public bool Verify ( )
2019-06-14 16:14:24 +00:00
{
2019-09-20 15:53:27 +00:00
var tenant = TenantManager . GetCurrentTenant ( ) ;
2019-11-08 12:21:51 +00:00
var settings = SettingsManager . Load < IPRestrictionsSettings > ( ) ;
2019-09-20 15:53:27 +00:00
2019-06-14 16:14:24 +00:00
if ( ! IpSecurityEnabled ) return true ;
2019-09-20 15:08:45 +00:00
if ( HttpContextAccessor ? . HttpContext = = null ) return true ;
2019-06-14 16:14:24 +00:00
2019-09-20 15:08:45 +00:00
if ( tenant = = null | | AuthContext . CurrentAccount . ID = = tenant . OwnerId ) return true ;
2019-06-14 16:14:24 +00:00
string requestIps = null ;
try
{
var restrictions = IPRestrictionsService . Get ( tenant . TenantId ) . ToList ( ) ;
2022-01-18 13:54:24 +00:00
if ( restrictions . Count = = 0 ) return true ;
2019-06-14 16:14:24 +00:00
if ( string . IsNullOrWhiteSpace ( requestIps = CurrentIpForTest ) )
{
2019-09-20 15:08:45 +00:00
var request = HttpContextAccessor . HttpContext . Request ;
2019-06-14 16:14:24 +00:00
requestIps = request . Headers [ "X-Forwarded-For" ] . FirstOrDefault ( ) ? ? request . GetUserHostAddress ( ) ;
}
var ips = string . IsNullOrWhiteSpace ( requestIps )
2022-01-19 10:24:11 +00:00
? Array . Empty < string > ( )
2019-06-14 16:14:24 +00:00
: requestIps . Split ( new [ ] { "," , " " } , StringSplitOptions . RemoveEmptyEntries ) ;
if ( ips . Any ( requestIp = > restrictions . Any ( restriction = > MatchIPs ( GetIpWithoutPort ( requestIp ) , restriction . Ip ) ) ) )
{
return true ;
}
}
catch ( Exception ex )
{
Log . ErrorFormat ( "Can't verify request with IP-address: {0}. Tenant: {1}. Error: {2} " , requestIps ? ? "" , tenant , ex ) ;
return false ;
}
2019-09-20 15:08:45 +00:00
Log . InfoFormat ( "Restricted from IP-address: {0}. Tenant: {1}. Request to: {2}" , requestIps ? ? "" , tenant , HttpContextAccessor . HttpContext . Request . GetDisplayUrl ( ) ) ;
2019-06-14 16:14:24 +00:00
return false ;
}
private static bool MatchIPs ( string requestIp , string restrictionIp )
{
var dividerIdx = restrictionIp . IndexOf ( '-' ) ;
if ( restrictionIp . IndexOf ( '-' ) > 0 )
{
var lower = IPAddress . Parse ( restrictionIp . Substring ( 0 , dividerIdx ) . Trim ( ) ) ;
var upper = IPAddress . Parse ( restrictionIp . Substring ( dividerIdx + 1 ) . Trim ( ) ) ;
var range = new IPAddressRange ( lower , upper ) ;
return range . IsInRange ( IPAddress . Parse ( requestIp ) ) ;
}
return requestIp = = restrictionIp ;
}
private static string GetIpWithoutPort ( string ip )
{
var portIdx = ip . IndexOf ( ':' ) ;
return portIdx > 0 ? ip . Substring ( 0 , portIdx ) : ip ;
}
}
}