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

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

问题描述

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

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

我使用了以下代码

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

我查看了这个外部 rest 服务的 API,它说它支持基本 HTTP 身份验证,但我不知道为什么我总是遇到这个错误.

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.

有什么想法吗?

推荐答案

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

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

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

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.

如果是这种情况,则需要将 Client 配置为处理 SSL 握手,这就是您收到异常的原因.您可以在此处看到一些关于如何配置Client以使用的好答案https

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

您提供的链接已失效,所以我不知道 'myTrustManager' 和 'hostnameVerifier' 是什么...您能分享一些有关如何提供的信息吗?

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

基本上你需要从拥有者那里获得 X.509 证书API(有关编程方式,请参见下面的链接).然后将其导入您的信任库.这就是您的客户知道信任连接的方式.如果您相信服务器就是他们所说的那个人,那么连接可以被加密.

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.

获得证书后,您可以使用 Java 密钥工具.通过这样做

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

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

您将被要求输入密码.然后问你是否信任证书.输入是",然后你就完成了.这是您输入的文件 (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.

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

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.

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

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

文件 →新项目→马文→来自 Archetype 的项目 →搜索jersey-quickstart-webapp";选择 groupId "org.glassfish.jersey.archetypes" →下一个→将项目命名为secured-rest-app" →希望你能完成剩下的.你应该最终得到一个 Maven 应用程序.

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.

在任何其他支持 Maven 的 IDE 中,只需查找带有坐标的原型:

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

  • 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.xml 中完成.打开项目的 web.xml 并将其添加到 </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>

第三步:

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

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

第四步:

现在我们可以测试它了.如果您已经在 Netbeans 上安装了 Tomcat,我们需要做的就是 Run 并选择服务器.这应该会自动打开浏览器到我们的 index.jsp.该文件不安全,因为它不适合 out 安全约束的 /webapi/*.单击 Jersey Resource 链接,您将看到 Basic Auth 登录.分别输入用户名和密码的 peeskilletsecret.现在您可以访问该资源了.

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.

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

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.

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

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/conf 并输入以下内容(全部在一行上)

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

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

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

系统将提示您输入密码,输入 supersecret.您现在应该会看到在 conf 目录中创建的 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.

从命令行cd到项目根目录,tomcat.cert的位置并输入以下内容

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

系统将提示您输入信任库的密码.使用 trustpass.您将需要输入两次.完成后会提示信任证书,输入yes并回车.您现在应该在项目根目录中看到一个 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.

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

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

最后,在我们的 webapp 中,我们应该通过更改 <security-constraint>

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.

上面的代码使用 Jersey 1 客户端.我们使用的是 Jersey 2,所以代码会略有不同.在应用程序的任何地方,只需创建一个带有 main 方法的类来运行我们的客户端.这是我使用的:

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

    }
}

你应该能够运行它,它应该会打印出 Got it!.我们完成了!

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

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

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
  • 版本:1.18.1

在 Netbeans 中,只需按照上述步骤操作,但选择 jersey-quickstart-webappcom.sun.jersey.archetypes 版本.

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

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

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.

如果帖子中有任何错误,请告诉我.我还没有机会校对这个:-)

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

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