Skip to content

Commit

Permalink
Merge branch '1.5' into Import-Subnets-to-Customer
Browse files Browse the repository at this point in the history
* 1.5:
  pull upstream 1.5
  Feature: Warn when php and db schema versions do not match
  Update php-saml (3.6.1) and xmlseclibs (3.1.1) submodules
  SAML JIT Provisioning (phpipam#3389)
  Bugfix: Fix remaining version-check comparisons.
  Bugfix: Fix 'New version available' widget
  Bugfix: 1.5.38 Upgrade SQL syntax error (<=MySQL 5.7)
  Bugfix: 1.5.38 Upgrade SQL syntax error (<=MySQL 5.7). Fixes phpipam#3443
  Feature: dbschema 38
  Refactor: Cleanup upgrade_queries
  Bugfix: Database stored sessions require the php_sessions table to exist (dbversion>=3)
  Update changelog. Fix escape_input()
  Bugfix: SAML return to same page when session expires.
  • Loading branch information
4o66 committed Nov 15, 2021
2 parents 6b25875 + 36c2481 commit f068a70
Show file tree
Hide file tree
Showing 22 changed files with 369 additions and 186 deletions.
9 changes: 9 additions & 0 deletions app/admin/authentication-methods/edit-SAML2.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@
</tr>

<!-- Advanced Settings -->
<tr>
<td><?php print _('Enable JIT'); ?></td>
<td>
<input type="checkbox" class="input-switch" value="1" name="jit" <?php if(@$method_settings->params->jit == 1) print 'checked'; ?> <?php print $is_disabled; ?> >
</td>
<td class="info2">
<?php print _('Provision new users automatically'); ?><br>
</td>
</tr>
<tr>
<td><?php print _('Use advanced settings'); ?></td>
<td>
Expand Down
24 changes: 19 additions & 5 deletions app/admin/authentication-methods/edit-result.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,29 @@
"type" =>$_POST['type'],
"description" =>@$_POST['description'],
);

# Validate input
if (isset($_POST['type']) && $_POST['type']=="SAML2") {
# The JIT & SAML mapped user options are mutually exclusive.
if (filter_var($_POST['jit'], FILTER_VALIDATE_BOOLEAN) && !empty($_POST['MappedUser'])) {
$Result->show("danger", _("The JIT and mapped user options are mutually exclusive"), true);
}

# Validate Prettify links is enabled for strict mode.
if (filter_var($_POST['strict'], FILTER_VALIDATE_BOOLEAN) && !filter_var($User->settings->prettyLinks, FILTER_VALIDATE_BOOLEAN)) {
$Result->show("danger", _("Strict mode requires global setting \"Prettify links\"=yes"), true);
}

# Verify that the private certificate and key are provided if Signing Authn Requests is set
if($action!="delete" && filter_var(['spsignauthn'], FILTER_VALIDATE_BOOLEAN) && (empty($_POST['spx509cert']) || empty($_POST['spx509key']))) {
$Result->show("danger", _("SP (Client) certificate and key are required to sign Authn requests"), true);
}
}

# remove processed params
unset($_POST['id'], $_POST['type'], $_POST['description'], $_POST['action']);
$values["params"]=json_encode($_POST);

#Verify that the private certificate and key are provided if Signing Authn Requests is set
if($action!="delete" && @$_POST['spsignauthn']=="1" && (empty($_POST['spx509cert']) || empty($_POST['spx509key']))) {
$Result->show("danger", _("SP (Client) certificate and key are required to sign Authn requests"), true);
}

$secure_keys=[
'adminUsername',
'adminPassword',
Expand Down
68 changes: 44 additions & 24 deletions app/admin/version-check/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,40 @@
print "<h4>phpIPAM version check</h4><hr>";

# get latest version */
if(!$version = $Tools->check_latest_phpipam_version(true)) { $Result->show("danger", _("Version check failed").'!', false); }
else {
$version = $Tools->check_latest_phpipam_version(true);
$version_delta = is_string($version) ? $Tools->cmp_version_strings(VERSION_VISIBLE, $version) : 0;

if(is_string($version)) {
//print result
if(VERSION_VISIBLE == $version) { $Result->show("success", _('Latest version').' ('. VERSION_VISIBLE .') '._('already installed').'!', false); }
else if (VERSION_VISIBLE > $version) { $Result->show("success", _('Development version').' ('. VERSION_VISIBLE .') '._('installed! Latest production version is').' '. $version, false);}
else { $Result->show("danger", _('New version of phpipam available').':</b><hr>'._('Installed version').': '.VERSION_VISIBLE."<br>"._('Available version').': '. $version."<br><br>"._('You can download new version'). " <a href='https://github.com/phpipam/phpipam/releases/tag/v$version'>"._('GitHub').'</a>' . ' ( '._('archive').' <a href="https://sourceforge.net/projects/phpipam/files/current/phpipam-'. $version .'.tar/download">'._('SourceForge').'</a> ).', false); }
if($version_delta == 0) { $Result->show("success", _('Latest version').' ('. VERSION_VISIBLE .') '._('already installed').'!', false); }
else if ($version_delta > 0) { $Result->show("success", _('Development version').' ('. VERSION_VISIBLE .') '._('installed! Latest production version is').' '. $version, false);}
else { $Result->show("danger", _('New version of phpipam available').':</b><hr>'._('Installed version').': '.VERSION_VISIBLE."<br>"._('Available version').': '. $version."<br><br>"._('You can download new version'). " <a href='https://github.com/phpipam/phpipam/releases/tag/v$version'>"._('GitHub').'</a>' . ' ( '._('archive').' <a href="https://sourceforge.net/projects/phpipam/files/current/phpipam-'. $version .'.tar/download">'._('SourceForge').'</a> ).', false); }
} else {
$Result->show("danger", _("Version check failed").'!', false);
}

if ($Tools->cmp_version_strings(VERSION, $User->settings->version) != 0) {
$Result->show("danger", _("Incompatible php and database schema versions").": php=v".VERSION.", db=v".$User->settings->version, false);
}

# Show version info
print "<table class='ipaddress_subnet table-condensed table-auto'>";
print "<tbody>";
print "<tr><th>"._("Latest phpIPAM release")."</th><td>".(is_string($version) ? $version : _("Version check failed"))."</td></tr>";
print "<tr><th>"._("Installed phpIPAM release")."</th><td>".VERSION_VISIBLE."</td></tr>";
print "<tr><th>"._("Database schema version")."</th><td>".$User->settings->version." dbversion ".$User->settings->dbversion."</td></tr>";
print "<tr><th>"._("PHP version")."</th><td>".phpversion()."</td></tr>";
print "<tr><th>"._("MySQL version")."</th><td>".$Tools->fetch_mysql_version()."</td></tr>";
print "<tr><th>"._("MySQL CTE queries")."</th><td>".($Database->is_cte_enabled() ? _("Yes") : _("No"))."</td></tr>";
print "</tbody>";
print "</table><br>";

# release and commit logs
print "<ul class='nav nav-tabs log-tabs'>";
print "<li role='presentation' class='active'><a href='' data-target='changelog'>Change log</a></li>";
if(!is_null($Tools->phpipam_releases))
print "<li role='presentation'> <a href='' data-target='releaselog'>Release log</a></li>";
if (VERSION_VISIBLE > $version)
if ($version_delta > 0)
print "<li role='presentation'> <a href='' data-target='gitlog'>Commit log (local)</a></li>";
print "</ul>";

Expand All @@ -39,28 +59,28 @@


# release log
if(!is_null($Tools->phpipam_releases)) {
print "<div class='log-print releaselog' style='display:none'>";
print "<h4 style='margin-top:40px;'>Release log</h4><hr>";
foreach ($Tools->phpipam_releases as $r) {
// pre-release ?
$prerelease = !is_numeric(str_replace(array("Version", "."), "", $r->title)) ? "<span class='label label-danger'>Prerelease</span>" : "";

// title
print "<h5><i class='fa fa-angle-double-right'></i> $r->title $prerelease</h5>";
// date
print "<div style='padding-left:20px;margin-bottom:20px;'>";
print "<span class='text-muted'>Released on ".date("Y-M-d", strtotime($r->updated))."</span> ";
print "<div style='padding-top:10px;'>$r->content</div>";
// tag
print "<a class='btn btn-xs btn-default' href='".$r->link->{'@attributes'}->href."'>Download (GitHub)</a>";
if(!empty($Tools->phpipam_releases)) {
print "<div class='log-print releaselog' style='display:none'>";
print "<h4 style='margin-top:40px;'>Release log</h4><hr>";
foreach ($Tools->phpipam_releases as $r) {
// pre-release ?
$prerelease = !is_numeric(str_replace(array("Version", "."), "", $r->title)) ? "<span class='label label-danger'>Prerelease</span>" : "";

// title
print "<h5><i class='fa fa-angle-double-right'></i> $r->title $prerelease</h5>";
// date
print "<div style='padding-left:20px;margin-bottom:20px;'>";
print "<span class='text-muted'>Released on ".date("Y-M-d", strtotime($r->updated))."</span> ";
print "<div style='padding-top:10px;'>$r->content</div>";
// tag
print "<a class='btn btn-xs btn-default' href='".$r->link->{'@attributes'}->href."'>Download (GitHub)</a>";
print "</div>";
}
print "</div>";
}
print "</div>";
}

# commit log for devel
if (VERSION_VISIBLE > $version) {
if ($version_delta > 0) {

print "<div class='log-print gitlog' style='display:none'>";

Expand Down
2 changes: 1 addition & 1 deletion app/login/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// try to authenticate
$User->authenticate ($_SERVER['PHP_AUTH_USER'], '');
// Redirect user where he came from, if unknown go to dashboard.
if( !empty($_COOKIE['phpipamredirect']) ) { header("Location: ".escape_input($_COOKIE['phpipamredirect'])); }
if( !empty($_COOKIE['phpipamredirect']) ) { header("Location: ".safeurlencode($_COOKIE['phpipamredirect'])); }
else { header("Location: ".create_link("dashboard")); }
exit();
}
Expand Down
109 changes: 107 additions & 2 deletions app/saml2/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,120 @@
// Extract username from attribute
$attr = $auth->getAttribute($params->UserNameAttr);
$username = is_array($attr) ? $attr[0] : '';
$username_source = "getAttribute(".escape_input($params->UserNameAttr).")";
} else {
// Extract username from NameId
$username = $auth->getNameId();
$username_source = "getNameId()";
}

$User->authenticate ($username, '', true);
// Validate username
if (!isset($username) || !is_string($username) || strlen($username)==0) {
$Result->show("danger", _("Could not extract valid username from SAML response")." : ".$username_source, true);
}

// Attempt JIT if enabled
if(filter_var($params->jit, FILTER_VALIDATE_BOOLEAN)) {

//
// Auto provision users via SAML attributes
//
// - "display_name", (String), MANDATORY
// Users real name / full name.
// Can not be blank.
//
// - "email", (String), MANDATORY
// Users email address.
// Can not be blank. Must pass filter_var($email, FILTER_VALIDATE_EMAIL).
//
// - "is_admin", (Boolean), OPTIONAL, default: 0
// User role, "Administrator" or "Normal User".
//
// - "groups", (String), OPTIONAL (Admins have admin level access to all groups), default: ""
// Comma separated list of group membership.
// e.g "groups"="Operators,Guests"
//
// - "modules", (String), OPTIONAL (Admins have admin level access to all modules), default: ""
// Comma separated list of modules with permission level, 0=None, 1=Read, 2=Read/Write, 3=Admin
// "*" can be used to wildcard match all modules.
// e.g The following will assign admin permissions to the vlan module and read permissions to everything else.
// "modules" = "*:1,vlan:3"

if (empty($auth->getAttribute("display_name")[0])) {
$Result->show("danger", _("Mandatory SAML JIT attribute missing")." : display_name (string)", true);
}
elseif (!filter_var($auth->getAttribute("email")[0], FILTER_VALIDATE_EMAIL)) {
$Result->show("danger", _("Mandatory SAML JIT attribute missing")." : email (string)", true);
}

$values = [];

$existing_user = $User->fetch_object("users", "username", $username);

if (is_object($existing_user)) {
// User exists in DB. Check this is a SAML account.

if ($existing_user->authMethod != $dbobj->id) {
$Result->show("danger", _("Requested SAML user is not configured for SAML authentication")." : ".escape_input($username), true);
}

$action = "edit";
$values["id"] = $existing_user->id;
}
else {
// User does not exist in DB. Auto-provision user.

$action = "add";
$values["username"] = $username;
$values["authMethod"] = $dbobj->id;
$values["lang"] = $User->settings->defaultLang;
}

$values["real_name"] = $auth->getAttribute("display_name")[0];
$values["email"] = $auth->getAttribute("email")[0];
$values["role"] = filter_var($auth->getAttribute("is_admin")[0], FILTER_VALIDATE_BOOLEAN) ? "Administrator" : "User";

// Parse groups
$saml_groups = array_map('trim', explode(',', $auth->getAttribute("groups")[0])) ? : [];

$ug = [];
foreach ($Tools->fetch_all_objects("userGroups", "g_id") as $g) {
if (in_array($g->g_name, $saml_groups)) {
$ug[$g->g_id] = $g->g_id;
}
}
$values["groups"] = json_encode($ug);

//parse modules
$saml_modules = [];
foreach(explode(',', $auth->getAttribute("modules")[0]) as $entry){
if (strpos($entry, ":")!==false) {
list($module_name, $module_perm) = array_map('trim', explode(':', $entry)) ? : ['', 0];
$saml_modules[$module_name] = filter_var($module_perm, FILTER_VALIDATE_INT, ["options"=>["default"=>0, "min_range"=>0, "max_range"=>3]]);
}
}

$um = [];
foreach($User->get_modules_with_permissions() as $module) {
// Allow "*" wildcard
if (array_key_exists('*', $saml_modules)) {
$um[$module] = $saml_modules['*'];
}
if (array_key_exists($module, $saml_modules)) {
$um[$module] = $saml_modules[$module];
}
}
$values["module_permissions"] = json_encode($um);

// Construct admin object for helper functions
$Admin = new Admin($Database, false);
if (!$Admin->object_modify("users", $action, "id", $values)) { $Result->show("danger", _("Failed to create/update SAML JIT user")." : ".escape_input($username), true); }
}

$User->authenticate ($username, '', true);

// Redirect user where he came from, if unknown go to dashboard.
if( !empty($_COOKIE['phpipamredirect']) ) { header("Location: ".escape_input($_COOKIE['phpipamredirect'])); }
if( !empty($_COOKIE['phpipamredirect']) ) { header("Location: ".safeurlencode($_COOKIE['phpipamredirect'])); }
else { header("Location: ".create_link("dashboard")); }

}
8 changes: 7 additions & 1 deletion app/sections/menu/menu-tools-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
$Tools->update_phpipam_checktime ();
} else {
# new version available
if ($User->settings->version < $version) {
if ($Tools->cmp_version_strings(VERSION_VISIBLE, $version) < 0) {
print "<li>";
print " <a href='".create_link("administration","version-check")."' class='icon-li btn-warning' rel='tooltip' data-placement='bottom' title='"._('New version available')."'><i class='fa fa-bullhorn'></i><sup>$version</sup></a>";
print "</li>";
Expand All @@ -191,6 +191,12 @@
}
}
}

if ($User->is_admin(false) && $Tools->cmp_version_strings(VERSION, $User->settings->version) != 0) {
print "<li>";
print " <a href='".create_link("administration","version-check")."' class='icon-li btn-danger' rel='tooltip' data-placement='bottom' title='"._("Incompatible php and database schema versions")."'><i class='fa fa-bullhorn'></i><sup>".$User->settings->version."</sup></a>";
print "</li>";
}
?>

</ul>
5 changes: 0 additions & 5 deletions app/upgrade/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,6 @@
* LAST_POSSIBLE //last possible for upgrade
*/

# default dbversion for older releases
if(!isset($User->settings->dbversion)) {
$User->settings->dbversion = 0;
}

# authenticated, but not admins
if (!$User->is_admin(false)) {
# version is ok
Expand Down
4 changes: 2 additions & 2 deletions config.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@
/**
* Cookie SameSite settings ("None", "Lax"=Default, "Strict")
* - "Strict" increases security
* - "Lax" required for SAML2
* - "None" requires HTTPS
* - "Lax" required for SAML2, some SAML topologies may require "None".
* - "None" requires HTTPS (implies "Secure;")
*/
$cookie_samesite = "Lax";

Expand Down
8 changes: 8 additions & 0 deletions config.docker.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ function file_env($var, $default) {
******************************/
$debugging = filter_var(file_env('IPAM_DEBUG', $debugging), FILTER_VALIDATE_BOOLEAN);

/**
* Cookie SameSite settings ("None", "Lax"=Default, "Strict")
* - "Strict" increases security
* - "Lax" required for SAML2, some SAML topologies may require "None".
* - "None" requires HTTPS (implies "Secure;")
*/
$cookie_samesite = file_env('COOKIE_SAMESITE', $cookie_samesite);

/**
* Session storage - files or database
*
Expand Down
2 changes: 1 addition & 1 deletion css/bootstrap/bootstrap-custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ table#subnetsMenu td#subnetsLeft .menu-tools {
margin-top: 6px;

margin-left: -1px;
width: 35px;
min-width: 35px;
text-align: center;

-webkit-border-radius: 3px;
Expand Down
Loading

0 comments on commit f068a70

Please sign in to comment.