Веб- приложение Java:Использование пользовательской области

StackOverflow https://stackoverflow.com/questions/719708

Вопрос

Я пишу веб-приложение 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, но, в принципе, нет причин для того, чтобы код отличался как-то иначе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top