ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – 无法在Jersey中进行基本的http身份验证

2019-09-27 09:00:19  阅读:296  来源: 互联网

标签:java ssl rest jersey jersey-client


我正在尝试使用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 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);
  }
}

但我一直在打这个例外..

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

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

有什么想法吗?

解决方法:

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

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

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

如果是这种情况,则需要将客户端配置为处理SSL握手,这就是您获得异常的原因.关于如何配置客户端以使用https,您可以看到一些很好的答案here

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

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

获得证书后,您可以使用Java keytool将其导入.通过执行此操作

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

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

> Programmaticly add a remote certificate to your truststore
>查看更多关于Java Secure Socket Framework

更新2

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

第1步:

装箱一个新的应用程序.我将从Maven原型创建一个简单的Jersey应用程序.在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.

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

> 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>下面添加它.

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

第3步:

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

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

第四步:

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

第5步:

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

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

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

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

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

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

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

从命令行cd到项目根目录,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>内元件
. (注意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中,我们应该通过改变< 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>

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

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

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

    }
}

你应该能够运行它,它应该打印出来了!我们完成了!

由于这个特定的问题是关于泽西1,我只是提到你可以轻松创建一个泽西1应用程序.从第一步开始,只需使用Maven原型的坐标即可

> groupId:com.sun.jersey.archetypes
> artifactId:jersey-quickstart-webapp
>版本:1.18.1

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

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

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

一些资源

> Tomcat 8 SSL/TLS Configuration HOW-TO
> Tomcat 8 Realm Configuration HOW-TO
> Tomcat 7 Realm Configuration HOW-TO
> Tomcat 7 SSL/TLS Configuration HOW-TO

标签:java,ssl,rest,jersey,jersey-client
来源: https://codeday.me/bug/20190927/1823375.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有