Аутентификация через диалоговое окно входа в Scout (RAP)
Я хотел бы иметь аутентификацию, основанную на концепции безопасности скаутов по умолчанию, найденной в https://wiki.eclipse.org/Scout/Concepts/Security.
Что я сделал:
Я добавил BasicSecurityFilter
к серверам plugin.xml
:
<extension name="" point="org.eclipse.scout.rt.server.commons.filters">
<filter aliases="/ /process /remotefiles /updatesite" class="org.eclipse.scout.http.servletfilter.security.BasicSecurityFilter" ranking="30"></filter>
</extension>
И активировал его в config.ini
:
org.eclipse.scout.http.servletfilter.security.BasicSecurityFilter#active=true
org.eclipse.scout.http.servletfilter.security.BasicSecurityFilter#realm=Development
org.eclipse.scout.http.servletfilter.security.BasicSecurityFilter#users=TEST\=admin
На стороне клиента я добавил InternalNetAuthenticator
в plugin.xml
:
<extension point="org.eclipse.core.net.authenticator">
<authenticator class="org.eclipse.scout.rt.ui.rap.login.internal.InternalNetAuthenticator"</authenticator>
</extension>
И установите его как аутентификатор по умолчанию в клиенте Activator
:
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
plugin = this;
InternalNetAuthenticator authenticator = new InternalNetAuthenticator();
InternalNetAuthenticator.setDefault(authenticator);
}
Что просходит:
BasicSecurityFilter.negotiate()
вызывается при доступе к приложению (первая загрузка, например,http://localhost:8015/web
)InternalNetAuthenticator.getPasswordAuthentication()
называется, когда переговоры вBasicSecurityFilter
происходит сбой (это когда пользователь и пароль не найдены в заголовке HTTP или пользователь и пароль недействительны).- Открытие диалога на уровне RAP (см.
InternalNetAuthenticator.showModalDialog(status, display)
) невозможно, потому что Display.getDefault() или Display.getCurrent() всегда возвращаетnull
,- Это связано с тем, что все операции пользовательского интерфейса (например, открытие диалогового окна) ДОЛЖНЫ появляться в UIThread (см. Java-doc в
Display.getDefault()
). -
InternalNetAuthenticator
создается в UIThread (см.Activator.start()
), но это не называется в UIThread! Зачем???
- Это связано с тем, что все операции пользовательского интерфейса (например, открытие диалогового окна) ДОЛЖНЫ появляться в UIThread (см. Java-doc в
- Возвращение
PasswordAuthentication
Объект предоставляет учетные данные в заголовке HTTP для следующегоBasicSecurityFilter.negotiate()
вызов.
- Открытие диалога на уровне RAP (см.
BasicSecurityFilter.negotiate()
вызывается снова с заданными учетными данными.
Что не получается:
Так из-за того, что InternalNetAuthenticator.showModalDialog(status, display)
не вызывается в потоке пользовательского интерфейса, это вызывает NullPointerException
:
java.lang.NullPointerException
at org.eclipse.scout.rt.ui.rap.login.internal.InternalNetAuthenticator.showModalDialog(InternalNetAuthenticator.java:102)
...
Что я уже рассмотрел:
- Основная информация
https://wiki.eclipse.org/Scout/HowTo/3.9/Extending_the_login_dialog
https://wiki.eclipse.org/Scout/Concepts/Securit
- Проблема UI-потока
https://www.eclipse.org/forums/index.php/t/440290/
https://www.eclipse.org/rap/developers-guide/devguide.php?topic=threads.html
- Я уже пытался сохранить UI-поток при создании экземпляра Authenticator в
Activator.start()
метод путем создания собственного Authenticator и добавления параметра в конструктор, например:MyAuthenticator my_authenticator = new MyAuthenticator(Thread.currentThread());
- Но это вызывает
IllegelStateException
или что-то типа того. Таким образом, UI-поток не доступен на этом пути.
- С использованием
BasicSecurityFilter
на уровне RAP (вplugin.xml
пакета RAP) позволяет использовать системный диалог входа по умолчанию.- Но я хотел бы иметь собственный SecurityFilter, который имеет доступ к другим системам на стороне сервера, поэтому он должен отображаться на стороне сервера, а SecurityFilter на стороне RAP/client не подходит!
Резюме
Все, что я могу видеть, это то, что решение проблемы с UI-потоком будет предпочтительным способом продвинуть эту проблему вперед.
Я также приму альтернативные решения для создания собственного диалогового окна входа в мою среду eclipse-scout-RAP.
1 ответ
Описание проблемы:
Если я правильно понял ваш вариант использования, вы бы хотели ввести что-то вроде аутентификации на основе форм. Я предполагаю, что это то, чего вы хотели достичь, отображая диалог входа в RAP UI-Thread.
Предложение по решению:
Были предприняты некоторые шаги по внедрению аутентификации на основе форм в демонстрационном приложении BahBah Scout, которое можно найти в [1]. Обратите внимание, что этот пример основан на более старой версии Scout (3.10). В следующем объяснении будет упомянуто выполнение в [1]:
В [1] подход состоял в том, чтобы использовать средство веб-контейнера Tomcat для достижения аутентификации на основе форм. Пример страницы входа в HTML [2] можно найти в комплекте RAP UI в папке web-ресурсов. Поэтому в файле plugin.xml [3] приложения RAP фильтр сервлетов BasicForwardSecurityFilter был удален. Убедитесь, что веб-ресурсы доступны, например, в / res.
<extension point="org.eclipse.equinox.http.registry.resources">
<resource alias="/res" base-name="/web-resources"/>
</extension>
В файле приложения RAP web.xml были сделаны следующие записи.
<!-- Activate form-based authentication -->
<login-config>
<auth-method>FORM</auth-method>
<realm-name>BahBahJAASLogin</realm-name>
<form-login-config>
<form-login-page>/res/index.html</form-login-page>
<form-error-page>/res/index.html</form-error-page>
</form-login-config>
</login-config>
<!-- Define security role to access the application -->
<security-role>
<role-name>BahBahRolePrincipal</role-name>
</security-role>
<!-- static resources under /res/* should be accessible without requiring authentication -->
<security-constraint>
<web-resource-collection>
<web-resource-name>All Access</web-resource-name>
<url-pattern>/res/*</url-pattern>
<http-method>DELETE</http-method>
<http-method>PUT</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- Protect all other URLs of the application -->
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Resources</web-resource-name
<url-pattern>/web/*</url-pattern>
<url-pattern>/tablet/*</url-pattern>
<url-pattern>/mobile/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>BahBahRolePrincipal</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- Define security filter and mapping -->
<filter>
<filter-name>BahbahSecurityFilter</filter-name>
<filter-class>com.bsiag.securityfilter.BahbahSecurityFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BahbahSecurityFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
BahbahSecurityFilter гарантирует, что только проверенные участники могут получить доступ к защищенным ресурсам на сервере пользовательского интерфейса. В методе doFilter проверка выполняется путем вызова метода, подобного следующему:
// Taken from org.eclipse.scout.rt.server.commons.authentication.ServletFilterHelper#isRunningWithValidSubject(HttpServletRequest) see [4]
public boolean isRunningWithValidSubject(HttpServletRequest req) {
String username = req.getRemoteUser();
if (username == null || username.isEmpty()) {
return false;
}
Subject subject = Subject.getSubject(AccessController.getContext());
if (subject == null || subject.getPrincipals().isEmpty()) {
return false;
}
for (Principal principal : subject.getPrincipals()) {
if (username.equalsIgnoreCase(principal.getName())) {
return true;
}
}
return false;
}
В BahBahChat Realm [5] и модуль входа в систему настроены для аутентификации пользователей. В частности, определены UserPrincipal и RolePrincipal, а также создан класс LoginModule.
В файле contextcat.xml Tomcat настроена область.
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="BahBahJAASLogin"
userClassNames="com.bsiag.securityfilter.BahBahUserPrincipal"
roleClassNames="com.bsiag.securityfilter.BahBahRolePrincipal"/>
Наконец, файл jaas.config определен:
BahBahJAASLogin {
com.bsiag.securityfilter.BahBahJAASLoginModule required debug=true;
};
BahBahJAASLoginModule реализует для фактического процесса аутентификации. Хороший пример настройки аутентификации JAAS в Tomcat можно найти по адресу [6].
Пожалуйста, ознакомьтесь с сообщением на форуме Eclipse Scout [7], в котором кратко изложены необходимые шаги.
- [1] https://github.com/BSI-Business-Systems-Integration-AG/org.eclipsescout.demo/tree/features/kle/formBasedAuthentication
- [2]
org.eclipsescout.demo.bahbah.ui.rap/web-resources/index.html
- [3]
org.eclipsescout.demo.bahbah.ui.rap/plugin.xml
- [4] http://git.eclipse.org/c/scout/org.eclipse.scout.rt.git/tree/org.eclipse.scout.rt.server.commons/src/main/java/org/eclipse/scout/rt/server/commons/authentication/ServletFilterHelper.java?h=releases/5.2.x
- [5] https://tomcat.apache.org/tomcat-7.0-doc/realm-howto.html
- [6] http://www.byteslounge.com/tutorials/jaas-authentication-in-tomcat-example
- [7] https://www.eclipse.org/forums/index.php?t=msg&th=821196&goto=1435976msg_1435976.