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 @@
+
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 %}