无法在Jersey中进行基本的http身份验证 [英] Cannot make basic http authentication work in Jersey

查看:219
本文介绍了无法在Jersey中进行基本的http身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Jersey 1.X版本连接到安全的外部休息服务。



我使用了以下代码

  public class MyRestClient 
{
private static final String API_USER_NAME =some value;
private static final String API_PASSWORD =some value;
private static final String REST_URL =https://< somevalue>;

public static void main(String [] args)
{
ClientConfig config = new DefaultClientConfig();
客户端客户端= Client.create(config);
client.addFilter(new HTTPBasicAuthFilter(API_USER_NAME,API_PASSWORD));
WebResource webResource =
client.resource(UriBuilder.fromUri(REST_URL).build());

ClientResponse response = webResource.post(ClientResponse.class);
System.out.println(响应);
}
}

但我一直在遇到这个例外..

  com.sun.jersey.api.client.ClientHandlerException:javax.net.ssl.SSLHandshakeException:java.security.cert.CertificateException:No名称匹配'somevalue'发现

我检查了这个外部休息服务的API,并说它支持基本的HTTP身份验证,但我不知道为什么我一直在遇到这个错误。



有什么想法吗?

解决方案

由于Basic Auth本身缺乏安全性,它通常通过SSL完成,您可以在URL中的 https 架构中看到。使用SSL,使用证书。 SSL握手包括服务器发送其证书和客户端检查其信任库以查看证书是否可信。该平台应具有其信任的证书颁发机构列表。例如,如果我们尝试访问

  WebTarget target = client.target(https://wikipedia.org); 

这将起作用,因为维基百科发送的证书由系统中的受信任机构签名。另一方面,如果来自服务器的证书未被其中一个被篡改的权限签名,则SSL握手将失败。



如果是这种情况,那么需要配置客户端来处理SSL握手,这就是您获得异常的原因。您可以在此处查看有关如何配置客户端的一些好答案使用 https






UPDATE




你提供的链接已经死了所以我不知道'myTrustManager'和'hostnameVerifier'是什么...你能分享一些关于我如何提供的信息吗? ?




  import com.sun.jersey.api.client.Client; 
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.junit.Test;

公共类JUnitTest {

private static final String TRUSTSTORE_FILE =< location-of-truststore;
private static final String TRUSTSTORE_PASSWORD =trustStorePassword;

@Test
public void test()throws Exception {
KeyStore truststore = KeyStore.getInstance(JKS);
truststore.load(new FileInputStream(TRUSTSTORE_FILE),
TRUSTSTORE_PASSWORD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(SunX509);
tmf.init(truststore);
SSLContext sslContext = SSLContext.getInstance(SSL);
sslContext.init(null,tmf.getTrustManagers(),null);

ClientConfig config = new DefaultClientConfig();
config.getProperties()。put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
new HTTPSProperties(null,sslContext));
客户端客户端= Client.create(config);

final String httpsUrl =https:// ...;
ClientResponse response = client.resource(httpsUrl).get(ClientResponse.class);
System.out.println(response.getStatus());
System.out.println(response.getEntity(String.class));
}
}

基本上你需要得到 X.509证书(请参阅下面的链接了解编程方式)。然后将其导入您的信任库。这是您的客户端知道如何信任连接的方式。如果你相信服务器是他们所说的那个,那么就可以加密连接。



获得证书后,你可以用 Java keytool 。通过这样做


keytool -import -alias serverCert -file< cert.file> -keystore< client_trust_file>


您将被要求输入密码。然后问你是否相信证书。输入是,然后就完成了。这是您输入的文件( client_trust_file )和密码,应该在上面的代码中使用。








更新2



创建简单的说明与Tomcat通过安全SSL连接的应用程序。使用上面的客户端代码来访问它。我将使用Netbeans 8,但也会尝试以一般方式包含执行此操作的说明。我也将使用Tomcat 8(配置可能与Tomcat 7有点不同。您应该查阅文档以了解任何差异)。我将使用Maven,所以希望你习惯使用它。



第1步:



创建一个新的应用程序。我将从Maven原型创建一个简单的Jersey应用程序。在Netbeans中


File→新项目→ Maven→来自Archetype&rarr的项目;搜索jersey-quickstart-webapp;选择groupIdorg.glassfish.jersey.archetypes→下一步→将项目命名为secured-rest-app→希望你能完成剩下的工作。您最终应该使用Maven应用程序。


在任何其他支持Maven的IDE中,只需查找坐标为的原型: / p>


  • groupId:org.glassfish.jersey.archetypes

  • artifactId:jersey-quickstart-webapp

  • 版本:2.13



从命令行:执行

  mvn archetype:generate -DarchetypeArtifactId = jersey-quickstart-grizzly2 \ 
-DarchetypeGroupId = org.glassfish.jersey.archetypes -DinteractiveMode = false \
-DgroupId = com.example -DartifactId = secured-rest-app -Dpackage = secured.rest.app \
-DarchetypeVersion = 2.13



第2步:



我们需要在应用程序中设置基本身份验证。这可以在web.xm l中完成。打开项目的web.xml并将其添加到< / servlet-mapping>



<$ p $下面p> <安全约束>
< web-resource-collection>
< web-resource-name>安全休息应用< / web-resource-name>
< url-pattern> / webapi / *< / url-pattern>
< / web-resource-collection>
< auth-constraint>
< role-name> *< / role-name>
< / auth-constraint>
< / security-constraint>

< login-config>
< auth-method> BASIC< / auth-method>
< realm-name> secured-rest-app.com< / realm-name>
< / login-config>

< security-role>
< role-name> user< / role-name>
< / security-role>



第3步:



现在我们只是需要在Tomcat中设置领域。默认情况下,Tomcat使用域名 UserDatabaseRealm 。它基本上只是从xml文件中读取。这可能不是生产中最理想的方式,但这是一个最简单的例子。有关领域的更多信息,请参阅领域配置操作方法 。对于此特定领域,已经设置了该文件。我们只需要添加我们的用户。打开< tomcat-home> /conf/tomcat-users.xml 并在< tomcat-users>

 < user password =secretroles =userusername =peeskillet/> 



第4步:



现在我们可以测试一下。如果你已经在Netbeans上安装了Tomcat,我们需要做的只是运行并选择服务器。这应该会自动将浏览器打开到我们的 index.jsp 。该文件不受保护,因为它不符合安全约束的< url-pattern> / webapi / *< / url-pattern> 。单击Jersey资源链接,您将看到Basic Auth登录。分别输入 peeskillet secret 作为用户名和密码。现在您可以访问该资源了。



第5步:



以上所有内容仅为我们设置了Basic身份验证,但由于所有Basic Auth都是base64编码我们的用户名和密码,因此可以轻松解码,因此我们需要通过安全连接进行身份验证。



首先我们需要做的是为我们的服务器创建一个密钥库。我们将要做的是创建一个自签名证书,该证书只能在开发中完成。在生产中,您需要从受信任的CA机构获得证书



cd < tomcat-home> / conf 并输入以下内容(全部在一行上)

  keytool -genkey -alias localhost -keyalg RSA -keysize 1024 
-dnameCN = localhost
-keypass supersecret
-keystore tomcat-keystore.jks
-storepass supersecret

您现在应该看到一个文件 tomcat-keystore.jks conf 目录中。现在我们可以导出证书。

  keytool -export -alias localhost -rfc -keystore ./tomcat-keystore.jks> ./tomcat.cert 

系统将提示您输入密码,输入 supersecret 。您现在应该看到在 conf 目录中创建的 tomcat.cert 文件。将该文件复制到您在上面创建的应用程序的项目根目录中。



从命令行 cd 到项目root, tomcat.cert 的位置,然后键入以下内容

  keytool -import -alias tomcatCert -file ./tomcat.cert -keystore ./client-truststore.jks 

系统将提示您输入信任库的密码。使用 trustpass 。您需要输入两次。完成后,它将提示信任证书,键入 yes 并输入。您现在应该在项目根目录中看到 client-truststore.jks 文件。这就是我们将用于客户端应用程序的内容。



现在我们只需要配置Tomcat以使用我们的密钥库进行连接。在< tomcat-home> /conf/server.xml 中,在< Service> 元素内b $ b。 (注意Tomcat 7可能会略有不同)

 < Connector port =8443
protocol =org .apache.coyote.http11.Http11NioProtocol
maxThreads =150
SSLEnabled =true
scheme =https
secure =true
keystoreFile =absolute / path / to / tomcat-keystore.jks
keystorePass =supersecret
clientAuth =false
sslProtocol =TLS/>

最后,在我们的webapp中,我们应该通过更改<$ c $来添加安全连接支持c>< security-constraint>

 < security-constraint> 
< web-resource-collection>
< web-resource-name>安全休息应用< / web-resource-name>
< url-pattern> / webapi / *< / url-pattern>
< / web-resource-collection>
< auth-constraint>
< role-name> *< / role-name>
< / auth-constraint>
< user-data-constraint>
< transport-guarantee> CONFIDENTIAL< / transport-guarantee>
< / user-data-constraint>
< / security-constraint>

现在我们设置使用我们的客户代码。



第6步:



上面的代码使用Jersey 1客户端。我们正在使用Jersey 2,因此代码会略有不同。在应用程序的任何位置,只需使用 main 方法创建一个类来运行我们的客户端。这是我使用的:

  import java.io.FileInputStream; 
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

公共类SimpleClientApp {

private static final String TRUSTSTORE_FILE =client-truststore.jks;
private static final String TRUSTSTORE_PASSWORD =trustpass;
private static final String APP_URL
=https:// localhost:8443 / secured-rest-app / webapi / myresource;

public static void main(String [] args)throws Exception {
KeyStore truststore = KeyStore.getInstance(JKS);
truststore.load(new FileInputStream(TRUSTSTORE_FILE),
TRUSTSTORE_PASSWORD.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(SunX509);
tmf.init(truststore);
SSLContext sslContext = SSLContext.getInstance(TLS);
sslContext.init(null,tmf.getTrustManagers(),null);

客户端客户端= ClientBuilder.newBuilder()
.sslContext(sslContext).build();
client.register(HttpAuthenticationFeature.basic(peeskillet,secret));

响应响应= client.target(APP_URL).request()。get();
System.out.println(response.readEntity(String.class));

}
}

你应该可以运行这个它应该打印出得到它!。我们已经完成了!



由于这个特殊问题是关于Jersey 1的,我只想提一下你可以轻松创建一个Jersey 1应用程序。从第一步开始,只需使用Maven原型的坐标




  • groupId:com.sun.jersey.archetypes

  • artifactId:jersey-quickstart-webapp

  • 版本:1.18.1



在Netbeans中,只需按照上述步骤操作,但选择 jersey-quickstart-webapp com.sun.jersey.archetypes 版本c $ c>。



使用Jersey 1,您可以使用原始答案中的代码,只需添加Basic Auth过滤器,就像OP在原始帖子中所做的那样,设置用户名和密码并更改网址。



如果帖子中有任何错误,请告诉我。我还没有机会证明这一点: - )



一些资源


I am trying to connect to a secure external rest service using Jersey 1.X version.

I used the following code

public class MyRestClient
{
  private static final String API_USER_NAME = "some value";
  private static final String API_PASSWORD = "some value";
  private static final String REST_URL = "https://<somevalue>";

  public static void main(String[] args)
  {
    ClientConfig config = new DefaultClientConfig();
    Client client = Client.create(config);
    client.addFilter(new HTTPBasicAuthFilter(API_USER_NAME, API_PASSWORD));
    WebResource webResource =
      client.resource(UriBuilder.fromUri(REST_URL).build());

    ClientResponse response = webResource.post(ClientResponse.class);
    System.out.println(response);
  }
}

But I keep hitting this exception..

com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching 'somevalue' found

I checked out the API of this external rest service and it says it support Basic HTTP authentication but I dont know why I keep hitting this error.

Any thoughts?

解决方案

Because the lack of security in Basic Auth by itself, it's usually done over SSL, as you can see in the https schema in the URL. With SSL, there are certificates used. The SSL handshake consists of the server sending its certificate and the client checking its truststore to see if the certificate is trusted. The platform should have a list of Certificate authorities that it trusts. For instance if we try and access

WebTarget target = client.target("https://wikipedia.org");

this will work as the cert sent by wikipedia is signed by a trusted authority in the system. On the other hand, if the certificate from the server is not signed by one of those trused authorities, then the SSL handshake will fail.

If this is the case, then Client needs to be configured to handle the SSL handshake, that's why you are getting the exception. You can see some good answers here on how to configure the Client for working with https


UPDATE

The link you have provided is dead so I dont know what 'myTrustManager' and 'hostnameVerifier' is...can you share some info on how can I supply that?

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;
import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import org.junit.Test;

public class JUnitTest {

    private static final String TRUSTSTORE_FILE = "<location-of-truststore";
    private static final String TRUSTSTORE_PASSWORD = "trustStorePassword";

    @Test
    public void test() throws Exception {
        KeyStore truststore = KeyStore.getInstance("JKS");
        truststore.load(new FileInputStream(TRUSTSTORE_FILE), 
                                            TRUSTSTORE_PASSWORD.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(truststore);
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, tmf.getTrustManagers(), null);

        ClientConfig config = new DefaultClientConfig();
        config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, 
                new HTTPSProperties(null, sslContext));
        Client client = Client.create(config);

        final String httpsUrl = "https://...";
        ClientResponse response = client.resource(httpsUrl).get(ClientResponse.class);
        System.out.println(response.getStatus());
        System.out.println(response.getEntity(String.class));
    } 
}

Basically you need to get the X.509 Certificate from the people who own the API (see link below for programmatic way). Then you import it into your trust store. This is how your client knows to trust the connection. If you trust that the server is who they say they are, then the connection can be encrypted.

Once you have the cert you can import it with the Java keytool. By doing this

keytool -import -alias serverCert -file <cert.file> -keystore <client_trust_file>

You will be asked for a password. Then asked if you trust the cert. Type 'yes', then you're done. This is the file (client_trust_file) and password you typed, should be used in the above code.


Update 2

Instructions on creating a simple app that is over a secured SSL connection with Tomcat. The use the client code above to access it. I am going to be using Netbeans 8, but will try to include instructions for doing this in a general way also. I will also be using Tomcat 8 (the configuration may be a bit different fro Tomcat 7. You should consult the documentation for any differences). I will be using Maven, so hopefully you are comfortable using it.

Step 1:

Crate a new app. I will create a simple Jersey app from a Maven archetype. In Netbeans

File → New Project → Maven → Project from Archetype → Search "jersey-quickstart-webapp"; choose the one with groupId "org.glassfish.jersey.archetypes" → Next → Name the project "secured-rest-app" → Hopefully you can complete the rest. You should end up with a Maven app.

In any other IDE that supports Maven, just look for an archetype with the coordinates:

  • groupId: org.glassfish.jersey.archetypes
  • artifactId: jersey-quickstart-webapp
  • version: 2.13

From command line: do

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
    -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
    -DgroupId=com.example -DartifactId=secured-rest-app -Dpackage=secured.rest.app \
    -DarchetypeVersion=2.13 

Step 2:

We need to set up Basic Authentication in the app. This can be done in the web.xm l. Open up the web.xml of the project and add this below the </servlet-mapping>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Secured Rest App</web-resource-name>
        <url-pattern>/webapi/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
</security-constraint>

<login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>secured-rest-app.com</realm-name>
</login-config>

<security-role>
    <role-name>user</role-name>
</security-role>

Step 3:

Now we just need to set up the realm in Tomcat. By default Tomcat use a realm names UserDatabaseRealm. It basically just reads from an xml file. This is probably not the most desired way in production, but this is the easiest to work with for an example. For more information on realms, see Realm Configuration HOW-TO. For this particular realm, the file is already set up. We just need to add our user. Open the <tomcat-home>/conf/tomcat-users.xml and enter the following user inside <tomcat-users>

<user password="secret" roles="user" username="peeskillet"/>

Step 4:

Now we can test it. If you already have Tomcat setup on Netbeans, all we need to do is Run and select the server. This should automatically open up the browser to our index.jsp. The file is not secured, as it doesn't fit within the <url-pattern>/webapi/*</url-pattern> of out security constraint. Click the Jersey Resource link and you will see the Basic Auth login. Type in peeskillet and secret for the username and password, respectively. Now you can access the resource.

Step 5:

All of the above just set us up for Basic Authentication, but because all Basic Auth is, is just base64 encoding our username and password, it can be easily decoded, so we need to authenticate over a secure connection.

First thing we need to do is create a keystore for our server. What we will be going here is creating a self signed certificate, which should only be done in development. In production, you will want to get a cert from a trusted CA authority

cd to <tomcat-home>/conf and type the following (all on one line)

keytool -genkey -alias localhost -keyalg RSA -keysize 1024
        -dname "CN=localhost"
        -keypass supersecret
        -keystore tomcat-keystore.jks
        -storepass supersecret

You should now see a file tomcat-keystore.jks in the conf dir. Now we can export the certificate.

keytool -export -alias localhost -rfc -keystore ./tomcat-keystore.jks > ./tomcat.cert

You will be prompted for the password, type supersecret. You should now see a tomcat.cert file created in the conf dir. Copy that file into the project root of your application you created above.

From the command line cd to the project root, the location of the tomcat.cert and type the following

keytool -import -alias tomcatCert -file ./tomcat.cert -keystore ./client-truststore.jks

You will be prompted for a password for the truststore. Use trustpass. You will need to enter it twice. When done, it will prompt to trust the certificate, type yes and enter. You should now see a client-truststore.jks file in the project root. This is what we will use for our client app.

Now we just need to configure Tomcat to use our keystore for the connection. In the <tomcat-home>/conf/server.xml, inside the the <Service> element . (Note Tomcat 7 may be a little different)

<Connector port="8443" 
    protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" 
    SSLEnabled="true" 
    scheme="https" 
    secure="true"
    keystoreFile="absolute/path/to/tomcat-keystore.jks"
    keystorePass="supersecret"
    clientAuth="false" 
    sslProtocol="TLS" />

And finally, in our webapp, we should add the secure connection support by altering the <security-constraint>

<security-constraint>
    <web-resource-collection>
        <web-resource-name>Secured Rest App</web-resource-name>
        <url-pattern>/webapi/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

Now we are set to use our client code.

Step 6:

The code above, uses Jersey 1 client. We are using Jersey 2, so the code will be slightly different. Anywhere in the app, just create a class with a main method to run our client. Here's what I use:

import java.io.FileInputStream;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;

public class SimpleClientApp {

    private static final String TRUSTSTORE_FILE = "client-truststore.jks";
    private static final String TRUSTSTORE_PASSWORD = "trustpass";
    private static final String APP_URL 
            = "https://localhost:8443/secured-rest-app/webapi/myresource";

    public static void main(String[] args) throws Exception {
        KeyStore truststore = KeyStore.getInstance("JKS");
        truststore.load(new FileInputStream(TRUSTSTORE_FILE), 
                                            TRUSTSTORE_PASSWORD.toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(truststore);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        Client client = ClientBuilder.newBuilder()
                .sslContext(sslContext).build();
        client.register(HttpAuthenticationFeature.basic("peeskillet", "secret"));

        Response response = client.target(APP_URL).request().get();
        System.out.println(response.readEntity(String.class));

    }
}

You should be able to run this and it should print out Got it!. We're done!

Since this particular question was about Jersey 1, I'll just mention that you can easily create a Jersey 1 app. From the first step, just use the coordinates for the Maven archetype

  • groupId: com.sun.jersey.archetypes
  • artifactId: jersey-quickstart-webapp
  • version: 1.18.1

In Netbeans, just follow the steps above, but select the com.sun.jersey.archetypes version of the jersey-quickstart-webapp.

With Jersey 1, you can use the code in the original answer, just add the Basic Auth filter, as the OP has done in the original post, setting the username and password and changing the url of course.

Please let me know if there are any mistakes in the post. I haven't gotten a chance to proof-read this yet :-)

Some Resource

这篇关于无法在Jersey中进行基本的http身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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