私は現在、SSO と SLO を実装するために、passport-saml で WSO2-IS 5.4.1 を使用しています。シングル サインオンは正しく機能していますが、完全なシングル ログアウトを適切に構成できないようです。
正直なところ、いくつかのことで混乱しています
- ログアウトを開始した SP に WSO2IS がログアウト要求を送信するのはなぜですか? このアクションは SAML リクエストではキャプチャされませんが、以下に示す IdP ターミナル エラーに記載されています。
- samlStrategy.logout もローカル ログアウトを実行しますか、それとも単にリクエストを作成して WSO2IS にリダイレクトするだけですか? 私が確認したすべてのサンプル コードには、ログアウト コールバックに req.logout() が含まれていますが、/wso2app/logout/callback ポストで req.logout() を行う前に、req.isAuthenticated() を false として取得しています。
アプリは WSO2IS saml URL に正しくリダイレクトされ、WSO2IS はアプリ構成のコールバックにポストバックします。WSO2IS もユーザーのログアウトに成功しましたが、不要な SLO 要求をノード アプリに送り返しているようです。IdP のノード SP 構成については、以下の画像リンクを参照してください。
saml DEBUG を使用して IdP ターミナルで生成される主なエラー:
[2018-05-01 10:44:47,135] DEBUG {org.wso2.carbon.identity.sso.saml.servlet.SAMLSSOProviderServlet} - Query string : slo=true&SAMLRequest=nVFLS8QwEP4rJfdtm272NbRdF4pQWD2oePAioc26hTRTM1P15xu7KyyCHoS5ZOZ7ZSbffvQ2ejOeOnSFkHEqtmVOurcD7PEFR74zr6MhjgLOEUyTQozeAWrqCJzuDQE3cL%2B72UMWpzB4ZGzQigvK3wxNZDyHACKqq0I8b5aLTaN0dlCtXmmZzlu1FtHjd8hACUCi0dSOWDsOrVSuZ%2BlilsoHqUCFWsUyWz6JqArZO6d5Yh6ZB4Iksdhoe0Ri2Cg1T74SEuGWLBbsRyNOG4DJw%2F%2FjG%2BU7YaaHIU8udM6it4FXV9E1% 2Bl7z74IyllOna2eHCQqm153dta03RKIcg5e86sICZNxgf3Y6iZen148Llp8%3D [2018-05-01 10:44:47,140] DEBUG {org.wso2.carbon.identity.sso.saml.builders.SignKeyDataHolder} - システム キー ストアを使用したスーパーのキー データの初期化 [2018-tenant1 10:44:47,163] DEBUG {org.wso2.carbon.identity.sso.saml.servlet.SAMLSSOProviderServlet} - クエリ文字列: slo=true&SAMLRequest=nVFLS8QwEP4rJfdtm272NbRdF4pQWD2oePAioc26hTRTM1P15xu7KyyCHoS5ZOZ7ZSbffvQ2ejOeOnSFkHEqtmVOurcD7PEFR74zr6MhjgLOEUyTQozeAWrqCJzuDQE3cL%2B72UMWpzB4ZGzQigvK3wxNZDyHACKqq0I8b5aLTaN0dlCtXmmZzlu1FtHjd8hACUCi0dSOWDsOrVSuZ%2BlilsoHqUCFWsUyWz6JqArZO6d5Yh6ZB4Iksdhoe0Ri2Cg1T74SEuGWLBbsRyNOG4DJw%2F%2FjG%2BU7YaaHIU8udM6it4FXV9E1%2Bl7z74IyllOna2eHCQqm153dta03RKIcg5e86sICZNxgf3Y6iZen148Llp8%3D [2018-05-01 10:44:47,169] DEBUG {org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} - A logoutReqSenderTaskスレッド プールに割り当てられています [2018-05-01 10:44:47,169] DEBUG {org.wso2.carbon.identity.sso.saml.session.SSOSessionPersistenceManager} - セッション インデックス 6ffb8168-3022 のセッション ID からセッション インデックスを取得しました- 4d77-9ecc-3bc168d6c5da [2018-05-01 10:44:47,345] デバッグ {org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} - シングル ログアウト リクエストが次の宛先に送信されます。 http://localhost:3000/wso2app/logout/callbackMoved Temporarily [2018-05-01 10:44:47,348] DEBUG {org.wso2.carbon.identity.sso.saml.util.SAMLSSOUtil} - リクエスト メッセージ ��u�����)ඈm�� で返されます ����,�}4��.qǬ��Z�� [致命的なエラー] :1:1: プロローグではコンテンツを使用できません。[2018-05-01 10:44:47,368] エラー {org.wso2.carbon.identity.sso.saml.util.SAMLSSOUtil} - エンコードされた文字列 org.xml.sax.SAXParseException から AuthRequest を構築する際のエラー: コンテンツがありませんプロローグで許可されています。org.apache.xerces.parsers.DOMParser.parse(不明なソース) org.apache.xerces.jaxp.DocumentBuilderImpl.parse(不明なソース) javax.xml.parsers.DocumentBuilder.parse(不明なソース) org.wso2 org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender$LogoutReqSenderTask. http://localhost:3000/wso2app/logout/callback run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 原因: org.xml.sax.SAXParseException: コンテンツはプロローグで許可されていません。org.apache.xerces.parsers.DOMParser.parse(不明なソース) org.apache.xerces.jaxp.DocumentBuilderImpl.parse(不明なソース) javax.xml.parsers.DocumentBuilder.parse(不明なソース) org.wso2 .carbon.identity.sso.saml.util.SAMLSSOUtil.unmarshall(SAMLSSOUtil.java:298) ... 7 もっと見る
ノードアプリ。user1 は IdP によって認証されるとすぐに /wso2app/logout にリダイレクトされることに注意してください。これはテスト用です。
const express = require('express');
const session = require('express-session');
const bodyParser = require('body-parser');
const passport = require('passport');
const SamlStrategy = require('passport-saml').Strategy;
const fs = require('fs');
const app = express();
// logger middleware
function logger(req,res,next){
console.log(req.method, req.url);
next();
}
app.use(logger);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
// express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
// passport middleware
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
const samlStrategy = new SamlStrategy({
issuer: 'wso2app',
// login endpoints
entryPoint: 'https://localhost:9443/samlsso',
callbackUrl: 'http://localhost:3000/wso2app/login/callback',
// logout endpoints
logoutUrl: 'https://localhost:9443/samlsso?slo=true',
logoutCallbackUrl: 'http://localhost:3000/success',
},
function(profile, done){
return done(null,{
// subject claim, SAML:1.1 dialect
Email: profile.nameID,
// requested claims, WSO2 internal dialect
FirstName: profile['http://wso2.org/claims/givenname'],
LastName: profile['http://wso2.org/claims/lastname'],
Organization: profile['http://wso2.org/claims/organization'],
Role: profile['http://wso2.org/claims/role'],
// slo attributes
nameID: profile.nameID,
nameIDFormat: profile.nameIDFormat
});
});
passport.use(samlStrategy);
app.get('/wso2app/login',
passport.authenticate('saml', {
successRedirect: '/wso2app',
failureRedirect: '/wso2app/login'
})
);
app.post('/wso2app/login/callback', passport.authenticate('saml', {
failureRedirect: '/wso2app/login',
failureFlash: true,
}),
function(req, res){
res.redirect('/wso2app')
}
);
app.get('/wso2app', function(req, res) {
if (!req.isAuthenticated()) {
res.redirect('/wso2app/login');
}
//parse domain from the user's email attribute in SAML response
const domain = req.user.Email.substring(req.user.Email.lastIndexOf("@") + 1);
console.log(domain);https://localhost:9443/samlsso?slo=true
//use domain as index router, send specific users to their respective url
switch(domain){
case 'inst1.com':
console.log(JSON.stringify(req.user));
//res.redirect('/wso2app/inst1/');
res.redirect('/wso2app/logout');
break;
case 'unv2.edu':
console.log(JSON.stringify(req.user));
res.redirect('/wso2app/unv2/');
break;
case 'inst3.com':
console.log(JSON.stringify(req.user));
res.redirect('/wso2app/inst3/');
break;
default:
res.send("You're Authenticated but Unaffiliated, Your Credentials: " + JSON.stringify(req.user));
}
});
app.get('/wso2app/logout', function(req, res){
console.log("req.user.nameID: " + req.user.nameID);
console.log("req.user.nameIDFormat: " + req.user.nameIDFormat);
if (req.isAuthenticated()) {
console.log("Still Auth in Node 1");
}
samlStrategy.logout(req, function(err, request){
if (!err) {
res.redirect(request);
console.log('request: ' + request);
}
});
});
app.post('/wso2app/logout/callback', function(req,res){
if (!req.isAuthenticated()) {
console.log("Already logged out");
}
req.logout();
res.redirect('http://localhost:3000/success');
});
app.listen(3000, function(){
console.log('Server Started on Port 3000');
});
SLO リクエスト注: これは、ノード アプリから IdP に送信される適切な SLO リクエストであり、SAML ブラウザ ツールによってキャプチャされます。IdP からアプリに送り返された謎の slo リクエストは、IdP ターミナル エラーにのみ記載されています。
複数の投稿を確認しましたが、私の問題に関連する投稿が見つかりません。http://localhost:3000/wso2app/logout/callbackに送信されるログアウト リクエストの不可解な性質が懸念されますが、これが送信される理由がわかりません。これは、ここに示されている公式の SLO フローに従っていないようです。「[致命的なエラー] :1:1: コンテンツはプロローグでは許可されていません。過剰な空白文字に関連していますが、このリクエストがどのように、またはなぜ生成されているのかわかりません。どんな助けでも大歓迎です。