define('AUTH_TYPE_EXTERNAL_REMOTE_USER', 4);
define('AUTH_TYPE_EXTERNAL_X_FORWARDED_USER', 5);
+define('AUTH_TYPE_SAML', 6);
// Passwd-auth related ----
. '&url_after_login=' . rawurlencode($url_after_login);
header('HTTP/1.0 302 Found');
header('Location: ' . $loginurl);
- } elseif (AUTH_TYPE_EXTERNAL === $auth_type) {
+ } elseif (AUTH_TYPE_EXTERNAL === $auth_type ||
+ AUTH_TYPE_SAML === $auth_type) {
$url_after_login = get_script_uri() . '?' . $g_query_string;
$loginurl = get_auth_external_login_url($page, $url_after_login);
header('HTTP/1.0 302 Found');
case AUTH_TYPE_EXTERNAL:
case AUTH_TYPE_EXTERNAL_REMOTE_USER:
case AUTH_TYPE_EXTERNAL_X_FORWARDED_USER:
+ case AUTH_TYPE_SAML:
break;
default:
// $auth_type is not valid, Set form auth as default
}
case AUTH_TYPE_FORM:
case AUTH_TYPE_EXTERNAL:
+ case AUTH_TYPE_SAML:
{
session_start();
$user = '';
$dynamic_groups = $_SESSION['dynamic_member_groups'];
} else {
$fullname = $user;
- if ($auth_type === AUTH_TYPE_EXTERNAL && $ldap_user_account) {
+ if (($auth_type === AUTH_TYPE_EXTERNAL || $auth_type === AUTH_TYPE_SAML) &&
+ $ldap_user_account) {
$ldap_user_info = ldap_get_simple_user_info($user);
if ($ldap_user_info) {
$fullname = $ldap_user_info['fullname'];
global $auth_provider_user_prefix_default;
global $auth_provider_user_prefix_ldap;
global $auth_provider_user_prefix_external;
+ global $auth_provider_user_prefix_saml;
$user_prefix = '';
switch ($auth_type) {
case AUTH_TYPE_BASIC:
case AUTH_TYPE_EXTERNAL_X_FORWARDED_USER:
$user_prefix = $auth_provider_user_prefix_external;
break;
+ case AUTH_TYPE_SAML:
+ $user_prefix = $auth_provider_user_prefix_saml;
+ break;
case AUTH_TYPE_FORM:
if ($ldap_user_account) {
$user_prefix = $auth_provider_user_prefix_ldap;
$script = get_script_uri(); // Init automatically
}
+// INI_FILE: Auth settings
+if (isset($auth_type) && $auth_type === AUTH_TYPE_SAML) {
+ $auth_external_login_url_base = get_script_uri() . '?//cmd.saml//sso';
+}
+
+
/////////////////////////////////////////////////
// INI_FILE: $agents: UserAgentの識別
$vars = array_merge($_GET, $_POST); // Considered reliable than $_REQUEST
}
+/**
+ * Parse specified format query_string as params.
+ *
+ * For example: ?//key1.value2//key2.value2
+ */
+function parse_query_string_ext($query_string) {
+ $vars = array();
+ $m = null;
+ if (preg_match('#^//[^&]*#', $query_string, $m)) {
+ foreach (explode('//', $m[0]) as $item) {
+ $sp = explode('.', $item, 2);
+ if (isset($sp[0])) {
+ if (isset($sp[1])) {
+ $vars[$sp[0]] = $sp[1];
+ } else {
+ $vars[$sp[0]] = '';
+ }
+ }
+ }
+ }
+ return $vars;
+}
+if (isset($g_query_string) && $g_query_string) {
+ if (substr($g_query_string, 0, 2) === '//') {
+ // Parse ?//key.value//key.value format query string
+ $vars = array_merge($vars, parse_query_string_ext($g_query_string));
+ }
+}
+
+
// 入力チェック: 'cmd=' and 'plugin=' can't live together
if (isset($vars['cmd']) && isset($vars['plugin']))
die('Using both cmd= and plugin= is not allowed');
--- /dev/null
+<?php
+// PukiWiki - Yet another WikiWikiWeb clone.
+// saml.inc.php
+// Copyright
+// 2017 PukiWiki Development Team
+// License: GPL v2 or (at your option) any later version
+//
+// PukiWiki SAML Plugin
+
+require 'vendor/autoload.php';
+require_once 'vendor/onelogin/php-saml/_toolkit_loader.php';
+
+define('PLUGIN_SAML_AUTHUSER_ID_ATTR', 'UserId');
+define('PLUGIN_SAML_AUTHUSER_DISPLAYNAME_ATTR', 'DisplayName');
+
+/**
+ * SAML Handler
+ */
+function plugin_saml_action() {
+ global $vars;
+ require 'saml_settings.php';
+
+ $auth = new OneLogin_Saml2_Auth($settingsInfo);
+
+ if (isset($vars['sso'])) {
+ // sso: Sign in endpoint before IdP
+ $url_after_login = $vars['url_after_login'];
+ $auth->login($url_after_login);
+ } else if (isset($vars['slo'])) {
+ // sso: Sign out endpoint before IdP
+ $returnTo = null;
+ $paramters = array();
+ $nameId = null;
+ $sessionIndex = null;
+ if (isset($_SESSION['samlNameId'])) {
+ $nameId = $_SESSION['samlNameId'];
+ }
+ if (isset($_SESSION['samlSessionIndex'])) {
+ $sessionIndex = $_SESSION['samlSessionIndex'];
+ }
+ $auth->logout($returnTo, $paramters, $nameId, $sessionIndex);
+ } else if (isset($vars['acs'])) {
+ // acs: Sign in endpoint after IdP
+ $auth->processResponse();
+
+ $errors = $auth->getErrors();
+
+ if (!empty($errors)) {
+ return array('msg' => 'SAML Error', print_r('<p>'.implode(', ', $errors).'</p>'));
+ }
+
+ if (!$auth->isAuthenticated()) {
+ return array('msg' => 'SAML sign in', 'body' => '<p>Not authenticated</p>');
+ }
+ $attrs = $auth->getAttributes();
+ $_SESSION['samlUserdata'] = $attrs;
+ $_SESSION['samlNameId'] = $auth->getNameId();
+ $_SESSION['samlSessionIndex'] = $auth->getSessionIndex();
+ if (isset($attrs[PLUGIN_SAML_AUTHUSER_ID_ATTR][0])) {
+ // PukiWiki ExternalAuth requirement
+ $_SESSION['authenticated_user'] = $attrs[PLUGIN_SAML_AUTHUSER_ID_ATTR][0];
+ } else {
+ $_SESSION['authenticated_user'] = $auth->getNameId();
+ }
+ if (isset($attrs[PLUGIN_SAML_AUTHUSER_DISPLAYNAME_ATTR][0])) {
+ // PukiWiki ExternalAuth requirement
+ $_SESSION['authenticated_user_fullname'] = $attrs[PLUGIN_SAML_AUTHUSER_DISPLAYNAME_ATTR][0];
+ }
+
+ if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) {
+ $auth->redirectTo($_POST['RelayState']);
+ }
+ return array('msg' => 'SAML sign in', 'body' => 'SAML Sined in. but no redirection');
+ } else if (isset($vars['sls'])) {
+ // sls: Sign out endpoint after IdP
+ // onelone/php-saml only supports Redirect SingleLogout
+ $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
+ if ($is_post) {
+ session_destroy();
+ $_SESSION = array();
+ } else {
+ $auth->processSLO();
+ $errors = $auth->getErrors();
+ $msg = '';
+ if (empty($errors)) {
+ $msg .= '<p>Sucessfully logged out</p>';
+ } else {
+ $msg .= '<p>'.implode(', ', $errors).'</p>';
+ }
+ }
+ return array('msg' => 'SAML sign out', 'body' => 'SAML Sined out. ' . $msg);
+ } else if (isset($vars['metadata'])) {
+ // metadata: SP metadata endpoint
+ try {
+ $auth = new OneLogin_Saml2_Auth($settingsInfo);
+ $settings = $auth->getSettings();
+ $metadata = $settings->getSPMetadata();
+ $errors = $settings->validateMetadata($metadata);
+ if (empty($errors)) {
+ header('Content-Type: text/xml');
+ echo $metadata;
+ } else {
+ throw new OneLogin_Saml2_Error(
+ 'Invalid SP metadata: '.implode(', ', $errors),
+ OneLogin_Saml2_Error::METADATA_SP_INVALID
+ );
+ }
+ } catch (Exception $e) {
+ echo $e->getMessage();
+ }
+ exit;
+ }
+ return array('msg' => 'Error', 'body' => 'SAML Invalid state srror');
+}