Веб- приложение Java:Использование пользовательской области
-
23-08-2019 - |
Вопрос
Я пишу веб-приложение Java, которому необходимо выполнить вход в систему через веб-сервис.Конечно, ни одна из областей, поставляемых с сервером приложений, который я использую (glassfish v2), не может выполнить это задание.Поэтому мне пришлось написать свой собственный.Однако, похоже, что реализация realm, которую я написал, полностью привязана к glassfish и не может использоваться так, как есть на любых других серверах приложений.
Существует ли какой-либо стандартный или широко поддерживаемый способ реализации пользовательской области?Возможно ли каким-либо образом развернуть эту область из .war, или ее всегда нужно загружать с собственного пути к классам сервера?
Решение
ПРИМЕЧАНИЕ:Приведенный ниже ответ действителен только для Java EE 5.Как было доведено до моего сведения в одном из других ответов, Java EE 6 поддерживает это.Поэтому, если вы используете Java EE 6, не читайте этот ответ, но прочитайте другой соответствующий ответ.
Исходя из моих собственных исследований и ответов на этот вопрос, я нашел следующий ответ:Хотя JAAS является стандартным интерфейсом, не существует единого способа написания, развертывания и интеграции JAAS Realm + LoginModule на различных серверах приложений.
Glassfish v2 требует, чтобы вы расширили некоторые из его собственных внутренних классов, которые сами реализуют LoginModule или Realm.Однако вы не можете настроить весь процесс входа в систему, поскольку многие методы интерфейса LoginModule помечены как final в суперклассе Glassfish.Пользовательские классы LoginModule и Realm должны быть помещены в AS classpath (не для приложения), а realm должна быть зарегистрирована вручную (развертывание из .war невозможно).
Ситуация, похоже, немного лучше для Tomcat, который позволит вам полностью закодировать ваши собственные Realm и LoginModule, а затем настроить их на сервере приложений, используя собственный JAASRealm (который делегирует фактическую работу вашим реализациям Realm и LoginModule).Однако даже tomcat не позволяет развернуть вашу пользовательскую область из вашего .war .
Обратите внимание, что ни один из серверов приложений, на которых были показаны мои результаты, похоже, не может в полной мере воспользоваться всеми обратными вызовами JAAS.Все они, похоже, поддерживают только базовую схему имя пользователя + пароль.Если вам нужно что-то более сложное, чем это, то вам нужно будет найти решение, которое не управляется вашим контейнером Java EE.
Для справки, а также потому, что об этом просили в комментариях к моему вопросу, вот код, который я написал для GlassfishV2.
Прежде всего, вот реализация Realm:
public class WebserviceRealm extends AppservRealm {
private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());
private String jaasCtxName;
private String hostName;
private int port;
private String uri;
@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
_logger.info("My Webservice Realm : init()");
// read the configuration properties from the user-supplied properties,
// use reasonable default values if not present
this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
this.hostName = props.getProperty("hostName", "localhost");
this.uri = props.getProperty("uri", "/myws/EPS");
this.port = 8181;
String configPort = props.getProperty("port");
if(configPort != null){
try{
this.port = Integer.parseInt(configPort);
}catch(NumberFormatException nfe){
log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
}
}
}
@Override
public String getJAASContext() {
return jaasCtxName;
}
public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
List groupNames = new LinkedList();
return (Enumeration) groupNames;
}
public String getAuthType() {
return "My Webservice Realm";
}
public String getHostName() {
return hostName;
}
public int getPort() {
return port;
}
public String getUri() {
return uri;
}
}
И затем реализация LoginModule:
public class WebserviceLoginModule extends AppservPasswordLoginModule {
// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately
@Override
protected void authenticateUser() throws LoginException {
if (_username == null || _password == null) {
throw new LoginException("username and password cannot be null");
}
String[] groups = this.getWebserviceClient().login(_username, _password);
// must be called as last operation of the login method
this.commitUserAuthentication(groups);
}
@Override
public boolean commit() throws LoginException {
if (!_succeeded) {
return false;
}
// fetch some more information through the webservice...
return super.commit();
}
private WebserviceClient getWebserviceClient(){
return theWebserviceClient;
}
}
наконец, в области должно быть привязано к LoginModule.Это делается на уровне файла конфигурации JAAS, который в glassfish v2 находится в yourDomain/config/login.conf.Добавьте следующие строки в конец этого файла:
myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
my.auth.login.WebserviceLoginModule required;
};
Это то, что заставило меня работать над glassfish.Опять же, это решение не является переносимым на серверы приложений, но, насколько я могу судить, переносимого решения не существует.
Другие советы
Существует ли какой-либо стандартный или широко поддерживаемый способ реализации пользовательского Realm?Возможно ли каким-либо образом развернуть эту область из .war, или всегда ли ее нужно загружать из собственного пути к классам сервера?
Абсолютно существует стандартный способ реализации пользовательской области, или, в более общих чертах, пользовательского модуля аутентификации.Это может быть сделано с помощью JASPIC/JASPI/JSR 196 SPI/API.JASPIC является стандартной частью любой полной реализации Java EE 6, но, к сожалению, не является частью веб-профиля Java EE 6.
Однако, несмотря на то, что JASPIC является частью Java EE 6, поставщики не обеспечивают его оптимальной поддержки.GlassFish и WebLogic, похоже, имеют очень хорошие реализации, JBoss AS и Geronimo немного более проблематичны.Ведущий инженер из JBoss по этой теме (Анил Салдхана) даже заявил, что он отказывается активировать JASPIC по умолчанию на данный момент.Несколько наиболее серьезных ошибок в Jboss AS 7.1 были недавно исправлено, но поскольку публичных релизов JBoss 7.1.x больше не запланировано, а до JBoss AS 7.2 еще некоторое время, это означает, что на данный момент, по крайней мере, на JBoss JASPIC, это проблематично.
Другая досадная проблема заключается в том, что фактический модуль аутентификации может быть стандартизирован, но не существует декларативного способа (чтение XML-файла) его стандартизированной настройки.
Возможно ли каким-либо образом развернуть эту область из .war, или это так всегда нужно загружать с собственного пути к классам сервера?
С JASPIC модуль аутентификации ('realm') действительно может быть загружен из .war.Я не уверен на 100%, гарантировано ли это спецификацией, но из 4 серверов, которые я тестировал (GlassFish, WebLogic, Geronimo и JBoss AS), все они поддерживали это.К сожалению, у Geronimo есть какое-то условие гонки при программной регистрации, поэтому вам нужен некрасивый обходной путь, выполнив горячее развертывание дважды, но в конце концов if загружает модуль из .war.
Что касается проприетарных механизмов, по крайней мере, JBoss AS всегда поддерживал загрузку модуля (напримерподкласс org.jboss.security.auth.spi.AbstractServerLoginModule) из .war или .ear.
Я написал сообщение в блоге об этой теме недавно, в которой есть еще некоторые подробности.
Вы никогда не сможете развернуть область из WAR, потому что область - это НЕ артефакт приложения, это артефакт контейнера (отсюда и фраза "безопасность на основе контейнера").Вы можете настроить свое приложение на использование определенной области, предоставляемой контейнером, но приложение не может предоставить это само.
Тем не менее, хотя все контейнеры разные, и эти области НЕ являются переносимыми, простой здравый смысл сведет различия к небольшому фрагменту связующего кода, необходимого для интеграции с контейнером, если вы ищете переносимость.
Бегло просмотрев документацию Suns, похоже, что вам придется написать пользовательский LoginModule, который расширяет класс, специфичный для их сервера приложений.Мне это кажется немного отсталым и является ограничением Glassfish.
Если вы хотите сделать это более переносимым, я бы предложил поместить основную часть реализации в пользовательский LoginModule, разработанный для стандартных интерфейсов JavaEE, а затем создать тонкий слой реализации, специфичный для Glassfish, который делегирует стандартную переносимую реализацию.
Проверьте Статья Sun на эту тему.
На самом деле я никогда не делал этого сам, но я почти уверен, что каждый AS дает вам возможность регистрировать на нем новые области (домены безопасности).
Вероятно, он не будет переносимым на 100%, и для каждого AS вам может понадобиться другой конфигурационный XML, но, в принципе, нет причин для того, чтобы код отличался как-то иначе.