基本身份验证失败与glassfish [英] basic authentication fails with glassfish

查看:158
本文介绍了基本身份验证失败与glassfish的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我对这个长篇帖子表示歉意。这是我以前的问题的延续(,其中声明


无存储的目的指令是为了防止无意中的
释放或保留敏感信息(例如,在备份
磁带上)。 no-store指令适用于整个消息,MAY
可以通过响应或请求发送。如果在请求中发送,
缓存不得存储此请求的任何部分或任何响应


我们会很好 - 网络嗅探器证明客户端正确地设置了Cache-Control头。另外Jersey的ContainerResponseFilter向我展示了请求上的标题设置正确。另一方面,响应没有Cache-Control标头集。根据规范应该没什么问题,但事实上Web Start一直在缓存响应!



因此,我编写了一个ContainerResponseFilter,它将请求中的Cache-Control头复制到回应:

  import com.sun.jersey.spi.container.ContainerRequest; 
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

import javax.ws.rs.core.HttpHeaders;
import java.util.ArrayList;
import java.util.List;

public class CacheControlCopyFilter
implements ContainerResponseFilter
$ b @Override
public ContainerResponse过滤器(ContainerRequest containerRequest,ContainerResponse containerResponse){
if(containerRequest。 getRequestHeader(HttpHeaders.CACHE_CONTROL)!= null){
List< Object> responseCacheControlValues = new ArrayList< Object>(containerRequest.getRequestHeader(HttpHeaders.CACHE_CONTROL).size());
for(String value:containerRequest.getRequestHeader(HttpHeaders.CACHE_CONTROL)){
responseCacheControlValues.add(value);
}
containerResponse.getHttpHeaders()。put(HttpHeaders.CACHE_CONTROL,responseCacheControlValues);
}
return containerResponse;
}

}

并在 web.xml

 < init-param> 
< param-name> com.sun.jersey.spi.container.ContainerResponseFilters< / param-name>
< param-value> my.package.CacheControlCopyFilter< / param-value>
< / init-param>

然后您必须删除您的Java客户端缓存:

 javaws -viewer - >一般
- >设置...
- >删除文件...
- >选中全部三个复选框
- > OK

和voilà,不再有恼人的身份验证弹出窗口:)


First of all, my apologies for this long post. This is a continuation of my previous question (Authentication required window popping up after 7u21 update) regarding this issue, but I narrowed down the search. In short, it seems that my BASIC authentication is broken since Java 7u21.

Applets started through JNLP files are not functioning stable at all and gives Authentication Popup windows.

THE SETUP

First of all I've set up a MySQL database with a usertable and grouptable.

  • Table: authentication

  • Table: groups

Next I have setup a jdbcRealm in Glassfish. Notice that the database user and database password fields are empty because I use a JNDI (see further below):

Glassfish realm settings:

JDNI configuration (as shown in the domain.xml file):

<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>

Once this was done, I changed the default realm to the newly created jdbcRealm and checked the Default principal to role mapping:

TESTING

After all that, for testing I created a simple WebService in Netbeans who fetches some countries from the database and configured the web.xml for BASIC authentication:

<?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>

To test the webservice, I right clicked it in NetBeans and clicked the Test RESTful Web Service. A new Internet Explorer window opens and show me a login screen, I enter the credentials for the dummy user and everything works.

Next, I create a simple JavaFX FXML project who fetches the countries. I have a class (who uses Jersey) who looks like following. This is generated code by 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);
}

In my FXML Controller file, I have this method linked to a button:

@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();
}

That is about the setup of my project. Now, when I test this inside Netbeans or I launch this through the *.jar file, everything works as intended and it gives me following output:

<?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>

However, as soon as I start the applet through a *.jnlp file I get this annoying popup complaining about credentials:

The java console records this:

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>

On the server side (glassfish log)

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")

There are a few things that I really don't understand:

  • On the client side, I see a 401 response code which means Not authorized. How can this be if I use the exact same credentials that I use for testing my webservice?
  • On the client side, If I press cancel on the authentication popup windows, why do I still receive the XML data from my request if the user is not properly authenticated?
  • On the server side, Still a authentication process is happening. Does this have to do with the fact that this is coded in Java? But again, if the authentication process actually succeeds, why is the authentication popup showing on the client side?

解决方案

The reason for the symptoms you encounter is that Oracle has enabled caching of HTTP responses by default with JDK7 in Web Start:

Caching enabled by default: Caching of network content for application code running in Web Start mode is now enabled by default. This allows application improved performance and consistency with applet execution mode. To ensure the latest copy of content is used, the application can use URLConnection.setUseCaches(false) or request header Cache-Control values no-cache/no-store.

So what I did was, setting this header after creating the Jersey client:

Client client = Client.create();
client.addFilter( new HTTPBasicAuthFilter( userId, password ) );
client.addFilter( new ClientFilter() {

    @Override
    public ClientResponse handle( ClientRequest cr )
       throws ClientHandlerException {
           List<Object> cacheControlRequestValues = new ArrayList<Object>();
           cacheControlRequestValues.add( "no-cache" );
           cacheControlRequestValues.add( "no-store" );
           cr.getHeaders().put( HttpHeaders.CACHE_CONTROL, cacheControlRequestValues );
           return getNext().handle( cr );
    }
}

Now if the above specification would be correct, and the implementation of Web Start would follow the HTTP/1.1 reference, which states

The purpose of the no-store directive is to prevent the inadvertent release or retention of sensitive information (for example, on backup tapes). The no-store directive applies to the entire message, and MAY be sent either in a response or in a request. If sent in a request, a cache MUST NOT store any part of either this request or any response to it.

we would be fine - a network sniffer proved that the client was setting the Cache-Control header correctly. Also a ContainerResponseFilter of Jersey was showing me, that the header on the request was set correctly. The response on the other hand had no Cache-Control header set. Should not matter according to the specification, but in reality Web Start kept caching the responses!

So I wrote a ContainerResponseFilter that copies the Cache-Control header from the request to the response:

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;

import javax.ws.rs.core.HttpHeaders;
import java.util.ArrayList;
import java.util.List;

public class CacheControlCopyFilter
    implements ContainerResponseFilter 

    @Override
    public ContainerResponse filter( ContainerRequest containerRequest, ContainerResponse containerResponse ) {
        if ( containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ) != null ) {
            List<Object> responseCacheControlValues = new ArrayList<Object>( containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ).size() );
            for ( String value : containerRequest.getRequestHeader( HttpHeaders.CACHE_CONTROL ) ) {
                responseCacheControlValues.add( value );
            }
            containerResponse.getHttpHeaders().put( HttpHeaders.CACHE_CONTROL, responseCacheControlValues );
        }
        return containerResponse;
    }

}

and activated it in the web.xml

<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>my.package.CacheControlCopyFilter</param-value>
</init-param>

Then you have to delete your Java client cache:

"javaws -viewer" -> General
                 -> Settings...
                 -> Delete Files...
                 -> Select all three check boxes
                 -> OK

and voilà, no more annoying authentication pop ups :)

这篇关于基本身份验证失败与glassfish的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆