まず、この長い投稿についてお詫び申し上げます。これは、この問題に関する以前の質問 ( 7u21 の更新後に認証が必要なウィンドウがポップアップする) の続きですが、検索を絞り込みました。要するに、私のBASIC認証はJava 7u21以降壊れているようです。
JNLP ファイルを介して開始されたアプレットは、まったく安定して機能しておらず、認証ポップアップ ウィンドウが表示されます。
セットアップ
まず、ユーザーテーブルとグループテーブルを使用してMySQL データベースをセットアップしました。
- 表: 認証
- 表: グループ
次に、Glassfishで jdbcRealm をセットアップしました。JNDI を使用しているため、データベース ユーザーとデータベース パスワード フィールドが空であることに注意してください (以下を参照)。
Glassfish レルム設定:
JDNI 構成(domain.xml ファイルに示されているとおり):
<jdbc-connection-pool connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" wrap-jdbc-objects="false" res-type="javax.sql.DataSource" name="mysql_mit_rohhPool">
<property name="URL" value="jdbc:mysql://localhost:3306/mit?zeroDateTimeBehavior=convertToNull"></property>
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="Password" value="****"></property>
<property name="portNumber" value="3306"></property>
<property name="databaseName" value="mit"></property>
<property name="User" value="****"></property>
<property name="serverName" value="localhost"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="mysql_mit_rohhPool" jndi-name="jdbc/DB_MIT"></jdbc-resource>
これが完了したら、デフォルトのレルムを新しく作成されたjdbcRealmに変更し、デフォルトのプリンシパルからロールへのマッピングを確認しました。
テスト
その後、テストのために、データベースからいくつかの国をフェッチし、BASIC 認証用にweb.xmlを構成する単純な WebService を Netbeans で作成しました。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>ServletAdaptor</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<description>Multiple packages, separated by semicolon(;), can be specified in param-value</description>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>service</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletAdaptor</servlet-name>
<url-pattern>/webresources/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<security-constraint>
<display-name>Basic Protection</display-name>
<web-resource-collection>
<web-resource-name>REST</web-resource-name>
<description/>
<url-pattern>/webresources/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>dummy</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>jdbcRealm</realm-name>
</login-config>
<security-role>
<description>Dummy</description>
<role-name>dummy</role-name>
</security-role>
Web サービスをテストするために、NetBeans で右クリックし、Test RESTful Web Serviceをクリックしました。新しい Internet Explorer ウィンドウが開き、ログイン画面が表示されます。ダミーユーザーの資格情報を入力すると、すべてが機能します。
次に、国を取得する単純な JavaFX FXML プロジェクトを作成します。次のようなクラス(Jerseyを使用する)があります。これは、Netbeans 7.3 によって生成されたコードです。
private WebResource webResource;
private Client client;
private static final String BASE_URI = "http://localhost:8080/myWS/webresources";
public CountriesClient() {
com.sun.jersey.api.client.config.ClientConfig config = new com.sun.jersey.api.client.config.DefaultClientConfig();
client = Client.create(config);
webResource = client.resource(BASE_URI).path("entities.countries");
}
public void close() {
client.destroy();
}
public void setUsernamePassword(String username, String password) {
client.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
}
public <T> T findAll_XML(Class<T> responseType) throws UniformInterfaceException {
WebResource resource = webResource;
return resource.accept(javax.ws.rs.core.MediaType.APPLICATION_XML).get(responseType);
}
私の FXML コントローラ ファイルでは、次のメソッドをボタンにリンクしています。
@FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
CountriesClient c = new CountriesClient();
c.setUsernamePassword("dummy", "****");
String r = c.findAll_XML(String.class);
System.out.println(r);
c.close();
}
それは私のプロジェクトのセットアップについてです。ここで、これを Netbeans 内でテストするか、*.jar ファイルから起動すると、すべてが意図したとおりに機能し、次の出力が得られます。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><countriess><countries><country>Belgium</country><id>1</id></countries><countries><country>Ireland</country><id>2</id></countries><countries><country>United Kingdom</country><id>3</id></countries><countries><country>Poland</country><id>4</id></countries></countriess>
ただし、 *.jnlp ファイルからアプレットを起動するとすぐに、資格情報について不平を言う迷惑なポップアップが表示されます。
Java コンソールには次のように記録されます。
network: Cache entry found [url: http://localhost:8080/myWS/webresources/entities.countries, version: null] prevalidated=false/0
cache: Adding MemoryCache entry: http://localhost:8080/myWS/webresources/entities.countries
cache: Resource http://localhost:8080/myWS/webresources/entities.countries has expired.
cache: Resource http://localhost:8080/myWS/webresources/entities.countries has cache control: no-cache.
network: Connecting http://localhost:8080/myWS/webresources/entities.countries with proxy=DIRECT
network: Connecting socket://localhost:8080 with proxy=DIRECT
network: Firewall authentication: site=localhost/127.0.0.1:8080, protocol=http, prompt=jdbcRealm, scheme=basic
network: ResponseCode for http://localhost:8080/myWS/webresources/entities.countries : 401
network: Encoding for http://localhost:8080/myWS/webresources/entities.countries : null
network: Connecting http://localhost:8080/myWS/webresources/entities.countries with proxy=DIRECT
basic: JNLP2ClassLoader.findClass: com.sun.jersey.core.header.InBoundHeaders: try again ..
basic: JNLP2ClassLoader.findClass: com.sun.jersey.core.util.StringKeyStringValueIgnoreCaseMultivaluedMap: try again ..
network: Downloading resource: http://localhost:8080/myWS/webresources/entities.countries
Content-Length: 322
Content-Encoding: null
network: Wrote URL http://localhost:8080/myWS/webresources/entities.countries to File C:\Users\stbrunee\AppData\LocalLow\Sun\Java\Deployment\cache\6.0\6\4b456206-236d2196-temp
cache: MemoryCache replacing http://localhost:8080/myWS/webresources/entities.countries (refcnt=0). Was: URL: http://localhost:8080/myWS/webresources/entities.countries | C:\Users\stbrunee\AppData\LocalLow\Sun\Java\Deployment\cache\6.0\6\4b456206-15cb0b99.idx Now: URL: http://localhost:8080/myWS/webresources/entities.countries | C:\Users\stbrunee\AppData\LocalLow\Sun\Java\Deployment\cache\6.0\6\4b456206-236d2196.idx
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><countriess><countries><country>Belgium</country><id>1</id></countries><countries><country>Ireland</country><id>2</id></countries><countries><country>United Kingdom</country><id>3</id></countries><countries><country>Poland</country><id>4</id></countries></countriess>
サーバー側 (glassfish ログ)
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/entities.countries" "GET")
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] Codesource with Web URL: file:/myWS/myWS
FINE: [Web-Security] Checking Web Permission with Principals : null
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
FINEST: JACC Policy Provider: PolicyWrapper.implies, context (myWS/myWS)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET"))
FINE: [Web-Security] hasResource isGranted: false
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/entities.countries" "HEAD")
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] Codesource with Web URL: file:/myWS/myWS
FINE: [Web-Security] Checking Web Permission with Principals : null
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "HEAD")
FINEST: JACC Policy Provider: PolicyWrapper.implies, context (myWS/myWS)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "HEAD"))
FINE: [Web-Security] hasResource isGranted: false
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "HEAD")
//NOW I PRESS CANCEL AT THE POPUP WINDOW CLIENT SIDE
FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = myWS/myWS
FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/entities.countries" "GET")
FINE: [Web-Security] hasUserDataPermission isGranted: true
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] Codesource with Web URL: file:/myWS/myWS
FINE: [Web-Security] Checking Web Permission with Principals : null
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
FINEST: JACC Policy Provider: PolicyWrapper.implies, context (myWS/myWS)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET"))
FINE: [Web-Security] hasResource isGranted: false
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
FINEST: Processing login with credentials of type: class com.sun.enterprise.security.auth.login.common.PasswordCredential
FINE: Logging in user [dummy] into realm: jdbcRealm using JAAS module: jdbcRealm
FINE: Login module initialized: class com.sun.enterprise.security.auth.login.JDBCLoginModule
FINEST: JDBC login succeeded for: dummy groups:[dummy]
FINE: JAAS login complete.
FINE: JAAS authentication committed.
FINE: Password login succeeded for : dummy
FINE: Set security context as user: dummy
FINE: [Web-Security] Policy Context ID was: myWS/myWS
FINE: [Web-Security] Codesource with Web URL: file:/myWS/myWS
FINE: [Web-Security] Checking Web Permission with Principals : dummy, dummy
FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
FINE: [Web-Security] hasResource isGranted: true
FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/entities.countries" "GET")
私が本当に理解していないことがいくつかあります:
- クライアント側では、承認されていないことを意味する 401 応答コードが表示されます。Web サービスのテストに使用する資格情報とまったく同じ資格情報を使用すると、これはどのようになりますか?
- クライアント側で、認証ポップアップ ウィンドウでキャンセルを押した場合、ユーザーが適切に認証されていないにもかかわらず、要求から XML データを受け取るのはなぜですか?
- サーバー側では、まだ認証プロセスが行われています。これは、これが Java でコーディングされているという事実と関係がありますか? 繰り返しますが、認証プロセスが実際に成功した場合、認証ポップアップがクライアント側に表示されるのはなぜですか?