www/web-proxy-sso: Smart-Soft Proxy SSO plugin (#266)

(cherry picked from commit e2a42db535)
(cherry picked from commit 74166077c9)
(cherry picked from commit 94df25e89c)
(cherry picked from commit c75320efc2)
(cherry picked from commit 2d603f3171)
(cherry picked from commit 14e1595f4a)
This commit is contained in:
evbevz 2017-09-25 12:49:49 +04:00 committed by Franco Fichtner
parent 99426f7940
commit cad2df28cc
40 changed files with 791 additions and 734 deletions

View file

@ -1,4 +1,3 @@
Copyright (c) 2016 <gitdevmod@github.com>
Copyright (c) 2015-2016 Ad Schellevis
Copyright (c) 2005-2008 Bill Marquette <bill.marquette@gmail.com>
Copyright (c) 2005-2006 Colin Smith <ethethlay@gmail.com>
@ -21,6 +20,7 @@ Copyright (c) 2012 Pierre POMES <pierre.pomes@gmail.com>
Copyright (c) 2004-2012 Scott Ullrich <sullrich@gmail.com>
Copyright (c) 2010 Seth Mos <seth.mos@dds.nl>
Copyright (c) 2008 Shrew Soft Inc.
Copyright (c) 2017 Smart-Soft
Copyright (c) 2013 Stanley P. Miller \ stan-qaz
Copyright (c) 2004-2005 T. Lechat <dev@lechat.org>
Copyright (c) 2010 Yehuda Katz

View file

@ -60,7 +60,7 @@ security/intrusion-detection-content-pt-open -- IDS PT Research ruleset (only fo
security/tinc -- Tinc VPN
security/tor -- The Onion Router
www/c-icap -- c-icap connects your Proxy with a virus scanner
www/web-proxy-sso -- Add SSO Active Directory to use in Proxy
www/web-proxy-sso -- Kerberos authentication module
```
A brief description of how to use the plugins repository

View file

@ -0,0 +1,4 @@
rm -f /usr/local/etc/squid/pre-auth/20-negotiate.auth.conf
if [ -f /var/run/squid/squid.pid ]; then
configctl proxy reconfigure
fi

View file

@ -1,9 +1,9 @@
PLUGIN_NAME= web-proxy-sso
PLUGIN_VERSION= 0.3
PLUGIN_REVISION= 1
PLUGIN_COMMENT= Add SSO Active Directory to use in Proxy
PLUGIN_DEPENDS= msktutil
PLUGIN_MAINTAINER= gitdevmod@github.com
PLUGIN_VERSION= 1.3
PLUGIN_COMMENT= Kerberos authentication module
PLUGIN_DEPENDS= msktutil cyrus-sasl-gssapi
PLUGIN_MAINTAINER= evbevz@gmail.com
PLUGIN_WWW= https://smart-soft.ru
PLUGIN_DEVEL= yes
.include "../../Mk/plugins.mk"

View file

@ -0,0 +1,15 @@
<?php
function proxy_sso_configure()
{
return [
'webproxy' => ['proxy_sso_squid_hook:2'],
];
}
function proxy_sso_squid_hook($verbose, $action)
{
if($action == "reconfigure") {
configd_run('template reload OPNsense/ProxySSO');
}
}

View file

@ -0,0 +1,262 @@
<?php
namespace OPNsense\ProxySSO\Api;
use \OPNsense\Core\Backend;
use \OPNsense\Core\Config;
use \OPNsense\ProxySSO\ProxySSO;
class ServiceController extends \OPNsense\Proxy\Api\ServiceController
{
/**
* show Kerberos keytab for Proxy
* @return array
*/
public function showkeytabAction()
{
$backend = new Backend();
$response = $backend->configdRun("proxysso showkeytab");
return array("response" => $response,"status" => "ok");
}
/**
* delete Kerberos keytab for Proxy
* @return array
*/
public function deletekeytabAction()
{
$backend = new Backend();
$response = $backend->configdRun("proxysso deletekeytab");
return array("response" => $response,"status" => "ok");
}
/**
* create Kerberos keytab for Proxy
* @return array
*/
public function createkeytabAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$mdl = new ProxySSO();
$cnf = Config::getInstance()->toArray();
$hostname = 'HTTP/' . $cnf['system']['hostname'];
$domain = $cnf['system']['domain'];
$kerbname = substr(strtoupper($cnf['system']['hostname']), 0, 13) . "-K";
$winver = (string)$mdl->ADKerberosImplementation == 'W2008' ? '2008' : '2003';
$username = escapeshellarg($this->request->getPost("admin_login"));
$pass = escapeshellarg($this->request->getPost("admin_password"));
$response = $backend->configdRun("proxysso createkeytab {$hostname} {$domain} {$kerbname} {$winver} {$username} {$pass}");
parent::reconfigureAction();
return array("response" => $response,"status" => "ok");
}
return array("response" => array());
}
/**
* test Kerberos login
* @return array
*/
public function testkerbloginAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$cnf = Config::getInstance()->toArray();
$fqdn = $cnf['system']['hostname'].'.'.$cnf['system']['domain'];
$username = escapeshellarg($this->request->getPost("login"));
$pass = escapeshellarg($this->request->getPost("password"));
$response = $backend->configdRun("proxysso testkerblogin {$username} {$pass} {$fqdn}");
return array("response" => $response,"status" => "ok");
}
return array("response" => array());
}
/**
* get checklist data
* @return array
*/
public function getCheckListAction()
{
$backend = new Backend();
$cnf = Config::getInstance()->object();
$hostname = $cnf->system->hostname .'.'.$cnf->system->domain;
// LDAP
$methods = explode(',', $cnf->OPNsense->proxy->forward->authentication->method);
foreach($methods as $method) {
$xpath = $cnf->xpath("//system/authserver[name=\"$method\" and type=\"ldap\"]");
if(count($xpath)) {
$ldap_server = $xpath[0];
break;
}
}
$ldap_ip = null;
$ldap_fqdn = null;
$ldap_server_ping = [ "status" => "failure"];
if(isset($ldap_server) && !empty($ldap_server->host)) {
if(filter_var($ldap_server->host, FILTER_VALIDATE_IP)) {
$ldap_ip = $ldap_server->host;
}
else {
$ldap_fqdn = $ldap_server->host;
}
$host_esc = escapeshellarg("{$ldap_server->host}");
$output = array("# ping -c 1 -W 1 {$host_esc}");
$retval = 0;
exec("ping -c 1 -W 1 {$host_esc}", $output, $retval);
$ldap_server_ping = [ "status" => $retval == 0 ? "ok" : "failure"];
$ldap_server_ping["dump"] = implode("\n", $output);
}
// DNS
$dns_server = array();
$nameservers = preg_grep('/^nameserver/', file('/etc/resolv.conf'));
$dns_servers = array();
foreach($nameservers as $key => $record) {
$parts = explode(' ', $record);
$dns_servers[] = trim($parts[1]);
}
$dns_server = [ "status" => count($dns_servers) ? "ok" : "failure"];
if(!count($dns_servers)) {
$dns_server["message"] = gettext("DNS server not found");
}
$output = "# cat /etc/resolv.conf\n";
$output .= file_get_contents('/etc/resolv.conf');
$dns_server["dump"] = $output;
// DNS: hostname
$resolv_direct = chop(shell_exec("drill {$hostname} | grep -A 1 'ANSWER SECTION' | tail -n 1 | awk '{print \$5}'"));
$dns_hostname_resolution = [ "status" => !empty($resolv_direct) && filter_var($resolv_direct, FILTER_VALIDATE_IP) ? "ok" : "failure"];
$output = array("# drill {$hostname}");
exec("drill {$hostname}", $output);
$dns_hostname_resolution["dump"] = implode("\n", $output);
$resolv_reverse = null;
$dns_hostname_reverse_resolution = array();
$output = array();
if(!empty($resolv_direct) && filter_var($resolv_direct, FILTER_VALIDATE_IP)) {
$output[] = "# drill -x {$resolv_direct}";
exec("drill -x {$resolv_direct}", $output);
$resolv_reverse = chop(shell_exec("drill -x {$resolv_direct} | grep -A 1 'ANSWER SECTION' | tail -n 1 | awk '{print \$5}'"));
if(strtolower($resolv_reverse) != strtolower("{$hostname}.")) {
$dns_hostname_reverse_resolution["message"] = gettext("Hostname doesn't resolved to host IP.");
}
}
else {
$dns_hostname_reverse_resolution["message"] = gettext("Hostname doesn't resolved to IP.");
}
$dns_hostname_reverse_resolution["status"] = strtolower($resolv_reverse) == strtolower("{$hostname}.") ? "ok" : "failure";
$dns_hostname_reverse_resolution["dump"] = implode("\n", $output);
// DNS: LDAP server
ldap_dns:
$dns_ldap_reverse_resolution = array( "status" => "failure" );
if(empty($ldap_ip)) {
$dns_ldap_reverse_resolution["message"] = gettext("Unknown LDAP server IP.");
}
else {
$ldap_ip_esc = escapeshellarg($ldap_ip);
$resolv_reverse = chop(shell_exec("drill -x {$ldap_ip_esc} | grep -A 1 'ANSWER SECTION' | tail -n 1 | awk '{print \$5}'"));
if(empty($resolv_reverse)) {
$dns_ldap_reverse_resolution["message"] = gettext('LDAP server IP reverse lookup error. ');
}elseif (!empty($ldap_fqdn) && $resolv_reverse != "{$ldap_fqdn}.") {
$dns_ldap_reverse_resolution["message"] = gettext('LDAP server reverse DNS lookup is not equal to LDAP server FQDN. ');
}
else {
$dns_ldap_reverse_resolution["status"] = "ok";
$ldap_fqdn = substr($resolv_reverse, 0, strlen($resolv_reverse) - 1);
}
$output = array("# drill -x {$ldap_ip_esc}");
exec("drill -x {$ldap_ip_esc}", $output);
$dns_ldap_reverse_resolution["dump"] = implode("\n", $output);
}
$dns_ldap_resolution = array( "status" => "failure" );
if(empty($ldap_fqdn)) {
$dns_ldap_resolution["message"] = gettext('Unknown LDAP server FQDN.');
}
else {
$ldap_fqdn_esc = escapeshellarg($ldap_fqdn);
$resolv = chop(shell_exec("drill {$ldap_fqdn_esc} | grep -A 1 'ANSWER SECTION' | tail -n 1 | awk '{print \$5}'"));
if(empty($resolv)) {
$dns_ldap_resolution["message"] = gettext('LDAP server DNS lookup error. ');
}
elseif (!empty($ldap_ip) && $resolv != $ldap_ip) {
$dns_ldap_resolution["message"] = gettext('LDAP server DNS lookup is not equal to LDAP IP. ');
}
else {
$dns_ldap_resolution["status"] = "ok";
if(empty($ldap_ip)) {
$ldap_ip = $resolv;
goto ldap_dns;
}
}
$output = array("# drill {$ldap_fqdn_esc}");
exec("drill {$ldap_fqdn_esc}", $output);
$dns_ldap_resolution["dump"] = implode("\n", $output);
}
// KERBEROS
$krb5_conf = '/etc/krb5.conf';
$kerberos_config = array();
$kerberos_config["status"] = "failure";
if(!file_exists($krb5_conf)) {
$kerberos_config["message"] = sprintf(gettext('File %s does not exists.'), $krb5_conf);
}
else{
$domainstr = preg_quote($cnf->system->domain);
$config_valid = preg_grep("/$domainstr/", file($krb5_conf));
$kerberos_config["status"] = file_exists($krb5_conf) && !empty($config_valid) ? "ok" : "failure";
if (empty($config_valid)) {
$kerberos_config["message"] = gettext('SSO is not enabled or kerberos configuration file has invalid content');
}
$output = "# cat $krb5_conf\n";
$output .= file_get_contents($krb5_conf);
$kerberos_config["dump"] = $output;
}
$keytab_file = '/usr/local/etc/squid/squid.keytab';
$keytab = array();
$keytab["status"] = file_exists($keytab_file) ? "ok" : "failure";
if(!file_exists($keytab_file)) {
$keytab["message"] = sprintf(gettext('File %s does not exists.'), $keytab_file);
}
$keytab["dump"] = $backend->configdRun("proxysso showkeytab");
// and two more DNS check
if(!empty($ldap_ip) && !in_array($ldap_ip, $dns_servers)) {
$dns_server["status"] = "failure";
$dns_server["message"] = gettext("LDAP server is not in DNS servers list.");
}
elseif(in_array("127.0.0.1", $dns_servers) || in_array("::1", $dns_servers)) {
$dns_server["status"] = "failure";
$dns_server["message"] = gettext("Do not set localhost as DNS server.");
}
return [
"hostname" => $hostname,
"ldap_server_config" => isset($ldap_server) ? $ldap_server->name->__toString() : array("status" => "failure", "message" => gettext("LDAP server is not set in Web Proxy - Authentication Settings")),
"ldap_server" => isset($ldap_server) ? $ldap_server->host->__toString() : "",
"ldap_server_ping" => $ldap_server_ping,
"dns_server" => $dns_server,
"dns_hostname_resolution" => $dns_hostname_resolution,
"dns_hostname_reverse_resolution" => $dns_hostname_reverse_resolution,
"dns_ldap_resolution" => $dns_ldap_resolution,
"dns_ldap_reverse_resolution" => $dns_ldap_reverse_resolution,
"kerberos_config" => $kerberos_config,
"keytab" => $keytab,
];
}
}

View file

@ -1,7 +1,8 @@
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* Copyright (C) 2017 Smart-Soft
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -24,12 +25,20 @@
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\SSOProxyAD;
namespace OPNsense\ProxySSO\Api;
use OPNsense\Base\BaseModel;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Core\Config;
class SSOProxyAD extends BaseModel
/**
* Class SettingsController Handles settings related API actions for the ProxySSO
* @package OPNsense\ProxySSO
*/
class SettingsController extends ApiMutableModelControllerBase
{
static protected $internalModelName = "ProxySSO";
static protected $internalModelClass = "\OPNsense\ProxySSO\ProxySSO";
}

View file

@ -0,0 +1,16 @@
<?php
namespace OPNsense\ProxySSO;
class IndexController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("Web Proxy Single Sign-On");
$this->view->pick('OPNsense/ProxySSO/index');
$this->view->generalForm = $this->getForm("general");
$this->view->testingCreateForm = $this->getForm("testing_create");
$this->view->testingTestForm = $this->getForm("testing_test");
$this->view->checkListForm = $this->getForm("checklist");
}
}

View file

@ -0,0 +1,69 @@
<form>
<field>
<label>Kerberos authentication check-list</label>
<type>header</type>
</field>
<field>
<id>hostname</id>
<label>Hostname</label>
<type>info</type>
</field>
<field>
<id>ldap_server_config</id>
<label>LDAP Server configuration</label>
<type>info</type>
</field>
<field>
<id>ldap_server</id>
<label>LDAP Server</label>
<type>info</type>
</field>
<field>
<id>ldap_server_ping</id>
<label>LDAP Server accessible</label>
<type>info</type>
<help>LDAP server ping check.</help>
</field>
<field>
<id>dns_server</id>
<label>DNS Server</label>
<type>info</type>
<help>DNS server address from resolver configuration. <![CDATA[See <a href="/system_general.php">DNS settings</a>]]>.</help>
</field>
<field>
<id>dns_hostname_resolution</id>
<label>Hostname DNS lookup</label>
<type>info</type>
<help>DNS IP resolution for hostname.</help>
</field>
<field>
<id>dns_hostname_reverse_resolution</id>
<label>Hostname DNS reverse lookup</label>
<type>info</type>
<help>Reverse DNS resolution for host IP.</help>
</field>
<field>
<id>dns_ldap_resolution</id>
<label>LDAP server DNS lookup</label>
<type>info</type>
<help>DNS IP resolution for LDAP server name.</help>
</field>
<field>
<id>dns_ldap_reverse_resolution</id>
<label>LDAP server DNS reverse lookup</label>
<type>info</type>
<help>Reverse DNS resolution for LDAP server IP.</help>
</field>
<field>
<id>kerberos_config</id>
<label>Kerberos configuration</label>
<type>info</type>
<help>Kerberos configuration must exist and be valid.</help>
</field>
<field>
<id>keytab</id>
<label>Keytab file</label>
<type>info</type>
<help>Keytab file must exist and be valid.</help>
</field>
</form>

View file

@ -0,0 +1,14 @@
<form>
<field>
<id>ProxySSO.EnableSSO</id>
<label>Enable Single Sign-On</label>
<type>checkbox</type>
<help>Enable Kerberos based Single Sign-On</help>
</field>
<field>
<id>ProxySSO.ADKerberosImplementation</id>
<label>AD Kerberos implementation</label>
<type>dropdown</type>
<help>Select Windows Server version for AD controller</help>
</field>
</form>

View file

@ -0,0 +1,18 @@
<form>
<field>
<label>Key Table creation</label>
<type>header</type>
</field>
<field>
<id>admin_username</id>
<label>AD admin login</label>
<type>text</type>
<help>Active Directory user name with administrator rights (this value is not stored in configuration).</help>
</field>
<field>
<id>admin_password</id>
<label>AD admin password</label>
<type>password</type>
<help>Active Directory user password (this value is not stored in configuration).</help>
</field>
</form>

View file

@ -0,0 +1,12 @@
<form>
<field>
<id>username</id>
<label>Username</label>
<type>text</type>
</field>
<field>
<id>password</id>
<label>Password</label>
<type>password</type>
</field>
</form>

View file

@ -1,105 +0,0 @@
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\SSOProxyAD\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\SSOProxyAD\SSOProxyAD;
use \OPNsense\Core\Backend;
use \OPNsense\Cron\Cron;
class ServiceController extends ApiControllerBase
{
public function reloadAction()
{
$status = "failed";
if ($this->request->isPost()) {
$mdlSSOProxyAD = new SSOProxyAD();
if ((string)$mdlSSOProxyAD->general->UpdateCron == "") {
$mdlCron = new Cron();
$mdlSSOProxyAD->general->UpdateCron = $mdlCron->newDailyJob(
"SSOProyAD",
"ssoproxyad updateDomain",
"SSOProxyAD updateDomain cron",
"1"
);
if ($mdlCron->performValidation()->count() == 0) {
$mdlCron->serializeToConfig();
$mdlMymodule->serializeToConfig($validateFullModel = false, $disable_validation = true);
Config::getInstance()->save();
}
}
$backend = new Backend();
$bckresult = trim($backend->configdRun('template reload OPNsense/SSOProxyAD'));
if ($bckresult == "OK") {
$status = "ok";
}
}
return array("status" => $status);
}
public function testAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$bckresult = json_decode(trim($backend->configdRun("ssoproxyad test")), true);
if ($bckresult !== null) {
// only return valid json type responses
return $bckresult;
}
}
return array("message" => "unable to run config action");
}
public function joinDomainAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$bckresult = json_decode(trim($backend->configdRun("ssoproxyad joinDomain")), true);
if ($bckresult !== null) {
// only return valid json type responses
return $bckresult;
}
}
return array("message" => "unable to run config action");
}
public function updateDomainAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$bckresult = json_decode(trim($backend->configdRun("ssoproxyad updateDomain")), true);
if ($bckresult !== null) {
// only return valid json type responses
return $bckresult;
}
}
return array("message" => "unable to run config action");
}
}

View file

@ -1,52 +0,0 @@
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\SSOProxyAD\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Core\Config;
class SettingsController extends ApiMutableModelControllerBase
{
static protected $internalModelClass = '\OPNsense\SSOProxyAD\SSOProxyAD';
static protected $internalModelName = 'ssoproxyad';
/**
* @return array plain model settings (non repeating items)
*/
protected function getModelNodes()
{
$settingsNodes = array('general');
$result = array();
$mdlSSO = $this->getModel();
foreach ($settingsNodes as $key) {
$result[$key] = $mdlSSO->$key->getNodes();
}
return $result;
}
}

View file

@ -1,39 +0,0 @@
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\SSOProxyAD;
class IndexController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext('SSO Proxy Active Directory');
$this->view->pick('OPNsense/SSOProxyAD/index');
$this->view->generalForm = $this->getForm("general");
}
}

View file

@ -1,33 +0,0 @@
<form>
<field>
<id>ssoproxyad.general.Enabled</id>
<label>enabled</label>
<type>checkbox</type>
<help>Enable this feature</help>
</field>
<field>
<id>ssoproxyad.general.DomainName</id>
<label>Active Directory Domain Name</label>
<type>text</type>
</field>
<field>
<id>ssoproxyad.general.DomainDC</id>
<label>Active Directory Domain Controller</label>
<type>text</type>
</field>
<field>
<id>ssoproxyad.general.DomainVersion</id>
<label>Active Directory Domain Version</label>
<type>text</type>
</field>
<field>
<id>ssoproxyad.general.DomainUser</id>
<label>Active Directory Domain User</label>
<type>text</type>
</field>
<field>
<id>ssoproxyad.general.DomainPassword</id>
<label>Active Directory Domain Password</label>
<type>password</type>
</field>
</form>

View file

@ -1,73 +0,0 @@
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Auth;
use OPNsense\Core\Config;
/**
* Class SSOProxyAD connector
* @package OPNsense\Auth
*/
class SSOProxyAD implements IAuthConnector
{
public static function getType()
{
return 'ssoproxyad';
}
/**
* user friendly description of this authenticator
* @return string
*/
public function getDescription()
{
return gettext("SSO Proxy AD");
}
/**
* set connector properties
* @param array $config connection properties
*/
public function setProperties($config)
{
}
/**
* unused
* @return array mixed named list of authentication properties
*/
public function getLastAuthProperties()
{
return array();
}
public function authenticate($username, $password)
{
return false;
}
}

View file

@ -0,0 +1,7 @@
<menu>
<Services>
<WebProxy>
<ProxySSO VisibleName="Single Sign-On" cssClass="fa fa-shield fa-fw" order="26" url="/ui/proxysso/" />
</WebProxy>
</Services>
</menu>

View file

@ -0,0 +1,9 @@
<?php
namespace OPNsense\ProxySSO;
use OPNsense\Base\BaseModel;
class ProxySSO extends BaseModel
{
}

View file

@ -0,0 +1,20 @@
<model>
<mount>//OPNsense/ProxySSO</mount>
<description>
Web-proxy Single Sign-On plugin
</description>
<items>
<EnableSSO type="BooleanField">
<default>0</default>
<Required>Y</Required>
</EnableSSO>
<ADKerberosImplementation type="OptionField">
<default>W2008</default>
<Required>Y</Required>
<OptionValues>
<W2003>Windows 2003</W2003>
<W2008>Windows 2008 with AES</W2008>
</OptionValues>
</ADKerberosImplementation>
</items>
</model>

View file

@ -1,9 +0,0 @@
<acl>
<page-user-ssoproxyad>
<name>Services: Web Proxy: SSO</name>
<patterns>
<pattern>ui/ssoproxyad/*</pattern>
<pattern>api/ssoproxyad/*</pattern>
</patterns>
</page-user-ssoproxyad>
</acl>

View file

@ -1,7 +0,0 @@
<menu>
<Services>
<WebProxy>
<SSO VisibleName="Single-Sign On" url="/ui/ssoproxyad/"/>
</WebProxy>
</Services>
</menu>

View file

@ -1,43 +0,0 @@
<model>
<mount>//OPNsense/ssoproxyad</mount>
<description>
SSO Active Directory plugin
</description>
<items>
<general>
<Enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</Enabled>
<DomainName type="TextField">
<Required>Y</Required>
</DomainName>
<DomainDC type="TextField">
<Required>Y</Required>
</DomainDC>
<DomainVersion type="TextField">
<Required>Y</Required>
</DomainVersion>
<DomainUser type="TextField">
<Required>Y</Required>
</DomainUser>
<DomainPassword type="UpdateOnlyTextField">
<Required>Y</Required>
</DomainPassword>
<UpdateCron type="ModelRelationField">
<Model>
<queues>
<source>OPNsense.Cron.Cron</source>
<items>jobs.job</items>
<display>description</display>
<filters>
<origin>/SSOProxyAD/</origin>
</filters>
</queues>
</Model>
<ValidationMessage>Related cron not found.</ValidationMessage>
<Required>N</Required>
</UpdateCron>
</general>
</items>
</model>

View file

@ -0,0 +1,170 @@
<script type="text/javascript">
$( document ).ready(function() {
/*************************************************************************************************************
* link general actions
*************************************************************************************************************/
var data_get_map = {'frm_GeneralSettings':"/api/proxysso/settings/get"};
// load initial data
mapDataToFormUI(data_get_map).done(function(){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
// load checklist data
updateKerberosChecklist();
$("#RefreshCheckList").click(function() {
updateKerberosChecklist();
});
$("#ShowKeytab").click(function() {
ajaxCall(url="/api/proxysso/service/showkeytab", sendData={}, callback=function(data,status) {
$("#kerberos_output").html(data['response']);
});
});
$("#DeleteKeytab").click(function() {
ajaxCall(url="/api/proxysso/service/deletekeytab", sendData={}, callback=function(data,status) {
$("#kerberos_output").html(data['response']);
});
});
$("#CreateKeytab").click(function() {
ajaxCall(
url="/api/proxysso/service/createkeytab",
sendData={"admin_login":$("#admin_username").val(), "admin_password":$("#admin_password").val()},
callback=function(data,status) { $("#kerberos_output").html(data['response']); }
);
});
$("#TestKerbLogin").click(function() {
ajaxCall(
url="/api/proxysso/service/testkerblogin",
sendData={"login":$("#username").val(), "password":$("#password").val()},
callback=function(data,status) { $("#kerberos_output").html(data['response']); });
});
// link save button to API set action
$("#applyAct").click(function(){
$("#responseMsg").html('');
$("#applyAct_progress").addClass("fa fa-spinner fa-pulse");
$("#applyAct").addClass("disabled");
saveFormToEndpoint(url="/api/proxysso/settings/set",formid='frm_GeneralSettings',callback_ok=function(){
ajaxCall(url="/api/proxy/service/reconfigure", sendData={},callback=function(data,status) {
if(data.status == "ok") {
$("#responseMsg").html("{{lang._('Proxy reconfigured')}}");
$("#responseMsg").removeClass("hidden");
}
$("#applyAct_progress").removeClass("fa fa-spinner fa-pulse");
$("#applyAct").removeClass("disabled");
});
});
});
});
function showDump(fieldname)
{
$("#kerberos_output").html($("#" + fieldname + "_dump").html());
$("#kerberos_output")[0].scrollIntoView(true);
}
function updateKerberosChecklist()
{
$("#refresh_progress").addClass("fa fa-spinner fa-pulse");
$("#RefreshCheckList").addClass("disabled");
var checklist_get_map = {'frm_CheckList':"/api/proxysso/service/getchecklist"};
mapDataToFormUI(checklist_get_map).done(function(data){
$("#refresh_progress").removeClass("fa fa-spinner fa-pulse");
$("#RefreshCheckList").removeClass("disabled");
$.each(data.frm_CheckList, function(index, value){
// clear data
$("#" + index).html("");
$(".help-block[for='" + index + "']").html("");
if(value.status == "ok") {
jQuery('<div/>', {
id: index + '_indicator',
class: 'fa fa-check-circle text-success',
}).appendTo("#" + index);
if(value.message) {
$(".help-block[for='" + index + "']").html(value.message);
}
}
else if(value.status == "failure") {
jQuery('<div/>', {
id: index + '_indicator',
class: 'fa fa-times-circle text-danger',
}).appendTo("#" + index);
if(value.message) {
$(".help-block[for='" + index + "']").html(value.message);
}
}
else {
$("#" + index).html(value);
}
if(value.dump) {
jQuery('<div/>', {
id: index + '_dump',
text: htmlDecode(value.dump),
class: 'hidden',
}).appendTo(".help-block[for='" + index + "']");
jQuery('<a/>', {
text: "{{ lang._('Show dump') }}",
href: 'javascript:showDump("' + index + '");',
style: 'padding-left: 20px;',
}).appendTo("#" + index);
}
});
});
}
</script>
<div class="alert alert-info hidden" role="alert" id="responseMsg">
</div>
<ul class="nav nav-tabs" role="tablist" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general"><b>{{ lang._('General') }}</b></a></li>
<li><a data-toggle="tab" href="#testing"><b>{{ lang._('Kerberos Authentication') }}</b></a></li>
</ul>
<div class="tab-content content-box">
<div class="tab-pane fade in active" id="general">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_GeneralSettings'])}}
<hr/>
<button class="btn btn-primary __mb" id="applyAct" type="button"><b>{{ lang._('Apply') }}</b> <i id="applyAct_progress" class=""></i></button>
</div>
<div class="tab-pane fade" id="testing">
{{ partial("layout_partials/base_form",['fields':checkListForm,'id':'frm_CheckList'])}}
<hr/>
<button class="btn btn-primary __mb" id="RefreshCheckList" type="button"><b>{{ lang._('Refresh') }}</b> <i id="refresh_progress" class=""></i></button>
<div class="__mb">
{{ partial("layout_partials/base_form",['fields':testingCreateForm,'id':'frm_TestingCreate'])}}
<button class="btn btn-primary" id="CreateKeytab" type="button"><b>{{ lang._('Create Key Table') }}</b></button>
<button class="btn btn-primary" id="DeleteKeytab" type="button"><b>{{ lang._('Delete Key Table') }}</b></button>
<button class="btn btn-primary" id="ShowKeytab" type="button"><b>{{ lang._('Show Key Table') }}</b></button>
</div>
{{ partial("layout_partials/base_form",['fields':testingTestForm,'id':'frm_TestingTest'])}}
<button class="btn btn-primary" id="TestKerbLogin" type="button"><b>{{ lang._('Test Kerberos login') }}</b></button>
<hr/>
<p><b>{{ lang._('Output') }}</b></p>
<pre id="kerberos_output"></pre>
</div>
</div>

View file

@ -1,82 +0,0 @@
{#
Copyright (C) 2016 <gitdevmod@github.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
#}
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_GeneralSettings'])}}
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_GeneralSettings':"/api/ssoproxyad/settings/get"};
mapDataToFormUI(data_get_map).done(function(data){
// place actions to run after load, for example update form styles.
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/ssoproxyad/settings/set",formid='frm_GeneralSettings',callback_ok=function(){
// action to run after successful save, for example reconfigure service.
ajaxCall(url="/api/ssoproxyad/service/reload", sendData={},callback=function(data,status) {
// action to run after reload
});
});
});
$("#testAct").click(function(){
$("#responseMsg").removeClass("hidden");
ajaxCall(url="/api/ssoproxyad/service/test", sendData={},callback=function(data,status) {
// action to run after reload
$("#responseMsg").html(data['message']);
});
});
$("#joinDomainAct").click(function(){
$("#responseMsg").removeClass("hidden");
ajaxCall(url="/api/ssoproxyad/service/joinDomain", sendData={},callback=function(data,status) {
// action to run after reload
$("#responseMsg").html(data['message']);
});
});
$("#updateDomainAct").click(function(){
$("#responseMsg").removeClass("hidden");
ajaxCall(url="/api/ssoproxyad/service/updateDomain", sendData={},callback=function(data,status) {
// action to run after reload
$("#responseMsg").html(data['message']);
});
});
});
</script>
<div class="col-md-12">
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
<div class="alert alert-info hidden" role="alert" id="responseMsg">
</div>
<button class="btn btn-primary" id="testAct" type="button"><b>{{ lang._('Test') }}</b></button>
<button class="btn btn-primary" id="joinDomainAct" type="button"><b>{{ lang._('Join Domain') }}</b></button>
<button class="btn btn-primary" id="updateDomainAct" type="button"><b>{{ lang._('Update Domain') }}</b></button>

View file

@ -0,0 +1,27 @@
#!/bin/sh
PASS_TMP=/tmp/__tmp_kerb_pass
while getopts :f:u:p: name
do
case $name in
f) FQDN="$OPTARG" ;; # aka TING.tingnet.local
u) USERNAME="$OPTARG" ;; # username
p) PASSWORD="$OPTARG" ;; # password
esac
done
[ "$USERNAME" == "" ] && echo "No account name" && exit 0;
[ "$PASSWORD" == "" ] && echo "No account password" && exit 0;
[ "$FQDN" == "" ] && echo "No FQDN" && exit 0;
PASSWORD="${PASSWORD%\'}"
echo "${PASSWORD}" | sed 's/\\//g' > ${PASS_TMP}
/usr/local/bin/kinit ${USERNAME} < ${PASS_TMP}
TICKET=$?
rm ${PASS_TMP}
/usr/local/libexec/squid/negotiate_kerberos_auth_test ${FQDN} | awk '{sub(/Token:/,"YR"); print $0}END{print "QQ"}' | /usr/local/libexec/squid/negotiate_kerberos_auth -s GSS_C_NO_NAME
/usr/local/bin/kdestroy

View file

@ -0,0 +1,41 @@
#!/bin/sh
KEYTAB=/usr/local/etc/squid/squid.keytab
PASS_TMP=/tmp/__tmp_kerb_pass
while getopts :d:n:k:e:b:u:p: name
do
case $name in
d) DOMAIN="$OPTARG" ;; # aka opnsense.local
n) PRINCIPAL="$OPTARG" ;; # aka HTTP/OPNSENSE
k) KERB_COMPUTER_NAME="$OPTARG" ;; # aka OPNSENSE-K
e) ENCTYPES="$OPTARG" ;;
b) BASENAME="$OPTARG" ;;
u) USERNAME="$OPTARG" ;; # LDAP admin username
p) PASSWORD="$OPTARG" ;; # LDAP admin password
esac
done
[ "$USERNAME" == "" ] && echo "No administrator account name" && exit 0;
[ "$PASSWORD" == "" ] && echo "No administrator account password" && exit 0;
[ "$BASENAME" == "" ] && BASENAME="CN=Computers";
[ "$PRINCIPAL" == "" ] && echo "No principal name" && exit 0;
[ "$DOMAIN" == "" ] && echo "No domain name" && exit 0;
[ "$KERB_COMPUTER_NAME" == "" ] && echo "No Kerberos name for host" && exit 0;
[ "$ENCTYPES" == "2008" ] && ENCTYPES_PARAM="--enctypes 28";
PASSWORD="${PASSWORD%\'}"
echo "${PASSWORD}" | sed 's/\\//g' > ${PASS_TMP}
#/usr/local/bin/kinit --password-file=${PASS_TMP} ${USERNAME}
/usr/local/bin/kinit ${USERNAME} < ${PASS_TMP}
TICKET=$?
rm ${PASS_TMP}
[ $TICKET != 0 ] && echo "No ticket" && exit 0;
/usr/local/sbin/msktutil -c --verbose -b "${BASENAME}" -s ${PRINCIPAL}.${DOMAIN} -k ${KEYTAB} --computer-name ${KERB_COMPUTER_NAME} --upn ${PRINCIPAL}.${DOMAIN} ${ENCTYPES_PARAM} 2>&1
chmod +r ${KEYTAB}
/usr/local/bin/kdestroy

View file

@ -1,90 +0,0 @@
#!/usr/local/bin/php
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// Use legacy code to export certificates to the filesystem.
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
use OPNsense\Core\Config;
global $config;
$configObj = Config::getInstance()->object();
$hostname = $configObj->system->hostname;
$fqdn = $hostname . "." . $configObj->system->domain;
if (isset($configObj->OPNsense->ssoproxyad)) {
foreach ($configObj->OPNsense->ssoproxyad->general as $ssoproxyad) {
$enabled = $ssoproxyad->Enabled;
$domainname = $ssoproxyad->DomainName;
$domaindc = $ssoproxyad->DomainDC;
$domainversion = $ssoproxyad->DomainVersion;
$domainuser = $ssoproxyad->DomainUser;
$domainpassword = $ssoproxyad->DomainPassword;
}
}
$keytab = '/usr/local/etc/ssoproxyad/PROXY.keytab';
$cmd_2003 = '/usr/local/sbin/msktutil -c -b CN=COMPUTERS -s HTTP -k ' . $keytab . ' --computer-name ' . strtoupper($hostname) . ' --upn HTTP/' . $fqdn. ' --server ' . $domaindc . ' 2>&1';
$cmd_2008 = '/usr/local/sbin/msktutil -c -b CN=COMPUTERS -s HTTP -k ' . $keytab . ' --computer-name ' . strtoupper($hostname) . ' --upn HTTP/' . $fqdn. ' --server ' . $domaindc . ' --enctypes 28 2>&1';
if ($enabled == 1) {
$krb5secret = '/usr/local/etc/ssoproxyad/krb5secret';
if (!file_exists($keytab)) {
file_put_contents($krb5secret, $domainpassword);
chmod($krb5secret, 0600);
exec('/usr/local/bin/kinit --password-file="' . $krb5secret . '" ' . $domainuser. "@" . strtoupper($domainname) . " 2>&1", $output_kinit, $error_kinit);
if ($error_kinit > 0) {
$out = implode($output_kinit);
$return = array('message' => "$out");
} else {
if ($domainversion == '2003') {
exec($cmd_2003, $output_msktutil, $error_msktutil);
} elseif ($domainversion == '2008') {
exec($cmd_2008, $output_msktutil, $error_msktutil);
}
if ((file_exists($keytab)) and ($error_msktutil <= 0)) {
chown($keytab, 'squid');
chgrp($keytab, 'squid');
exec("/usr/local/bin/kdestroy 2>&1", $output_kdestroy, $error_kdestroy);
$return = array('message' => "keytab created");
} else {
$out = implode($output_msktutil);
$return = array('message' => "Unable to create keytab: $out");
}
}
} else {
$return = array('message' => "keytab already exists");
}
}
if (file_exists($krb5secret)) {
unlink($krb5secret);
}
echo json_encode($return);

View file

@ -1,42 +0,0 @@
#!/usr/local/bin/python2.7
"""
Copyright (c) 2016 <gitdevmod@github.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
"""
import os
import socket
import json
ssoproxyad_config = '/usr/local/etc/ssoproxyad/krb5.conf'
result = {}
if os.path.exists(ssoproxyad_config):
result['message'] = 'test ok!'
else:
# no config
result['message'] = 'no configuration file found'
print (json.dumps(result))

View file

@ -1,71 +0,0 @@
#!/usr/local/bin/php
<?php
/**
* Copyright (C) 2016 <gitdevmod@github.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
// Use legacy code to export certificates to the filesystem.
require_once("config.inc");
require_once("certs.inc");
require_once("legacy_bindings.inc");
require_once("util.inc");
use OPNsense\Core\Config;
global $config;
$configObj = Config::getInstance()->object();
$hostname = $configObj->system->hostname;
$fqdn = $hostname . "." . $configObj->system->domain;
if (isset($configObj->OPNsense->ssoproxyad)) {
foreach ($configObj->OPNsense->ssoproxyad->general as $ssoproxyad) {
$enabled = $ssoproxyad->Enabled;
}
}
if ($enabled == 1) {
$keytab = '/usr/local/etc/ssoproxyad/PROXY.keytab';
if (file_exists($keytab)) {
$cmd = exec_safe('/usr/local/sbin/msktutil %s %s %s %s %s 2>&1', array(
'--auto-update',
'--computer-name',
strtolower($hostname),
'--keytab',
$keytab
));
exec($cmd, $output_msktutil, $error_msktutil);
$out = implode($output_msktutil);
if ($error_msktutil > 0) {
$return = array('message' => "Unable to auto-update: $out)");
} else {
$return = array('message' => "Auto-update successful: $out");
}
} else {
$return = array('message' => "keytab do not exists");
}
}
echo json_encode($return);

View file

@ -0,0 +1,23 @@
[showkeytab]
command:( [ ! -f /usr/local/etc/squid/squid.keytab ] && echo "No keytab /usr/local/etc/squid/squid.keytab") || /usr/local/bin/klist -k /usr/local/etc/squid/squid.keytab
parameters:
type:script_output
message:show kerberos keytab
[createkeytab]
command:/usr/local/opnsense/scripts/OPNsense/ProxySSO/squid-gen-keytab.sh
parameters:-n %s -d %s -k %s -e %s -u %s -p %s
type:script_output
message:create keytab
[deletekeytab]
command:( [ ! -f /usr/local/etc/squid/squid.keytab ] && echo "No keytab file" ) || rm /usr/local/etc/squid/squid.keytab
parameters:
type:script_output
message:delete keytab
[testkerblogin]
command:/usr/local/opnsense/scripts/OPNsense/ProxySSO/kerberos_test.sh
parameters:-u %s -p %s -f %s
type:script_output
message:test kerberos login

View file

@ -1,17 +0,0 @@
[test]
command:/usr/local/opnsense/scripts/OPNsense/SSOProxyAD/testConnection.py
parameters:
type:script_output
message:SSO Proxy AD module test
[joinDomain]
command:/usr/local/opnsense/scripts/OPNsense/SSOProxyAD/joinDomain.php
parameters:
type:script_output
message:SSO Proxy AD module join AD domain
[updateDomain]
command:/usr/local/opnsense/scripts/OPNsense/SSOProxyAD/updateDomain.php
parameters:
type:script_output
message:SSO Proxy AD module update AD domain

View file

@ -1,14 +0,0 @@
{% if helpers.exists('OPNsense.proxy.forward.authentication.method') %}
{% if helpers.exists('system.authserver') %}
{% for server in helpers.toList('system.authserver') %}
{% if server.name == OPNsense.proxy.forward.authentication.method %}
{% if server.type == "ssoproxyad" %}
auth_param negotiate program "/usr/local/libexec/squid/negotiate_kerberos_auth"
auth_param negotiate children 10
auth_param negotiate keep_alive on
acl local_auth proxy_auth REQUIRED
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

View file

@ -0,0 +1,3 @@
rc.conf.d:/etc/rc.conf.d/squid_krb5
krb5.conf:/etc/krb5.conf
kerberos.sso.conf:/usr/local/etc/squid/pre-auth/20-negotiate.auth.conf

View file

@ -0,0 +1,20 @@
{% set ldap_method = [] %}
{% if helpers.exists('OPNsense.proxy.forward.authentication.method') and OPNsense.proxy.forward.authentication.method != '' %}
{% for method in OPNsense.proxy.forward.authentication.method.split(",") %}
{% if method != "Local Database" %}
{% for server in helpers.toList('system.authserver') %}
{% if server.type == 'ldap' and server.name == method %}
{% do ldap_method.append(server) %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% if ldap_method|length > 0 and helpers.exists('OPNsense.ProxySSO.EnableSSO') and OPNsense.ProxySSO.EnableSSO == '1' %}
auth_param negotiate program /usr/local/libexec/squid/negotiate_kerberos_auth -d -i -s HTTP/{{system.hostname}}.{{system.domain}}@{{system.domain|upper}}
auth_param negotiate keep_alive on
{% if helpers.exists('OPNsense.proxy.forward.authentication.children') %}
auth_param negotiate children {{OPNsense.proxy.forward.authentication.children}}
{% endif %}
{% endif%}
{% endif %}

View file

@ -0,0 +1,38 @@
# Autogenerated config. Do not edit manualy.
{% set ldap = [] %}
{% if helpers.exists('OPNsense.proxy.forward.authentication.method') %}
{% for method in OPNsense.proxy.forward.authentication.method.split(",") %}
{% for server in helpers.toList('system.authserver') %}
{% if server.type == 'ldap' and server.name == method %}
{% do ldap.append(server) %}
{% endif %}
{% endfor %}
{% endfor %}
{% endif %}
{% if ldap|length > 0 and helpers.exists('OPNsense.ProxySSO.EnableSSO') and OPNsense.ProxySSO.EnableSSO|default('0') == '1' %}
[libdefaults]
default_realm = {{ system.domain|upper }}
dns_lookup_kdc = no
dns_lookup_realm = no
ticket_lifetime = 24h
default_keytab_name = /usr/local/etc/squid/squid.keytab
{% if helpers.exists('OPNsense.ProxySSO.ADKerberosImplementation') and OPNsense.ProxySSO.ADKerberosImplementation == 'W2003' %}
default_tgs_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
default_tkt_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
permitted_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
{% else %}
default_tgs_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
default_tkt_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
permitted_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
{% endif %}
[realms]
{{ system.domain|upper }} = {
kdc = {{ ldap[0].host }}
admin_server = {{ ldap[0].host }}
default_domain = {{ system.domain }}
}
[domain_realm]
.{{ system.domain }} = {{ system.domain|upper }}
{{ system.domain }} = {{ system.domain|upper }}
{% endif %}

View file

@ -0,0 +1,3 @@
{% if helpers.exists('OPNsense.ProxySSO.EnableSSO') and OPNsense.ProxySSO.EnableSSO|default("0") == "1" %}
squid_krb5_ktname="/usr/local/etc/squid/squid.keytab"
{% endif %}

View file

@ -1,2 +0,0 @@
krb5.conf:/usr/local/etc/ssoproxyad/krb5.conf
rc.conf:/etc/rc.conf.d/squid/ssoproxyad

View file

@ -1,33 +0,0 @@
{% if helpers.exists('OPNsense.ssoproxyad.general') and OPNsense.ssoproxyad.general.Enabled|default("0") == "1" %}
[libdefaults]
default_realm = {{ OPNsense.ssoproxyad.general.DomainName|upper }}
dns_lookup_kdc = no
dns_lookup_realm = no
ticket_lifetime = 24h
default_keytab_name = /usr/local/etc/ssoproxyad/PROXY.keytab
{% if helpers.exists('OPNsense.ssoproxyad.general.DomainVersion') and OPNsense.ssoproxyad.general.DomainVersion == '2003' %}
default_tgs_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
default_tkt_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
permitted_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
{% endif %}
{% if helpers.exists('OPNsense.ssoproxyad.general.DomainVersion') and OPNsense.ssoproxyad.general.DomainVersion == '2008' %}
; for Windows 2008 with AES
default_tgs_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
default_tkt_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
permitted_enctypes = aes256-cts-hmac-sha1-96 rc4-hmac des-cbc-crc des-cbc-md5
{% endif %}
[realms]
{{ OPNsense.ssoproxyad.general.DomainName|upper }} = {
kdc = {{ OPNsense.ssoproxyad.general.DomainDC|lower }}.{{ OPNsense.ssoproxyad.general.DomainName|lower }}
admin_server = {{ OPNsense.ssoproxyad.general.DomainDC|lower }}.{{ OPNsense.ssoproxyad.general.DomainName|lower }}
default_domain = {{ OPNsense.ssoproxyad.general.DomainName|lower }}
}
[domain_realm]
.{{ OPNsense.ssoproxyad.general.DomainName|lower }} = {{ OPNsense.ssoproxyad.general.DomainName|upper }}
{{ OPNsense.ssoproxyad.general.DomainName|lower }} = {{ OPNsense.ssoproxyad.general.DomainName|upper }}
{% endif %}

View file

@ -1,11 +0,0 @@
{% if helpers.exists('system.authserver') %}
{% for server in helpers.toList('system.authserver') %}
{% if helpers.exists('OPNsense.proxy.forward.authentication.method') %}
{% if server.name == OPNsense.proxy.forward.authentication.method %}
{% if server.type == "ssoproxyad" %}
squid_krb5_ktname="/usr/local/etc/ssoproxyad/PROXY.keytab"
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}