2016-03-23 2 views
3

У меня есть встроенный сервер причала, который выполняет итерацию через список webapps (список зависит от развертывания) из разных мест. Я пытаюсь сделать переход от базовой аутентификации к формированию аутентификации.Single Sign On Jetty с несколькими экземплярами WebAppContext

То, что я хотел бы сделать что-то вроде:

// create constraint 
Constraint usersOnly = new Constraint(Constraint.__FORM_AUTH, "user"); 
usersOnly.setAuthenticate(true); 
ConstraintMapping requireAuthentication = new ConstraintMapping(); 
requireAuthentication.setConstraint(usersOnly); 
requireAuthentication.setPathSpec("/*"); 

// create login service 
LoginService loginService = new HashLoginService("realm"); 
loginService.setConfig("users.txt"); 

// create form authentication 
FormAuthenticator formAuthenticator = new FormAuthenticator("/login", "/login", true); 

// create /login route 
ServletHolder loginServlet = new ServletHolder(new DefaultServlet() { 
@Override 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
    response.getWriter().append("<html>\n<head>\n<title>Login</title>\n</head>\n<body>\n" 
    + "<form method='POST' action='/j_security_check'>\n" 
    + "<input type='text' name='j_username'/>\n" 
    + "<input type='password' name='j_password'/>\n" 
    + "<input type='submit' value='Login'/>\n</form>\n</body>\n</html>\n"); 
    } 
}); 

ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler(); 
securityHandler.addMapping(requireAuthentication); 
securityHandler.setLoginService(loginService); 
securityHandler.setAuthenticator(formAuthenticator); 

// assign security to each webapp 
for (WebAppContext webapp : webapps) { 
    webapp.setSecurityHandler(securityHandler); 
    webapp.addServlet(loginServlet, "/login"); 
} 

Это работает как хотелось бы, если есть только один веб-приложение в WebApps, но если есть несколько, вы получите приглашение на вход в каждый раз, когда вы будете следовать ссылку с одного webapp на другой, и каждый раз, когда вы повторно проверяете подлинность, вы перенаправляетесь на базовый webapp по маршруту «/» и проверяетесь только для этого.

Я хочу, чтобы мои контексты делились сессиями.

В соответствии с this question, имеющий общий SessionManager для каждого экземпляра WebAppContext, должен решить проблему, но у asker был только один экземпляр WebAppContext. Если я попытаюсь назначить один экземпляр SessionManager для каждого WebAppContext, я получаю NPE.

Я также видел, что некоторые ресурсы указывают на установление пути SessionCookieConfig каждого контекста к общему пути контекста и useRequestedId к true для каждого SessionManager WebAppContext, но это решение для org.mortbay.jetty и устарело.

Если у вас есть понимание или опыт настройки SSO для встроенного сервера причала с несколькими WebAppContexts, или если вы можете подумать о том, как лучше обслуживать несколько разных веб-приложений с одним общим сервером, пожалуйста, укажите мне в правильном направлении ,

Как я могу позволить пользователю пройти аутентификацию во всех веб-папках, обрабатываемых одним сервером, заполнив одну форму?

Сообщите мне, если я не буду чист или если у вас возникнут вопросы.

+0

Вы спрашиваете, как продлить безопасность на контейнере Jetty (JAAS разновидности сообщений формы) для нескольких приложений, запущенных на сервере Jetty? – Richard

+0

Да, особенно с единым входом. –

+0

Хорошо. У меня нет опыта. Но если все остальное не удалось, вы можете сделать свою безопасность «в приложении», а не «в контейнере». Использование таких вещей, как фильтры и т. Д. Существует много доступных фильтров безопасности, весенняя безопасность и т. Д., Которые сделают это для вас. Конкретно, что контейнер отправляет пользователя в сервлет формы и что после этого ваш пользователь не будет перенаправлен на свой исходный URL-адрес? – Richard

ответ

0

Моим решением было расширить класс HashSessionManager, чтобы он запрашивал SessionIdManager перед созданием нового сеанса. В результате экземпляры CrossContextSessionManager под одним и тем же SessionIdManager используют общий доступ к содержимому сеанса, а не только идентификаторы сеанса. Таким образом, вход в один webapp означает вход в них для всех.

import java.util.Collection; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpSession; 

import org.eclipse.jetty.server.session.AbstractSession; 
import org.eclipse.jetty.server.session.HashSessionIdManager; 
import org.eclipse.jetty.server.session.HashSessionManager; 

/** 
* Allows the WebAppContext to check the server's SessionIdManager before creating a new session 
* so that WebAppContext can share session contents for each client rather than just session ids. 
*/ 
public class CrossContextSessionManager extends HashSessionManager { 

    // Number of seconds before the user is automatically logged out of an idle webapp session 
    private int defaultSessionTimeout = 1800; 

    /** 
    * Check for an existing session in the session id manager by the requested id. 
    * If no session has that id, create a new HttpSession for the request. 
    */ 
    @Override 
    public HttpSession newHttpSession(HttpServletRequest request) { 
    AbstractSession session = null; 

    String requestedId = request.getRequestedSessionId(); 
    if (requestedId != null) { 
     String clusterId = getSessionIdManager().getClusterId(requestedId); 
     Collection<HttpSession> sessions = ((HashSessionIdManager) getSessionIdManager()).getSession(clusterId); 
     for (HttpSession httpSession : sessions) { 
     session = (AbstractSession) httpSession; 
     break; 
     } 
    } 

    if (session == null) { 
     session = newSession(request); 
     session.setMaxInactiveInterval(defaultSessionTimeout); 
     addSession(session,true); 
    } 

    return session; 
    } 
} 

Если запрос уже содержит идентификатор, newSessionId просто вытащит из него этот идентификатор. В противном случае он создаст новый идентификатор, уникальный из всех существующих идентификаторов.

+0

Как и где вы инициализируете этот CrossContextSessionManager? Мы используем контейнер Equinox OSGI, который запускает встроенный запуск Jetty. Поэтому мне интересно, где я могу подключиться к процессу запуска, чтобы передать этот CrossContextSessionManager. Не могли бы вы поделиться некоторыми фрагментами кода, показывающими, как вы это инициализируете? – Christoph

+0

для (WebAppContext webapp: webapps) { CrossContextSessionManager sessionManager = new CrossContextSessionManager(); SessionHandler sessionHandler = новый SessionHandler (sessionManager); webapp.setSessionHandler (sessionHandler); } –