Как стать автором
Обновить

Комментарии 11

В вашем примере с сервлетом для логина мы теряем одну из приятных вещей FORM аутентификации, а именно то, что контейнер вернет вас на тот урл, который вы ему скормили и для которого ему понадобилось проверить, кто вы. А у вас редиректит на index страницу :(

Есть еще нехорошая особенность, нет возможности при использовании FORM аутентификации при возникновении ошибки сообщить причину. Просто не залогинились и всё :( Только в лог будет нормальных LoginException записан, а дальше он не пройдёт.
По поводу редиректа на index… на самом деле мы можем редиректить на любую страницу, но, к сожалению, мне не удалось найти нигде адрес, к которому обратились, а referer содержит ту страницу, с которой прошли… Эта важная фича по какой-то причине труднореализуема.

По поводу причины: если вы используете FORM-аторизацию, то всё что вам остаётся, это покзать текст LoginExcepton. В условиях, когда LoginModule пишете вы, то вы же и можете класть в текст LoginException человеческое описание ошибки.
В нашем (который мы реализовали) LoginModule кидаются различные LoginException's (с разным текстом) в зависимости от причины.
Был бы признателен, если бы ты показал, как можно показать текст LoginExcepton'а.
А то у меня так и не получилось этого сделать. Я даже просматривал исходники GlassFish и нашел место в котором этот LoginException ловится и выводится в лог. После этого про него все забывают :(
У класса ProgramaticLogin есть несколько методов login. Важно установить параметр error = true, тогда исключение от LoginModule будет проброшено в наш сервлет:

fisheye5.cenqua.com/browse/glassfish/appserv-core/src/java/com/sun/appserv/security/ProgrammaticLogin.java?r=1.5#l164

В своём примере здесь я лювлю просто catch( Exception ) в блоке, где вызывается login, но можно поймать LoginException отдельно. К сожалению, пробрасывается не само исключение из LoginModule, а другое, но оригинальное исключение стоит в cause.
Например:
com.sun.enterprise.security.LoginException: Login failed: javax.security.auth.login.LoginException: bad login/password
        at com.sun.enterprise.security.auth.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:335)
        at com.sun.enterprise.security.auth.LoginContextDriver.login(LoginContextDriver.java:177)
        at com.sun.enterprise.security.auth.LoginContextDriver.login(LoginContextDriver.java:130)
        at com.sun.web.security.WebProgrammaticLogin.login(WebProgrammaticLogin.java:123)
        at com.sun.appserv.security.ProgrammaticLogin$2.run(ProgrammaticLogin.java:240)
        at java.security.AccessController.doPrivileged(Native Method)
        at com.sun.appserv.security.ProgrammaticLogin.login(ProgrammaticLogin.java:237)
        at cy6ergn0m.auth.LoginServlet.doPost(LoginServlet.java:57)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
        at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:427)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:315)
        at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648)
        at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096)
        at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579)
        at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
        at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
        at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
        at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
Caused by: javax.security.auth.login.LoginException: bad login/password
        at cy6ergn0m.auth.CGLoginModule.authenticateUser(CGLoginModule.java:33)
        at com.sun.appserv.security.AppservPasswordLoginModule.login(AppservPasswordLoginModule.java:184)
        at sun.reflect.GeneratedMethodAccessor62.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
        at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
        at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
        at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
        at com.sun.enterprise.security.auth.LoginContextDriver.doPasswordLogin(LoginContextDriver.java:319)
        ... 36 more

Здесь в этом stacktrace «javax.security.auth.login.LoginException: bad login/password» — это исключение, которое кидается в LoginModule, а текст bad «login/password» есть прямо в этой статье…
>> контейнер вернет вас на тот урл, который вы ему скормили и для которого ему понадобилось проверить, кто вы.
Если мы используем «j_security_check», то контейнер всё равно возвращает нас на index :(, так что URL всё равно теряется.
Нет. Если мы используем «j_security_check», то он нас вернет на тот ресурс, который мы запрашивали.
ananta.com/docs/j2eetutorial14/doc/Security5.html#wp483393
Сорри, что не самой первой свежести источник.
Трудно сказать в чём дело, но, к сожалению, фича не работает. Дело в том, что когда мы проходим на страницу логина, то в этот момент уже никак нельзя узнать о том, какую страницу хотели получить…
Мы используем такой LoginModule. Но, когда мы первоначально использовали «простой», то тоже всё работало.

  1. package .....;
  2. import com.sun.appserv.security.AppservPasswordLoginModule;
  3. import java.util.List;
  4. import java.util.logging.Level;
  5. import java.util.logging.Logger;
  6. import javax.security.auth.login.LoginException;
  7. import javax.security.jacc.PolicyContext;
  8. import javax.security.jacc.PolicyContextException;
  9. import javax.servlet.http.HttpServletRequest;
  10. /**
  11. *
  12. * @author ***
  13. */
  14. public class LoginModule extends AppservPasswordLoginModule {
  15. private static final Logger log = Logger.getLogger(LoginModule.class.getName());
  16. @Override
  17. protected void authenticateUser() throws LoginException {
  18. try {
  19. final HttpServletRequest request = (HttpServletRequest)PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
  20. final String xForwardedFor = request.getHeader("X-Forwarded-For");
  21. final String xForwardedHost = request.getHeader("X-Forwarded-Host");
  22. ....
  23. final List<String> roles = DbRealm.authenticate(_username, _password,… );
  24. if (roles == null || roles.size() == 0)
  25. throw new LoginException("User is not authenticated.");
  26. commitUserAuthentication(roles.toArray(new String[roles.size()]));
  27. } catch (PolicyContextException ex) {
  28. log.log(Level.SEVERE, ex.getMessage(), ex);
  29. throw new LoginException(ex.getMessage());
  30. }
  31. }
  32. }
У меня xForwardedFor и xForwardedHost = null…
По крайней мере, когда я писал эту статью — я проверял и у меня j_security_check отправлял на стартовую.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.