Java WebService over SSL
来源:互联网 发布:数据库爆破 编辑:程序博客网 时间:2024/06/17 19:14
I thought that customizing web service on https server (packed with JRE) and its client should be easy. But the lack of documentation make it quiet hard. Here are results of my findings. The topics covered are: Two-way SSL communication, custom SSLContext for webservice running on Java SDK embedded https server, dummy TrustManager, client certificate authentication. I’ll cover both the server and client side.
Suppose, you have created 2 certifikate keystore files, let’s say server.jks
(containing server private key and client public certificate) andclient.jks
(symmetrically, the client private key and server public certificate).
The server side code follows, consider it as code for reference.
package
com.example.echo;
import
com.sun.net.httpserver.Authenticator;
import
com.sun.net.httpserver.HttpContext;
import
com.sun.net.httpserver.HttpExchange;
import
com.sun.net.httpserver.HttpServer;
import
com.sun.net.httpserver.HttpsConfigurator;
import
com.sun.net.httpserver.HttpsExchange;
import
com.sun.net.httpserver.HttpsParameters;
import
com.sun.net.httpserver.HttpsServer;
import
java.io.FileInputStream;
import
java.net.InetSocketAddress;
import
java.security.KeyStore;
import
java.security.cert.CertificateException;
import
java.security.cert.X509Certificate;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
javax.annotation.Resource;
import
javax.jws.WebMethod;
import
javax.jws.WebParam;
import
javax.jws.WebResult;
import
javax.jws.WebService;
import
javax.net.ssl.KeyManagerFactory;
import
javax.net.ssl.SSLContext;
import
javax.net.ssl.SSLParameters;
import
javax.net.ssl.SSLPeerUnverifiedException;
import
javax.net.ssl.TrustManager;
import
javax.net.ssl.X509TrustManager;
import
javax.xml.ws.Endpoint;
import
javax.xml.ws.WebServiceContext;
import
javax.xml.ws.handler.MessageContext;
public
class
SSLWebService {
public
static
void
main(String[] args)
throws
Exception {
new
SSLWebService().runHttpsService();
}
public
void
runHttpsService()
throws
Exception {
KeyStore ks = KeyStore.getInstance(
"JKS"
);
FileInputStream keyStoreIn =
new
FileInputStream(
"server.jks"
);
try
{
ks.load(keyStoreIn,
"passphrase"
.toCharArray());
}
finally
{
keyStoreIn.close();
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks,
"passphrase"
.toCharArray());
TrustManager[] trustManagers =
new
TrustManager[] {
new
DummyTrustManager()};
SSLContext sslCtx = SSLContext.getInstance(
"TLS"
);
sslCtx.init(kmf.getKeyManagers(), trustManagers,
null
);
HttpsConfigurator cfg =
new
HttpsConfigurator(sslCtx){
public
void
configure(HttpsParameters params) {
SSLParameters sslparams = getSSLContext().getDefaultSSLParameters();
// Modify the default params: Will require client certificates
sslparams.setNeedClientAuth(
true
);
params.setSSLParameters(sslparams);
}
};
ExecutorService httpThreadPool = Executors.newFixedThreadPool(
10
);
HttpsServer httpsS = HttpsServer.create(
new
InetSocketAddress(
8081
),
50
);
httpsS.setHttpsConfigurator(cfg);
httpsS.setExecutor(httpThreadPool);
httpsS.start();
HttpContext ctx = httpsS.createContext(
"/ws"
);
ctx.setAuthenticator(
new
Authenticator(){
@Override
public
Result authenticate(HttpExchange exch) {
try
{
if
(exch
instanceof
HttpsExchange) {
HttpsExchange httpsExch = (HttpsExchange)exch;
System.out.println(
"authen: "
+ httpsExch.getSSLSession().getPeerPrincipal().getName());
// DO YOUR AUTHENTICATION HERE
httpsExch.getSSLSession().putValue(
"MY_PARAM_PEER_NAME"
,
httpsExch.getSSLSession().getPeerPrincipal().getName());
return
new
Authenticator.Success(exch.getPrincipal());
}
}
catch
(SSLPeerUnverifiedException e) {
e.printStackTrace();
}
return
new
Authenticator.Failure(
403
);
}
});
Endpoint endpoint = Endpoint.create(
new
Echo());
endpoint.publish(ctx);
// publish also on HTTP server, so we can access
// wsdl through HTTP, just for our example.
HttpServer httpS = HttpServer.create(
new
InetSocketAddress(
8082
),
50
);
httpS.start();
Endpoint endpoint2 = Endpoint.create(
new
Echo());
endpoint2.publish(httpS.createContext(
"/ws"
));
}
@WebService
(
targetNamespace =
"http://www.example.com/Echo"
)
public
static
class
Echo {
@Resource
protected
WebServiceContext context;
@WebMethod
(operationName =
"echo"
)
@WebResult
(name =
"message"
)
public
String echo(
@WebParam
(name =
"msg"
) String msg) {
String user =
"unknown"
;
MessageContext msgCtx = context.getMessageContext();
Object httpExchange = msgCtx.get(
"com.sun.xml.ws.http.exchange"
);
if
(httpExchange
instanceof
HttpsExchange) {
HttpsExchange httpsExch = (HttpsExchange)httpExchange;
user = (String)httpsExch.getSSLSession().getValue(
"MY_PARAM_PEER_NAME"
);
}
return
"user '"
+ user +
"' said: "
+ msg;
}
}
public
static
class
DummyTrustManager
implements
X509TrustManager {
public
X509Certificate[] getAcceptedIssuers() {
return
new
X509Certificate[
0
]; }
public
void
checkClientTrusted(X509Certificate[] certs, String authType)
throws
CertificateException {
// DO YOUR VERIFICATION
}
public
void
checkServerTrusted(X509Certificate[] certs, String authType)
throws
CertificateException {
// DO YOUR VERIFICATION
}
}
}
Obtain wsdl and generate client classes, from commandline:
wget -O echo.wsdl http://localhost:8082/ws?wsdl
wsimport -Xnocompile http://localhost:8082/ws?wsdl
And finally write a client:
package
com.example.echo;
import
java.io.FileInputStream;
import
java.security.KeyStore;
import
java.security.cert.CertificateException;
import
java.security.cert.X509Certificate;
import
java.util.Map;
import
javax.net.ssl.HostnameVerifier;
import
javax.net.ssl.KeyManagerFactory;
import
javax.net.ssl.SSLContext;
import
javax.net.ssl.SSLSession;
import
javax.net.ssl.TrustManager;
import
javax.net.ssl.X509TrustManager;
import
javax.xml.namespace.QName;
import
javax.xml.ws.BindingProvider;
public
class
SSLWebClient {
public
void
callEcho(String wsUrl, String msg)
throws
Exception {
SSLContext sslCtx = SSLContext.getInstance(
"SSL"
);
TrustManager[] trustManagers =
new
TrustManager[] {
new
X509TrustManager() {
public
X509Certificate[] getAcceptedIssuers() {
return
new
X509Certificate[
0
];
}
public
void
checkClientTrusted(X509Certificate[] certs, String authType)
throws
CertificateException {
}
public
void
checkServerTrusted(X509Certificate[] certs, String authType)
throws
CertificateException {
}
}
};
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(
"JKS"
);
FileInputStream keyStoreIn =
new
FileInputStream(
"client.jks"
);
try
{
ks.load(keyStoreIn,
"passphrase"
.toCharArray());
}
finally
{
keyStoreIn.close();
}
kmf.init(ks,
"passphrase"
.toCharArray());
sslCtx.init(kmf.getKeyManagers(), trustManagers,
null
);
// This is a key point: We must not initialize service with target URL, because then
// the WSDL would be downloaded from the HTTPS server, before we initialize our
// context properties. So we initialize the EchoService with previously downloaded WSDL
// and then use it to call the real service through HTTPS.
EchoService service =
new
EchoService(
getClass().getResource(
"echo.wsdl"
),
new
QName(
"http://www.example.com/Echo"
,
"EchoService"
));
Echo port = service.getEchoPort();
Map<String, Object> ctxt = ((BindingProvider)port).getRequestContext();
ctxt.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, wsUrl);
// Sets dummy hostname verifier, so that server certificate CN doesn't
// have to match its hostname
HostnameVerifier hnv =
new
HostnameVerifier() {
@Override
public
boolean
verify(String hostname, SSLSession sslSession) {
return
true
;
}
};
ctxt.put(
"com.sun.xml.internal.ws.transport.https.client.hostname.verifier"
, hnv);
ctxt.put(
"com.sun.xml.ws.transport.https.client.hostname.verifier"
, hnv);
// Sets socket factory from our ssl context,
// which has dummy Trust manager. If used, server certificate doesn't need to be
// in our trust keystore nor in Java "cacerts" keystore.
ctxt.put(
"com.sun.xml.internal.ws.transport.https.client.SSLSocketFactory"
, sslCtx.getSocketFactory());
ctxt.put(
"com.sun.xml.ws.transport.https.client.SSLSocketFactory"
, sslCtx.getSocketFactory());
String response = port.echo(msg);
System.out.println(
"Response: "
+ response);
}
public
static
void
main(String[] args)
throws
Exception {
new
SSLWebClient().callEcho(
"https://localhost:8081/ws/Echo"
,
"Hello"
);
}
}
- Java WebService over SSL
- Java Client using FTP over SSL (Explicit)
- Consuming P6 Web Services over HTTPS (SSL) From Java
- Download page Over SSL
- EJB3 over SSL in JBOSS
- 如何配置LDAP over SSL
- 008-httpd_http over ssl(https)
- 通过SSL调用WebService
- 通过SSL调用WebService
- zt:Consuming Webservices over HTTPS (SSL)
- WinForm 调 SSL VPN WebService
- Webservice 通过SSL加密传输
- HttpClient 访问SSL WebService 方式
- Webservice 通过SSL加密传输
- Java调用使用SSL/HTTPS协议来传输的axis webservice服务
- SSL java
- java----ssl
- java SSL
- 黑马程序员——面向对象(3)
- fzu 2064(暴力)
- 伯努利数与自然数幂和
- shell浅谈之三for、while、until循环
- hdu 1175(回溯)
- Java WebService over SSL
- 二叉树的镜像
- 比较好的JavaScript库-日常备用
- Android动态加载APK问题整理
- Hadoop网络课程模板程序
- Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk
- 刷leetcode的第一道题——Reverse Words in a String
- android ICS 系统启动之Logo有关学习总结
- Cocos2d-x 3.0 开发(八)骨骼动画的动态换肤