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

Я пишу веб-приложение java, которое необходимо выполнить для входа через веб-сервис. Конечно, ни одна из сфер, поставляемых с сервером приложений, который я использую (glassfish v2), не может сделать трюк. Поэтому я должен был написать свое. Тем не менее, похоже, что реализация области, которую я написал, полностью привязана к стеклянной рыбке и не может использоваться как на других серверах приложений.

Существует ли стандартный или широко поддерживаемый способ реализации пользовательского Realm? Разве можно каким-либо образом развернуть эту область из .war, или ее всегда нужно загружать из собственного пути к классу сервера?

Ответы

Ответ 1

ПРИМЕЧАНИЕ. Ответ ниже действителен только для Java EE 5. Как было доведено до моего сведения в одном из других ответов, Java EE 6 поддерживает это. Поэтому, если вы используете Java EE 6, не читайте этот ответ, но прочитайте другой соответствующий ответ.

Из моего собственного исследования и ответов на этот вопрос я нашел следующее: Хотя JAAS является стандартным интерфейсом, нет единого способа записи, развертывания и интеграции JAAS Realm + LoginModule на разных серверах приложений.

Glassfish v2 требует, чтобы вы расширили некоторые из своих внутренних классов, которые сами внедряют LoginModule или Realm. Однако вы не можете настроить весь процесс входа в систему, потому что многие методы интерфейса LoginModule отмечены как final в суперклассе Glassfish. Пользовательские классы LoginModule и Realm должны быть помещены в путь AS-пути (а не в приложение), и область должна быть зарегистрирована вручную (развертывание из .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, который в стеклянном стекле v2 находится на вашем домене /config/login.conf. Добавьте следующие строки в конец этого файла:

myWebserviceRealm { // use whatever String is returned from you realm getJAASContext() method
    my.auth.login.WebserviceLoginModule required;
};

Вот что заставило меня работать на стеклянную рыбку. Опять же, это решение не переносится на всех серверах приложений, но, насколько я могу судить, нет портативного решения.

Ответ 2

Существует ли стандартный или широко поддерживаемый способ реализации пользовательского Realm? Разве можно каким-либо образом развернуть эту область из .war или всегда ли нужно загружаться из собственного пути к классу сервера?

Существует абсолютно стандартный способ реализации пользовательского Realm, или в более общих терминах - настраиваемый модуль аутентификации. Это можно сделать с помощью JASPIC/JASPI/JSR 196 SPI/API. JASPIC является стандартной частью любой полной реализации Java EE 6, но, к сожалению, не является частью веб-профиля Java EE 6.

Однако, несмотря на то, что JASPIC является частью Java EE 6, он не оптимально поддерживается поставщиками. GlassFish и WebLogic, похоже, имеют очень хорошие реализации, JBoss AS и Geronimo немного сложнее. Ведущий инженер JBoss на эту тему (Anil Saldhana) даже заявил, что он отказывается активировать 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, к сожалению, имеет какое-то состояние гонки в своей программной регистрации, поэтому вам нужно уродливое обходное решение, сделав горячее развертывание дважды, но в конце концов, если он загружает модуль из .war.

Как и в отношении проприетарных механизмов, по крайней мере JBoss AS всегда поддерживал загрузку модуля (например, подкласс org.jboss.security.auth.spi.AbstractServerLoginModule) из .war или .ear.

I написал сообщение в блоге об этой теме в последнее время, которая содержит более подробную информацию.

Ответ 3

Вы никогда не сможете развернуть область из WAR, потому что область не является артефактом приложения, это артефакт контейнера (таким образом, фраза "безопасность на основе контейнера" ). Вы можете настроить приложение на использование определенной области, предоставляемой контейнером, но приложение не может обеспечить это самостоятельно.

Тем не менее, в то время как все контейнеры различны, и эти сферы НЕ переносятся, простой здравый смысл уменьшит различия до небольшого количества кода клея, необходимого для интеграции с контейнером, если вы ищете переносимость.

Ответ 4

Имея быстрый взгляд на документацию Suns, похоже, вам придется написать пользовательский LoginModule, который расширяет свой класс сервера приложений. Это кажется немного отсталым для меня и ограничением Glassfish.

Если вы хотите сделать это более переносимым, я бы предложил разместить основную часть реализации в пользовательском LoginModule, разработанном против стандартного интерфейса (ов) JavaEE, а затем с тонким уровнем реализации, специфичным для Glassfish, который делегирует стандарту, переносимая реализация.

Ответ 5

Отметьте статья Sun по этому вопросу.

Я никогда не делал этого сам, но я уверен, что каждый AS дает вам возможность регистрировать на нем новые сферы (домены безопасности).

Он, вероятно, не будет переносимым на 100%, и для каждого AS вам может понадобиться другой конфигурационный XML-код, но в принципе нет причин для того, чтобы код был другим.