В настоящее время я использую WSO2-IS 5.4.1 с passport-saml для реализации SSO и SLO. Хотя единый вход работает правильно, я не могу правильно настроить полный однократный выход из системы.
Я запутался в нескольких вещах, если честно
- Почему WSO2IS отправляет запрос на выход для SP, который инициировал выход? Это действие НЕ фиксируется в запросе SAML, но IS указано в ошибке терминала IdP, показанной ниже. * * 1006
- samlStrategy.logout также выполняет локальный выход из системы или просто формирует запрос и перенаправляет его на WSO2IS, кажется, позже, когда я регистрирую запрос? Я спрашиваю, потому что весь пример кода, который я рассмотрел, содержит req.logout () в обратном вызове выхода из системы, но я получаю req.isAuthenticated () как ложное, ДО того, как я req.logout () в / wso2app / logout / callback post.
Приложение правильно перенаправляет на URL-адрес WSO2IS saml, а WSO2IS отправляет обратно к обратному вызову в конфигурации моего приложения. WSO2IS также успешно выходит из системы, но, похоже, отправляет ненужный SLO-запрос обратно в приложение узла. См. Ссылку на изображение ниже для конфигурации узла SP в IdP.
Конфигурация узла приложения в WSO2IS
Основная ошибка, сгенерированная в терминале IdP с помощью saml DEBUG:
[2018-05-01 10: 44: 47,135] ОТЛАДКА
{org.wso2.carbon.identity.sso.saml.servlet.SAMLSSOProviderServlet} -
Строка запроса :
SLO = истина & SAMLRequest = nVFLS8QwEP4rJfdtm272NbRdF4pQWD2oePAioc26hTRTM1P15xu7KyyCHoS5ZOZ7ZSbffvQ2ejOeOnSFkHEqtmVOurcD7PEFR74zr6MhjgLOEUyTQozeAWrqCJzuDQE3cL% 2B72UMWpzB4ZGzQigvK3wxNZDyHACKqq0I8b5aLTaN0dlCtXmmZzlu1FtHjd8hACUCi0dSOWDsOrVSuZ% 2BlilsoHqUCFWsUyWz6JqArZO6d5Yh6ZB4Iksdhoe0Ri2Cg1T74SEuGWLBbsRyNOG4DJw% 2F% 2FjG% 2BU7YaaHIU8udM6it4FXV9E1% 2Bl7z74IyllOna2eHCQqm153dta03RKIcg5e86sICZNxgf3Y6iZen148Llp8% 3D
[2018-05-01 10: 44: 47,140] ОТЛАДКА
{org.wso2.carbon.identity.sso.saml.builders.SignKeyDataHolder} -
Инициализация ключевых данных для супер-арендатора с использованием хранилища системных ключей
[2018-05-01 10: 44: 47,163] ОТЛАДКА
{org.wso2.carbon.identity.sso.saml.servlet.SAMLSSOProviderServlet} -
Строка запроса :
SLO = истина & SAMLRequest = nVFLS8QwEP4rJfdtm272NbRdF4pQWD2oePAioc26hTRTM1P15xu7KyyCHoS5ZOZ7ZSbffvQ2ejOeOnSFkHEqtmVOurcD7PEFR74zr6MhjgLOEUyTQozeAWrqCJzuDQE3cL% 2B72UMWpzB4ZGzQigvK3wxNZDyHACKqq0I8b5aLTaN0dlCtXmmZzlu1FtHjd8hACUCi0dSOWDsOrVSuZ% 2BlilsoHqUCFWsUyWz6JqArZO6d5Yh6ZB4Iksdhoe0Ri2Cg1T74SEuGWLBbsRyNOG4DJw% 2F% 2FjG% 2BU7YaaHIU8udM6it4FXV9E1% 2Bl7z74IyllOna2eHCQqm153dta03RKIcg5e86sICZNxgf3Y6iZen148Llp8% 3D
[2018-05-01 10: 44: 47,169] ОТЛАДКА
{org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} - A
logoutReqSenderTask назначается пулу потоков [2018-05-01
10: 44: 47,169] ОТЛАДКА
{} Org.wso2.carbon.identity.sso.saml.session.SSOSessionPersistenceManager
- Извлеченный индекс сеанса из идентификатора сеанса с индексом сеанса 6ffb8168-3022-4d77-9ecc-3bc168d6c5da [2018-05-01 10: 44: 47,345] DEBUG
{org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} -
один запрос на выход отправляется по адресу:
http://localhost:3000/wso2app/logout/callback возвращается с перемещением
Временно [2018-05-01 10: 44: 47,348] ОТЛАДКА
{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} - Ошибка в
конструирование AuthRequest из закодированной строки
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)
в
org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender $ LogoutReqSenderTask.validateResponse (LogoutRequestSender.java:280)
в
org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender $ LogoutReqSenderTask.run (LogoutRequestSender.java:234)
в
java.util.concurrent.Executors $ RunnableAdapter.call (Executors.java:511)
в java.util.concurrent.FutureTask.run (FutureTask.java:266) в
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1149)
в
java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:624)
at java.lang.Thread.run (Thread.java:748) [2018-05-01 10: 44: 47,376]
ОШИБКА {org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} -
Ошибка отправки запросов на выход:
http://localhost:3000/wso2app/logout/callback
org.wso2.carbon.identity.base.IdentityException: ошибка в построении
AuthRequest от закодированной строки в
org.wso2.carbon.identity.base.IdentityException.error (IdentityException.java:60)
в
org.wso2.carbon.identity.sso.saml.util.SAMLSSOUtil.unmarshall (SAMLSSOUtil.java:305)
в
org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender $ LogoutReqSenderTask.validateResponse (LogoutRequestSender.java:280)
в
org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender $ LogoutReqSenderTask.run (LogoutRequestSender.java:234)
в
java.util.concurrent.Executors $ RunnableAdapter.call (Executors.java:511)
в java.util.concurrent.FutureTask.run (FutureTask.java:266) в
java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1149)
в
java.util.concurrent.ThreadPoolExecutor $ Worker.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 сразу же перенаправляется в / wso2app / logout после аутентификации IdP, это только для тестирования.
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-запрос Примечание. Это правильный SLO-запрос, отправляемый приложением узла в IdP, который захватывается инструментом браузера SAML. Запрос mystery slo, отправленный обратно в приложение из IdP, задокументирован только в ошибке терминала IdP.
Я просмотрел несколько сообщений, но не смог найти ни одного, связанного с моей проблемой. Загадочная природа запроса на выход из системы, отправленного на http://localhost:3000/wso2app/logout/callback, касается, но, опять же, я не понимаю, почему он даже отправляется. Кажется, это не соответствует официальному потоку SLO, показанному здесь Я читал, что «[Фатальная ошибка]: 1: 1: Контент не разрешен в прологе». связано с чрезмерным количеством пробелов, я не уверен, как или почему этот запрос генерируется? Любая помощь очень ценится.