diff --git a/Makefile b/Makefile index c8d8618a4..08b0b889d 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ PAGER?= less all: @cat ${.CURDIR}/README.md | ${PAGER} -CATEGORIES= devel net sysutils security +CATEGORIES= devel net sysutils security www .for CATEGORY in ${CATEGORIES} _${CATEGORY}!= ls -1d ${CATEGORY}/* diff --git a/www/web-proxy-sso/Makefile b/www/web-proxy-sso/Makefile new file mode 100644 index 000000000..de79df76b --- /dev/null +++ b/www/web-proxy-sso/Makefile @@ -0,0 +1,8 @@ +PLUGIN_NAME= web-proxy-sso +PLUGIN_VERSION= 0.1 +PLUGIN_PRIVATE= yes +PLUGIN_COMMENT= Add SSO Active Directory to use in Proxy +PLUGIN_DEPENDS= msktutil +PLUGIN_MAINTAINER= gitdevmod@github.com + +.include "../../Mk/plugins.mk" diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/ServiceController.php b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/ServiceController.php new file mode 100644 index 000000000..9d25c3e1e --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/ServiceController.php @@ -0,0 +1,101 @@ +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"); +} + +} diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/SettingsController.php b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/SettingsController.php new file mode 100644 index 000000000..001de8c9d --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/Api/SettingsController.php @@ -0,0 +1,84 @@ +request->isGet()) { + $mdlSSOProxyAD= new SSOProxyAD(); + $result['ssoproxyad'] = $mdlSSOProxyAD->getNodes(); + } + return $result; + } + +/** + * update SSOProxyAD settings + * @return array status + */ +public function setAction() +{ + $result = array("result"=>"failed"); + if ($this->request->isPost()) { + // load model and update with provided data + $mdlSSOProxyAD= new SSOProxyAD(); + $mdlSSOProxyAD->setNodes($this->request->getPost("ssoproxyad")); + + // perform validation + $valMsgs = $mdlSSOProxyAD->performValidation(); + foreach ($valMsgs as $field => $msg) { + if (!array_key_exists("validations", $result)) { + $result["validations"] = array(); + } + $result["validations"]["general.".$msg->getField()] = $msg->getMessage(); + } + + // serialize model to config and save + if ($valMsgs->count() == 0) { + $mdlSSOProxyAD->serializeToConfig(); + Config::getInstance()->save(); + $result["result"] = "saved"; + } + } + return $result; +} + +} diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/IndexController.php b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/IndexController.php new file mode 100644 index 000000000..bcc082ff2 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/IndexController.php @@ -0,0 +1,42 @@ +view->title = "SSO Proxy Active Directory"; + // pick the template to serve to our users. + $this->view->pick('OPNsense/SSOProxyAD/index'); + + $this->view->generalForm = $this->getForm("general"); + } +} diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/forms/general.xml b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/forms/general.xml new file mode 100644 index 000000000..d50628060 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/controllers/OPNsense/SSOProxyAD/forms/general.xml @@ -0,0 +1,33 @@ +
+ + ssoproxyad.general.Enabled + + checkbox + Enable this feature + + + ssoproxyad.general.DomainName + + text + + + ssoproxyad.general.DomainDC + + text + + + ssoproxyad.general.DomainVersion + + text + + + ssoproxyad.general.DomainUser + + text + + + ssoproxyad.general.DomainPassword + + password + +
diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/library/OPNsense/Auth/SSOProxyAD.php b/www/web-proxy-sso/src/opnsense/mvc/app/library/OPNsense/Auth/SSOProxyAD.php new file mode 100644 index 000000000..397fa6355 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/library/OPNsense/Auth/SSOProxyAD.php @@ -0,0 +1,73 @@ + + + + WebCfg - Users: SSO Proxy AD + Allow access to the SSO Proxy AD module + + ui/ssoproxyad/* + api/ssoproxyad/* + + + diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/Menu/Menu.xml b/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/Menu/Menu.xml new file mode 100644 index 000000000..4c3a36cb7 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/Menu/Menu.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/SSOProxyAD.php b/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/SSOProxyAD.php new file mode 100644 index 000000000..c29691ce9 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/models/OPNsense/SSOProxyAD/SSOProxyAD.php @@ -0,0 +1,35 @@ + + //OPNsense/ssoproxyad + + SSO Active Directory plugin + + + + + 1 + Y + + + Y + + + Y + + + Y + + + Y + + + Y + + + + + OPNsense.Cron.Cron + jobs.job + description + + /SSOProxyAD/ + + + + Related cron not found. + N + + + + diff --git a/www/web-proxy-sso/src/opnsense/mvc/app/views/OPNsense/SSOProxyAD/index.volt b/www/web-proxy-sso/src/opnsense/mvc/app/views/OPNsense/SSOProxyAD/index.volt new file mode 100644 index 000000000..37a6bca44 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/mvc/app/views/OPNsense/SSOProxyAD/index.volt @@ -0,0 +1,84 @@ +{# +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'])}} + + + +
+ +
+ + + + + + diff --git a/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/joinDomain.php b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/joinDomain.php new file mode 100755 index 000000000..8134e6b41 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/joinDomain.php @@ -0,0 +1,89 @@ +#!/usr/local/bin/php +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/bin/kinit --password-file="' . $krb5secret . '" ' . $domainuser. "@" . strtoupper($domainname) . " 2>&1",$output_kinit,$error_kinit); + if ($error_kinit > 0) { + $return = array('message' => "$output_kinit"); + } + 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/bin/kdestroy 2>&1",$output_kdestroy,$error_kdestroy); + unlink($krb5secret); + $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"); + } +} +echo json_encode($return); diff --git a/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/testConnection.py b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/testConnection.py new file mode 100755 index 000000000..91b486186 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/testConnection.py @@ -0,0 +1,45 @@ +#!/usr/local/bin/python2.7 + +""" + Copyright (c) 2015 Ad Schellevis + 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. + + -------------------------------------------------------------------------------------- + + perform some tests for the helloworld application +""" +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)) diff --git a/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/updateDomain.php b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/updateDomain.php new file mode 100755 index 000000000..5d346962d --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/scripts/OPNsense/SSOProxyAD/updateDomain.php @@ -0,0 +1,66 @@ +#!/usr/local/bin/php +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 = '/usr/local/sbin/msktutil --auto-update --computer-name ' . strtolower($hostname) . ' --keytab ' . $keytab . ' 2>&1'; + 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); diff --git a/www/web-proxy-sso/src/opnsense/service/conf/actions.d/actions_ssoproxyad.conf b/www/web-proxy-sso/src/opnsense/service/conf/actions.d/actions_ssoproxyad.conf new file mode 100644 index 000000000..f95873260 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/service/conf/actions.d/actions_ssoproxyad.conf @@ -0,0 +1,17 @@ +[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 diff --git a/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/+TARGETS b/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/+TARGETS new file mode 100644 index 000000000..3d6b20d59 --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/+TARGETS @@ -0,0 +1 @@ +krb5.conf:/usr/local/etc/ssoproxyad/krb5.conf diff --git a/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/krb5.conf b/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/krb5.conf new file mode 100644 index 000000000..900f6d92b --- /dev/null +++ b/www/web-proxy-sso/src/opnsense/service/templates/OPNsense/SSOProxyAD/krb5.conf @@ -0,0 +1,33 @@ +{% 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 %}