Smart-Soft Proxy SSO plugin (#266)

This commit is contained in:
evbevz
2017-09-25 12:49:49 +04:00
committed by Franco Fichtner
parent 8b274753f9
commit e2a42db535
21 changed files with 832 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
rm -f /usr/local/etc/squid/pre-auth/20-negotiate.auth.conf
if [ -f /var/run/squid/squid.pid ]; then
configctl proxy reconfigure
fi
+8
View File
@@ -0,0 +1,8 @@
PLUGIN_NAME= proxy-sso
PLUGIN_VERSION= 1.3
PLUGIN_COMMENT= Kerberos authentication module
PLUGIN_DEPENDS= msktutil cyrus-sasl-gssapi
PLUGIN_MAINTAINER= evbevz@gmail.com
PLUGIN_WWW= http://smart-soft.ru
.include "../../Mk/plugins.mk"
@@ -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');
}
}
@@ -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,
];
}
}
@@ -0,0 +1,44 @@
<?php
/**
* Copyright (C) 2017 Smart-Soft
*
* 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\ProxySSO\Api;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Core\Config;
/**
* 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";
}
@@ -0,0 +1,17 @@
<?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");
}
}
@@ -0,0 +1,70 @@
<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>
@@ -0,0 +1,15 @@
<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>
@@ -0,0 +1,19 @@
<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>
@@ -0,0 +1,13 @@
<form>
<field>
<id>username</id>
<label>Username</label>
<type>text</type>
</field>
<field>
<id>password</id>
<label>Password</label>
<type>password</type>
</field>
</form>
@@ -0,0 +1,8 @@
<menu>
<Services>
<WebProxy>
<ProxySSO VisibleName="Single Sign-On" cssClass="fa fa-shield fa-fw" order="26" url="/ui/proxysso/" />
</WebProxy>
</Services>
</menu>
@@ -0,0 +1,10 @@
<?php
namespace OPNsense\ProxySSO;
use OPNsense\Base\BaseModel;
class ProxySSO extends BaseModel
{
}
@@ -0,0 +1,21 @@
<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>
@@ -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>
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 %}
@@ -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 %}

Some files were not shown because too many files have changed in this diff Show More