Ответ 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;
};
Вот что заставило меня работать на стеклянную рыбку. Опять же, это решение не переносится на всех серверах приложений, но, насколько я могу судить, нет портативного решения.