在今天的學習中,咱們講開始過渡到一個真正的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樣東西會簡化你的學習過程。