注:以下の回答はJava EE 5にのみ有効です。他の回答の1つで私の注意を引いたように、JavaEE6はこれをサポートしています。したがって、Java EE 6を使用している場合は、この回答を読むのではなく、他の関連する回答を読んでください。
私自身の調査とこの質問への回答から、私が見つけた答えは次のとおりです。JAASは標準インターフェースですが、JAAS Realm + LoginModuleをさまざまなアプリケーションサーバーに記述、デプロイ、統合するための統一された方法はありません。
Glassfish v2では、LoginModuleまたはRealm自体を実装する独自の内部クラスのいくつかを拡張する必要があります。ただし、LoginModuleインターフェースの多くのメソッドがGlassfishのスーパークラスでfinalとマークされているため、ログインプロセス全体をカスタマイズすることはできません。カスタムLoginModuleクラスとRealmクラスは(アプリケーションではなく)ASクラスパスに配置する必要があり、レルムは手動で登録する必要があります(.warからの展開はできません)。
Tomcatの状況は少し良くなっているようです。これにより、独自のRealmとLoginModuleを完全にコーディングし、独自のJAASRealm(実際の作業をRealmとLoginModuleの実装に委任する)を使用してアプリケーションサーバーに構成できます。 。ただし、Tomcatでさえ、.warからカスタムレルムをデプロイすることはできません。
私の結果を示したアプリケーションサーバーのどれも、すべてのJAASコールバックを十分に活用できないようであることに注意してください。それらはすべて、基本的なユーザー名とパスワードのスキームのみをサポートしているようです。それよりも複雑なものが必要な場合は、JavaEEコンテナで管理されていないソリューションを見つける必要があります。
参考までに、そして私の質問へのコメントで求められたので、ここに私がGlassfishV2用に書いたコードがあります。
まず、レルムの実装は次のとおりです。
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構成ファイルレベルで実行されます。これは、glassfishv2ではyourDomain/ config/login.confにあります。そのファイルの最後に次の行を追加します。
myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
my.auth.login.WebserviceLoginModule required;
};
これが、Glassfishでうまく機能するようになった理由です。繰り返しになりますが、このソリューションはアプリケーションサーバー間で移植可能ではありませんが、私が知る限り、既存の移植可能なソリューションはありません。