在今天的学习中,咱们讲开始过渡到一个真正的websecurity例子。php
次日中咱们知道了如何使用handler来处理客户端提交上来的用户名与密码,而在今天的学习中,咱们将会使用服务端预先配置的用户名与密码来authenticate客户端提交上来的值。java
相对于次日的学习,若是客户端提交的用户名与密码输错,但仍是可以与服务端创建http链接来讲,第三天中的例子的安 全性则更高,当客户端提交上来的用户名与密码错误则更本不可能和服务端创建起有效的http链接。该例子同时适用于一切J2EE AppServer,好比说:IBMWAS, ORACLE WEBLOGIC。web
同时,经过该例子将讲述ws-security与相关的ws-policy进而一步步过渡到QoS。算法
打开tomcat下的cnof/tomcat-user.xml文件:c#
<?xml version='1.0' encoding='utf-8'?>api <tomcat-users>tomcat <role rolename="operator"/>安全 <user username="tomcatws" password="123456" roles="operator"/>架构 </tomcat-users>app |
经过上述配置,咱们能够知道咱们在tomcat中增长了一个角色叫”operator”,同时配置了一个用户叫”tomcatws”密码为”123456”,该用户属于operator角色。
请打开你工程的web.xml文件,加入下述这段内容:
<security-role> <description>Normal operator user</description> <role-name>operator</role-name> </security-role> <security-constraint> <web-resource-collection> <web-resource-name>Operator Roles Security</web-resource-name> <url-pattern>/AuthHelloService</url-pattern> </web-resource-collection> <auth-constraint> <role-name>operator</role-name> </auth-constraint> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> </login-config> |
这边能够看到,咱们把一个WebService的访问置于了web security的保护下,若是须要该问该web资源,服务端须要验证两部份内容:
1) 是不是合法group/role中的用户
2) 因为<auth-method>设置为basic,即客户端要访问相关的web资源时还须要提供用户名与密码
package ctsjavacoe.ws.fromjava; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.jws.soap.SOAPBinding.Style; @SOAPBinding(style = Style.RPC) public interface AuthHello { @WebMethod public String say(String name); } |
package ctsjavacoe.ws.fromjava; import javax.jws.WebService; @WebService(endpointInterface = "ctsjavacoe.ws.fromjava.AuthHello") public class AuthHelloImpl implements AuthHello { @Override public String say(String name) { return "hello: " + name; } } |
该Web Service没有任何特殊的地方,也没有使用任何的handler,一切都交给了j2ee App容器去作认证
布署完后,咱们访问:http://localhost:8080/JaxWSSample/AuthHelloService?wsdl
看看咱们获得了什么:
OK,咱们输入tomcatws,密码为123456
而后咱们就获得正确的wsdl的输出了,接下来咱们用客户端去连服务端。
package ctsjavacoe.ws.fromjava; import javax.xml.namespace.QName; import javax.xml.ws.Response; import javax.xml.ws.BindingProvider; import javax.xml.ws.Service; import java.net.URL; public class AuthHelloClient { private static final String WS_URL = "file:D://wspace/JaxWSClient/wsdl/AuthHelloImplService.wsdl"; private static final String S_URL = "http://localhost:8080/JaxWSSample/AuthHelloService?wsdl"; public static void main(String[] args) throws Exception { URL url = new URL(WS_URL); QName qname = new QName("http://fromjava.ws.ctsjavacoe/", "AuthHelloImplService"); Service service = Service.create(url, qname); AuthHello port = service.getPort(AuthHello.class); BindingProvider bp = (BindingProvider) port; bp.getRequestContext().put( BindingProvider.USERNAME_PROPERTY, "tomcatws"); bp.getRequestContext().put( BindingProvider.PASSWORD_PROPERTY, "123456"); bp.getRequestContext().put( BindingProvider.ENDPOINT_ADDRESS_PROPERTY, S_URL); String rtnMessage = port.say("MK"); System.out.println("rtnMessage=====" + rtnMessage); } } |
关键语句我已经用红色标粗。
要点:
1) 根据wsdl create出来一个Service,这边须要一个wsdl,咱们不可能用http://这样形式的wsdl,由于咱们此时没有用户名和密码,若是咱们使 用的是http://这样形式的wsdl直接会抛“受权认证出错”,所以咱们使用jax-ws在编译服务端时生成的本地wsdl
2) 使用BindingProvider输入用户名与密码,最后再使用BindingProvider输入真正的咱们服务端的wsdl即:http://localhost:8080/JaxWSSample/AuthHelloService?wsdl
下面来看运行效果:
故意输错用户名与密码,咱们输入:
bp.getRequestContext().put(
BindingProvider.USERNAME_PROPERTY,
"tomcatws");
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "12345");
再来运行一下:
能够看到,若是用户名密码没有输对,根本没法经过认证,即连http链接都没法正确创建,这样咱们的安全程度极大的提升了。
即实现服务端与客户端的HTTPS通讯,这通常能够保证传输过程当中你的soap报文不会被拦截
咱们的用户名与密码是嵌在soapheader中的,是以明文方式存在的,若是一旦被推截,将形成灾难性的结果,所以咱们须要将咱们的soap报文中header部分进行加密,这就是ws-security。
且慢些加密咱们的soap-header,要加密很简单,直接使用对称或者非对称算法把用户名密码加个密而后传输至服务端解密不就完了。
是,是能够这么作,但你有没有想过,若是你的客户端使用的是Java,服务端使用的是.net或者php怎么办?对方能用java api来解密吗?
这时,咱们就要使用wcf了,一块儿来看,什么叫wcf.
Industry Standard WS-Security
Sun Microsystems and Microsoft jointly test Metro against WCF toensure that Sun web service clients (consumers) and web services (producers) doin fact interoperate with WCF web services applications and vice versa. Thistesting ensures that the following interoperability goals are realized:
l Metro web services clients can access and consume WCF web services.
l WCF web services clients can access and consume Metro web services.
Sun provides Metro on the Java platform and Microsoft provides WCFon the .NET 3.0 and .NET 3.5 platforms. The sections that follow describe theweb services specifications implemented by Sun Microsystems in Web ServicesInteroperability Technologies (WSIT) and provide high-level descriptions of howeach WSIT technology works.
这边出现了一个名词叫:Metro,这是一个基于JAXWS实现ws-security的标准框架,而Metro支持wcf协议。
如今知道我为何让你们用jax-ws的意图了吧。
Metro支持的ws-security有如下几种:
ü Username Authentication with Symmetric Key
ü Username Authentication with Password Derived Keys
ü Mutual Certificates Security
ü Symmetric Binding with Kerberos Tokens
ü Transport Security (SSL)
ü Message Authentication over SSL
ü SAML Authorization over SSL
ü Endorsing Certificate
ü SAML Sender Vouches with Certificates
ü SAML Holder of Key
ü STS Issued Token
ü STS Issued Token with Service Certificate
ü STS Issued Endorsing Token
真够多的啊,咱们看第一种,就是咱们说的基于用户名密码的ws-security,并且这个soap报文中的用户名与密码是被加密的。
要写符合WCF的webservice须要在webservice中引入QoS概念。
什么是QoS,从字面上理解就是qualityof service,它是一个很广的概念,它主要是把传统的一个webservice从架构上再分红7个部分,即你的webservice须要包含下面7个主要的方面:
ü Availability
ü Performance
ü Reliability
ü Regulatory
ü Security
ü Integrity
ü Accessibility
QoS所处的位置:
看到这边你们头不要大,咱们一块儿来看,到底怎么来实现QoS呢?
咱们使用QoS中的security来实现咱们的soap报文的加密与传输,下面给出一个soap报文片断:
<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="..." xmlns:wsa="..."> <soapenv:Header> <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1"> <wsse:BinarySecurityToken xmlns:wsu=...>MIIBvT...BnesE0=</wsse:BinarySecurityToken> <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <wsse:SecurityTokenReference> <wsse:KeyIdentifier EncodingType="..." ValueType="...">hS6nfYE9axFgay+gorMEo0I4GfY= </wsse:KeyIdentifier> </wsse:SecurityTokenReference> </ds:KeyInfo> <CipherData> <CipherValue>OULe5mAxLwYibommo1Ui/...1gvtagYQ=</CipherValue> </CipherData> |
如何生成上面这个soap报文的呢?
此时,你的webservice须要引入一个policy描述,即ws-policy,下面给出一个policy的片断:
<wsp:Policy wsu:Id="HelloPortBindingPolicy"> <wsp:ExactlyOne> <wsp:All> <wsam:Addressing wsp:Optional="false"/> <sp:SymmetricBinding> <wsp:Policy> <sp:ProtectionToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"> <wsp:Policy> <sp:WssX509V3Token10/> <sp:RequireIssuerSerialReference/> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:ProtectionToken> <sp:Layout> <wsp:Policy> <sp:Strict/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:OnlySignEntireHeadersAndBody/> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic128/> </wsp:Policy> </sp:AlgorithmSuite> |
即,在布署webservice时,须要把空上policy和wsdl一块儿编译成带有QoS的webservice。
在这个教程中,我不会带出从头到尾如何生成ws-policy和相应的带有QoS的Webservice以及相关的客户端。
由于你们若是把jax-ws的前五天基础教程看完后,加上我这后三天的教程,彻底能够本身有能力去用Metro来本身实现相关的soap报文加密。
这属于很是easy的事,搞个2-3天就能实现。
同时,通常的项目,可以真正用到经过soap报文传递用户名与密码或者经过handler的,并很少,通常都是用http://login.do?username=xxx&pwd=xxx这种拍屁股的作法在传用户名与密码,顶多加个https了不起了。
若是当你碰到真正作到了带有QoS的webservice时,本身结合我这8天教程,本身搞一下Metro就能搞得定,实在不行了,再来找我。
最后,给你们推荐3样东西:
1. Tomcat6扔了吧,用7了
2. 下载netbean7.0.1(其中自带tomcat7)
3. 使用glassfish3(支持J2EE6规范),一个缩小免费版的weblogic
若是你对QoS有兴趣,使用上述3样东西会简化你的学习过程。