Skip to content

Commit

Permalink
introduce a whitelist of uids exempted from ip check
Browse files Browse the repository at this point in the history
Signed-off-by: Lionel Elie Mamane <[email protected]>
  • Loading branch information
Lionel Elie Mamane committed Feb 9, 2021
1 parent aab692c commit 18707a0
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 31 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ source_dir=$(build_dir)/source
sign_dir=$(build_dir)/sign
package_name=$(app_name)
cert_dir=$(HOME)/.nextcloud/certificates
version+=1.0.2
version+=3.1.0

all: appstore

Expand Down Expand Up @@ -47,4 +47,4 @@ appstore: clean
@if [ -f $(cert_dir)/$(app_name).key ]; then \
echo "Signing package…"; \
openssl dgst -sha512 -sign $(cert_dir)/$(app_name).key $(build_dir)/$(app_name)-$(version).tar.gz | openssl base64; \
fi
fi
19 changes: 6 additions & 13 deletions appinfo/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,9 @@
$isLoginpage
);

if(!$loginHookListener->isLoginAllowed()) {
if($isLoginpage) {
header('Location: ' . \OC::$WEBROOT . '/index.php/apps/limit_login_to_ip/denied');
exit();
}

\OCP\Util::connectHook(
'OC_User',
'pre_login',
$loginHookListener,
'handleLoginRequest'
);
}
\OCP\Util::connectHook(
'OC_User',
'pre_login',
$loginHookListener,
'handleLoginRequest'
);
19 changes: 12 additions & 7 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>limit_login_to_ip</id>
<name>Restrict login to IP addresses</name>
<summary>Allows administrators to restrict logins to their instance to specific IP ranges.</summary>
<name>Restrict logins to whitelisted IP addresses or users</name>
<summary>Allows administrators to restrict logins to their instance by user or specific IP ranges.</summary>
<description><![CDATA[This app allows administrators to restrict login to their
Nextcloud server to specific IP ranges. Note that existing sessions will be kept
open.
Nextcloud server to specific IP ranges, unless the user is exempted.
Note that existing sessions will be kept open.
The allowed IP ranges can be administrated using the OCC command line interface
or graphically using the admin settings. If you plan to use the OCC tool, the
following commands would be applicable.
The allowed IP ranges and exempted users can be administrated using
the OCC command line interface or graphically using the admin
settings. If you plan to use the OCC tool, the following commands
would be applicable.
To whitelist `127.0.0.0/24`:
Expand All @@ -19,6 +20,10 @@ To whitelist `127.0.0.0/24`:
To whitelist `127.0.0.0/24` and also `192.168.0.0/24`:
- `occ config:app:set limit_login_to_ip whitelisted.ranges --value 127.0.0.0/24,192.168.0.0/24`
To whitelist `peter` and `john`:
- `occ config:app:set limit_login_to_ip whitelisted.uids --value peter,john`
]]></description>
<version>3.1.0</version>
<licence>agpl</licence>
Expand Down
26 changes: 25 additions & 1 deletion css/settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,28 @@

#limit-login-to-ip-list .action-column a {
display: inline-block;
}
}

#limit-login-to-ip-uidlist-spinner {
margin-top: 25px;
margin-bottom: 25px;
margin-left: auto;
margin-right: auto;
}

#limit-login-to-ip-uidlist {
min-width: 262px;
}

#limit-login-to-ip-uidlist td span {
padding: 10px 15px;
display: inline-block;
}

#limit-login-to-ip-uidlist .action-column {
width: 46px;
}

#limit-login-to-ip-uidlist .action-column a {
display: inline-block;
}
97 changes: 91 additions & 6 deletions js/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
(function(OCA) {
OCA.LimitLoginToIp = OCA.LimitLoginToIp || {};
OCA.LimitLoginToIp.Ranges = [];
OCA.LimitLoginToIp.UIDs = [];

/**
* @namespace OCA.LimitLoginToIp.Settings
Expand Down Expand Up @@ -58,7 +59,42 @@
actionCell.innerHTML = actionCellValue.outerHTML;
});

OCA.LimitLoginToIp.Settings.setEnabledState(true);
OCA.LimitLoginToIp.Settings.setIPEnabledState(true);
}
}
);
OCP.AppConfig.getValue(
'limit_login_to_ip',
'whitelisted.uids',
'',
{
success: function(data) {
var textData = $(data).find('data data').text();
var UIDs = textData.split(',');
var table = document.getElementById('limit-login-to-ip-uidlist');
table.innerHTML = '';

OCA.LimitLoginToIp.UIDs = UIDs;
UIDs.forEach(function(uid) {
var row = table.insertRow(0);
var actionCell = row.insertCell(0);
actionCell.className = 'action-column';
var uidCell = row.insertCell(0);

var uidCellValue = document.createElement('span');
uidCellValue.innerText = uid;
uidCell.innerHTML = uidCellValue.outerHTML;

var actionCellValue = document.createElement('span');
var deleteLink = document.createElement('a');
deleteLink.className = 'icon-delete has-tooltip';
deleteLink.title = t('limit_login_to_ip', 'Delete');
deleteLink.setAttribute('data', uid);
actionCellValue.innerHTML = deleteLink.outerHTML;
actionCell.innerHTML = actionCellValue.outerHTML;
});

OCA.LimitLoginToIp.Settings.setUIDEnabledState(true);
}
}
);
Expand Down Expand Up @@ -89,14 +125,49 @@
OCA.LimitLoginToIp.Settings.storeRanges();
},

setEnabledState: function(isEnabled) {
storeUIDs: function() {
var uids = OCA.LimitLoginToIp.UIDs.join();
OCP.AppConfig.setValue(
'limit_login_to_ip',
'whitelisted.uids',
uids,
{
success: function () {
OCA.LimitLoginToIp.Settings.load();
}
}
);
},

addUID: function(uid) {
OCA.LimitLoginToIp.UIDs.push(uid);
OCA.LimitLoginToIp.Settings.storeUIDs();
},

removeUID: function(uid) {
var index = OCA.LimitLoginToIp.UIDs.indexOf(uid);
OCA.LimitLoginToIp.UIDs.splice(index, 1);
OCA.LimitLoginToIp.Settings.storeUIDs();
},

setIPEnabledState: function(isEnabled) {
if(isEnabled !== true) {
$('#limit-login-to-ip-list-spinner').removeClass('hidden');
} else {
$('#limit-login-to-ip-list-spinner').addClass('hidden');
}

$('#limit-login-to-ip-input-fields input').prop('disabled', !isEnabled);
},

setUIDEnabledState: function(isEnabled) {
if(isEnabled !== true) {
$('#limit-login-to-ip-uidlist-spinner').removeClass('hidden');
} else {
$('#limit-login-to-ip-uidlist-spinner').addClass('hidden');
}

$('#limit-login-to-ip-uid-input-fields input').prop('disabled', !isEnabled);
}
};

Expand All @@ -108,7 +179,7 @@
$('#limit-login-to-ip-submit').click(function() {
var ipAddress = $('#limit-login-to-ip-whitelist').val();
var range = $('#limit-login-to-ip-whitelist_mask').val();

// ipAddress validation
// https://www.regexpal.com/?fam=104038
var regexFilter = '((^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$))';
Expand All @@ -118,16 +189,30 @@
if ( regexMatch == null ) {
return false;
}
OCA.LimitLoginToIp.Settings.setEnabledState(false);

OCA.LimitLoginToIp.Settings.setIPEnabledState(false);
OCA.LimitLoginToIp.Settings.addRange(ipAddress + '/' + range);
$('#limit-login-to-ip-whitelist').val('');
$('#limit-login-to-ip-whitelist_mask').val();
});

$('#limit-login-to-ip-list').on('click', 'a', function() {
var rangeToRemove = $(this).attr('data');
OCA.LimitLoginToIp.Settings.setEnabledState(false);
OCA.LimitLoginToIp.Settings.setIPEnabledState(false);
OCA.LimitLoginToIp.Settings.removeRange(rangeToRemove);
});

$('#limit-login-to-ip-uid-submit').click(function() {
var uid = $('#limit-login-to-ip-uid-whitelist').val();

OCA.LimitLoginToIp.Settings.setUIDEnabledState(false);
OCA.LimitLoginToIp.Settings.addUID(uid);
$('#limit-login-to-ip-uid-whitelist').val('');
});

$('#limit-login-to-ip-uidlist').on('click', 'a', function() {
var uidToRemove = $(this).attr('data');
OCA.LimitLoginToIp.Settings.setUIDEnabledState(false);
OCA.LimitLoginToIp.Settings.removeUID(uidToRemove);
});
})();
24 changes: 22 additions & 2 deletions lib/LoginHookListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private function matchCidr($ip, $range) {
/**
* @return bool
*/
public function isLoginAllowed() {
public function isIPWhiteListed() {
$allowedRanges = $this->config->getAppValue('limit_login_to_ip', 'whitelisted.ranges', '');
if($allowedRanges === '') {
return true;
Expand All @@ -125,7 +125,27 @@ public function isLoginAllowed() {
return false;
}

public function handleLoginRequest() {
/**
* @return bool
*/
public function isUidWhiteListed($uid) {
$allowedUids = $this->config->getAppValue('limit_login_to_ip', 'whitelisted.uids', '');
if($allowedUids === '') {
return false;
}

$allowedUids = explode(',', $allowedUids);

return in_array($uid, $allowedUids, true);
}

public function handleLoginRequest(array $params) {
if ( !$this->isUidWhiteListed($params['uid']) && !$this->isIPWhiteListed() ) {
$this->denyLoginRequest();
}
}

public function denyLoginRequest() {
// Web UI
if($this->isLoginPage) {
$url = $this->urlGenerator->linkToRouteAbsolute('limit_login_to_ip.LoginDenied.showErrorPage');
Expand Down
12 changes: 12 additions & 0 deletions templates/admin-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,16 @@
<input type="number" id="limit-login-to-ip-whitelist_mask" name="limit-login-to-ip-whitelist_mask" placeholder="24" style="width: 50px;" disabled>
<input type="button" id="limit-login-to-ip-submit" value="<?php p($l->t('Add')); ?>" disabled>
</div>

<em><?php p($l->t('These users can connect from any IP address. These are matched against the authentication username.')) ?></em>

<br/>
<img id="limit-login-to-ip-uidlist-spinner" src="<?php p(image_path('core', 'loading.gif')); ?>"/>
<table id="limit-login-to-ip-uidlist">
</table>

<div id="limit-login-to-ip-uid-input-fields">
<input type="text" name="limit-login-to-ip-uid-whitelist" id="limit-login-to-ip-uid-whitelist" placeholder="username" style="width: 200px;" disabled/>
<input type="button" id="limit-login-to-ip-uid-submit" value="<?php p($l->t('Add')); ?>" disabled>
</div>
</form>

0 comments on commit 18707a0

Please sign in to comment.