【发布时间】:2020-04-15 19:51:18
【问题描述】:
背景:我正在尝试为用户设置单点登录 (SSO),以便他们可以对我的网站进行身份验证,而不必再次对我们的第三方 MSP 网站进行身份验证。理想情况下,用户单击我们网站上的链接并被带到已经登录并登陆仪表板的第三方网站(如果帐户不存在,则在此步骤中创建)。我们没有使用 SAML 作为安全功能进行身份验证,因此我们需要 SAML 代码的只是生成 cookie,以防止用户在访问我们供应商的站点时必须再次登录。此第三方 MSP 不支持通过 API 或 Web 服务进行身份验证,因此我的任务是实施 SAML,这是他们唯一支持的 SSO 方法。我是 SAML(但不是 PHP 或开发)的新手,并且一直在学习。我被告知它将支持上述目标。
我最初尝试使用 LDAP 作为身份验证源,因为这是我用于对我的网站进行身份验证的方式,但这导致我被定向到登录页面,而没有明显的方法可以将参数传递给 SimpleSAMLphp 来告诉它“用户已经通过身份验证,我需要你做的就是给我有效的 cookie,这样我就可以通过第三方网站的身份验证检查”。
所以我转而编写自定义身份验证模块。我打开了 SimpleSAMLphp 的 GitHub,并使用“UserPassBase”类作为示例来创建我自己的身份验证模块,该模块继承自“Source”类。因为我不需要再次针对 LDAP 重新验证用户,因为他们已经登录到我们的网站,所以我创建了一个简单的“验证”函数,它只设置 $state['Attributes'] 数组。
这是我的自定义模块的代码:
<?php
namespace SimpleSAML\Module\productauth\Auth\Source;
use SimpleSAML\Auth;
/**
Author: Joey
Class developed to be used as a custom authentication module for simpleSAMLphp. This class will take an existing session from a product website and use it to create a SAML session and redirect to a website.
**/
class ProductAuth extends \SimpleSAML\Auth\Source {
const STAGEID = '\SimpleSAML\Module\productauth\Auth\ProductAuth.state';
const AUTHID = '\SimpleSAML\Module\productauth\Auth\ProductAuth.AuthId';
private $user;
public function __construct($info, $config) { // parameters aren't used, just filler from base class
$info = array("AuthId" => "productauth");
parent::__construct($info, $config);
}
public function login($user, $redirectURL) {
$this->user = $user; // normally I'd set this in the constructor, but the overload has my hands tied as far as function definitions go
$this->initLogin($redirectURL); // calls authenticate function and then, if no exceptions, parent::loginCompleted which redirects to the given URL
}
public function authenticate(&$state) { // called by parent::initLogin
$state[self::AUTHID] = $this->authId;
$state['Attributes'] = [
'uid' => [$this->user->uid],
'givenName' => [$this->user->givenName],
'sn' => [$this->user->sn],
'mail' => [$this->user->mail]
];
$id = Auth\State::saveState($state, self::STAGEID);
}
}
?>
我从我网站上的控制器类调用它:
private function goToTrainingSite() {
require_once("../third-party-libs/simplesamlphp/_include.php");
global $TRAINING_URL;
$user = $_SESSION['subject']->user;
$samlObj = new SimpleSAML\Module\productauth\Auth\Source\ProductAuth(array(), array());
$samlObj->login($user, $TRAINING_URL);
}
我模仿了“UserPassBase”类 (https://github.com/simplesamlphp/simplesamlphp/blob/master/modules/core/lib/Auth/UserPassBase.php) 的流程,但似乎尽管我的所有身份验证都在工作并设置了 SimpleSAMLAuth cookie,但当“Source”类中的 parent::loginCompleted 函数 (@ 987654322@) 运行,它将我重定向到第三方站点。然后我在日志中看到以下内容:
SAML2.0 - IdP.SSOService:传入的身份验证请求:[已编辑数据]
会话:“productauth”无效,因为我们未通过身份验证。
我已经尝试了 3 天来弄清楚为什么尽管设置 SimpleSAML 会话 cookie 并完成了成功的身份验证,但在收到来自 SP 的身份验证请求后,我的 SimpleSAMLphp 代码只是假装不知道完成身份验证并尝试再次进行身份验证...但是因为它不是从我的代码中调用的,所以它无权访问 $user 变量,该变量包含我在用户进行身份验证时需要放置在用户身上的所有属性到这个第三方网站。似乎当它收到身份验证请求时,我的 SimpleSAMLphp 安装会启动一个新会话并尝试全新的身份验证。
我已经深入研究了 SimpleSAMLphp 的大量代码并试图了解发生了什么,但似乎没有合理的方法通过从 PHP 代码调用身份验证源并能够跳过 SP 来进行身份验证- 发起的认证。我试过了:
- 使用 SimpleSAML API (https://simplesamlphp.org/docs/stable/simplesamlphp-sp-api) 调用我的身份验证源,但似乎无法传递我需要属性的 $user 变量。
- 尝试在“Session”类检查有效会话时加载 cookie...但我的代码启动的成功身份验证会话中的 cookie 似乎消失了,无处可寻。李>
【问题讨论】:
标签: php single-sign-on saml simplesamlphp