WSO2IS passport-saml SLO, Ошибка при создании AuthRequest из закодированной строки
В настоящее время я использую WSO2-IS 5.4.1 с passport-saml для реализации SSO и SLO. В то время как единый вход работает правильно, я не могу правильно настроить полный однократный выход из системы.
Я запутался в нескольких вещах, если честно
- Почему WSO2IS отправляет запрос на выход для SP, который инициировал выход? Это действие НЕ фиксируется в запросе SAML, но IS указано в ошибке терминала IdP, показанной ниже.
- 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:47135] ОТЛАДКА {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] DEBUG {org.wso2.carbon.identity.sso.saml.builders.Sign01 ключ ключа 10:44:47163] ОТЛАДКА {org.wso2.carbon.identity.sso.saml.servlet.SAMLSSOProviderServlet} - строка запроса: SLO = истина & SAMLRequest = nVFLS8QwEP4rJfdtm272NbRdF4pQWD2oePAioc26hTRTM1P15xu7KyyCHoS5ZOZ7ZSbffvQ2ejOeOnSFkHEqtmVOurcD7PEFR74zr6MhjgLOEUyTQozeAWrqCJzuDQE3cL% 2B72UMWpzB4ZGzQigvK3wxNZDyHACKqq0I8b5aLTaN0dlCtXmmZzlu1Ft Hjd8hACUCi0dSOWDsOrVSuZ% 2BlilsoHqUCFWsUyWz6JqArZO6d5Yh6ZB4Iksdhoe0Ri2Cg1T74SEuGWLBbsRyNOG4DJw% 2F% 2FjG% 2BU7YaaHIU8udM6it4FXV9E1% 2Bl7z74IyllOna2eHCQqm153dta03RKIcg5e86sICZNxgf3Y6iZen148Llp8% 3D [2018-05-01 10:44:47169] ОТЛАДКА {org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} - это logoutReqSenderTask назначается к пул потоков [2018-05-01 10:44:47,169] DEBUG {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] 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} - Ошибка при создании 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(выход из системы).wso2.carbon.identity.sso.saml.logout.LogoutRequestSender$LogoutReqSenderTask.run(LogoutRequestSender.java:234) в java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) в java.til..FutureTask.run(FutureTask.java:266) в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) в java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoavaEx6.) lang.Thread.run(Thread.java:748) [2018-05-01 10:44:47,376] ОШИБКА {org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender} - Ошибка отправки запросов на выход из системы по адресу: ht 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 $ LogoutReqSenderTaskseid LogoutRequestSender.java:280) в org.wso2.carbon.identity.sso.saml.logout.LogoutRequestSender$LogoutReqSenderTask.run(LogoutRequestSender.java:234) в java.util.concurrent.Executors $ RunnableAdapter. 511) в java.util.concurrent.FutureTask.run(FutureTask.java:266) в java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) в java.util.concurrent.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: содержимое не разрешено в прологе". связано с чрезмерным количеством пробелов, я не уверен, как или почему этот запрос генерируется? Буду признателен за любую оказанную помощь.