Dennis Sosnoski tiếp tục loạt bài các dịch vụ Web Java của mình bằng việc xem xét WS-Security chi tiết mịn hơn trong Web Services Description Language WSDL-Ngôn ngữ mô tả dịch vụ Web s
Trang 1Các dịch vụ Web Java: Sử dụng độ chi tiết của WS-Security
Áp dụng WS-Security ở mức hoạt động hoặc mức thông báo
Dennis Sosnoski, Nhà tư vấn, Sosnoski Software Solutions, Inc
Tóm tắt: WS-Security (An ninh dịch vụ Web) cho các dịch vụ Web SOAP không
nhất thiết phải là một đề xuất hoặc tất cả hoặc không gì cả Bằng cách cấu hình WS-Security tại mức hoạt động hoặc mức thông diệp, bạn có thể áp dụng một mức
độ bảo vệ thích hợp cho mọi trao đổi, giảm hoặc loại bỏ chi phí WS-Security cho
các hoạt động không cần bảo vệ đầy đủ Dennis Sosnoski tiếp tục loạt bài các dịch
vụ Web Java của mình bằng việc xem xét WS-Security chi tiết mịn hơn trong Web
Services Description Language (WSDL-Ngôn ngữ mô tả dịch vụ Web) sử dụng Axis2 và Rampart của Apache
Trong các môi trường dịch vụ Web đơn giản, các máy khách kết nối trực tiếp đến các máy chủ và các máy chủ trực tiếp thực hiện tất cả các xử lý cần thiết cho yêu cầu Như các bạn đã tìm hiểu trong bài viết trước của loạt bài này, các kết nối an ninh SSL có thể cung cấp an ninh tuyệt vời cho hầu hết các mục đích trong kiểu môi trường này Tuy nhiên, môi trường phức tạp hơn đang ngày càng phổ biến, trong đó nhiều tầng của các máy chủ tham gia vào việc xử lý một yêu cầu Toàn
bộ ý tưởng của cách dàn dựng (orchestration) dịch vụ đang ngày càng phổ biến trong nhiều môi trường doanh nghiệp, là dựa vào cách tiếp cận này, như là khái niệm về kiến trúc hướng dịch vụ (SOA) Trong các kiểu môi trường này, sự lựa chọn WS-Security mạnh hơn là cần thiết
Về loạt bài này
Các dịch vụ Web là một phần chủ yếu của vai trò công nghệ Java trong điện toán doanh nghiệp Trong loạt bài viết này, nhà tư vấn XML và các dịch vụ Web
Dennis Sosnoski trình bày các khung công tác và công nghệ chính rất quan trọng với các nhà phát triển Java khi sử dụng các dịch vụ Web Hãy theo dõi loạt bài này
để cập nhật những phát triển mới nhất trong lĩnh vực này và hiểu được bạn có thể
sử dụng chúng để hỗ trợ cho các dự án lập trình của bạn như thế nào
WS-Security đòi hỏi chi phí hiệu năng lớn, như đã thảo luận trong bài viết trước Một cách để giảm chi phí đó là thiết lập WS-SecurityPolicy (Chính sách an ninh dịch vụ Web) thích hợp cho từng hoạt động riêng lẻ hoặc thậm chí mỗi thông điệp được một dịch vụ xác định, hơn là áp dụng chỉ một WS-SecurityPolicy với toàn bộ dịch vụ Sử dụng độ chi tiết mịn hơn của WS-Security đòi hỏi phải xem xét nhiều hơn so với cách tiếp cận một-kích-cỡ-vừa-với-tất-cả, nhưng khi được áp dụng
Trang 2đúng cách nó có thể làm giảm chi phí hiệu năng cho các hoạt động thường được sử dụng mà không làm suy yếu việc bảo đảm an ninh của các hoạt động cần đến nó Định nghĩa một chính sách
Ứng dụng ví dụ được sử dụng cho bài viết này chính là ứng dụng đã sử dụng trong
"Axis2 WS-Security basics" (Những điều cơ bản về An ninh dịch vụ Web của Axis2) và "Axis2 WS-Security signing and encryption" (Ký và mã hoá trong An ninh dịch vụ Web của Axis2) — một dịch vụ quản lý thư viện đơn giản - (Xem Tải
về để nhận được mã nguồn đầy đủ cho bài này) Dịch vụ này định nghĩa ba hoạt động:
getBook để lấy ra các chi tiết về một cuốn sách cụ thể được nhận diện bằng
mã số sách tiêu chuẩn quốc tế (ISBN - International Standard Book
Number)
getBooksByType để lấy ra các chi tiết cho tất cả các cuốn sách thuộc một kiểu cụ thể
addBook để thêm một cuốn sách mới vào thư viện
Để đưa ra một số tính đa dạng thú vị trong việc bảo đảm an ninh, bài viết này giả định rằng:
Hoạt động getBook có thể trưng ra một cách an toàn cho bất cứ ai (không
có bảo mật)
getBooksByType cần một sự cấp phép (vì thế đòi hỏi một
UsernameToken)
Hoạt động addBook cần một lịch sử hoạt động để lần theo vết ai đã gửi mỗi cuốn sách (được thực hiện bằng cách ký các thông báo yêu cầu)
Trong các bài viết trước, bạn đã thấy cách cấu hình Axis2/Rampart bằng cách gắn một tài liệu WS-SecurityPolicy vào cá thể org.apache.axis2.client.ServiceClient (ở phía máy khách) hoặc bằng cách nhúng tài liệu chính sách trong tệp cấu hình dịch
vụ services.xml (ở phía máy chủ) Cách tiếp cận này làm việc được và có thể có ích trong việc thử nghiệm, nhưng đối với việc chạy sản xuất, tốt nhất là kết hợp trực tiếp WS-SecurityPolicy với một định nghĩa dịch vụ bằng cách nhúng nó trong một tài liệu WSDL WS-Policy và WS-SecurityPolicy được thiết kế để hỗ trợ kiểu nhúng này, với các tham chiếu từ các định nghĩa <wsdl:binding>,
<wsdl:binding>/<wsdl:operation>, hoặc
<wsdl:binding>/<wsdl:operation>/<wsdl:message> được sử dụng để nhận biết
Trang 3chính sách thích hợp được áp dụng cho liên kết, hoạt động hoặc thông báo đó Axis2 1.4.1 đã triển khai thực hiện xử lý sơ bộ cho các chính sách được nhúng trong WSDL và trển khai thực hiện này đã được cải thiện trong mã của bản phát hành Axis2 1.5 hiện tại Để giải thích việc sử dụng chính sách trong WSDL, bài viết này sử dụng mã của bản phát hành Axis2 1.5 kết hợp với mã Rampart hiện tại chưa phát hành (mà cuối cùng sẽ phải được phát hành như Rampart 1.5)
Liệt kê 1 cho thấy WSDL dành cho ứng dụng ví dụ có chính sách được thêm vào
và được tham chiếu từ các vị trí thích hợp (Liệt kê 1 đã chỉnh sửa để vừa chiều dài
và chiều rộng; WSDL đầy đủ có sẵn trong tệp library.wsdl trong phần tải mã.) Mỗi chính sách định nghĩa một giá trị Id (mã nhận dạng) mà sau đó giá trị này được tham khảo từ hoạt động thích hợp (trong trường hợp của chính sách
UsernameToken) hoặc thông báo (trong trường hợp của chính sách ký), tất cả được chỉ ra bằng in đậm
Liệt kê 1 WSDL với các chính sách an ninh chi tiết
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<! Policy for signing message, with certificate from client included in each message to server >
<wsp:Policy wsu:Id="SignOnly" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
Trang 4<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token
sp:IncludeToken=" /IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:InitiatorToken>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <sp:Body/>
</sp:SignedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Trang 5<! Policy for UsernameToken with plaintext password, sent from client to server only >
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <wsp:Policy>
<sp:UsernameToken
sp:IncludeToken=" /IncludeToken/AlwaysToRecipient"/>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsdlsoap:binding style="document"
Trang 6transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="getBooksByType">
<wsp:PolicyReference
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameToken"/>
<wsdlsoap:operation soapAction="urn:getBooksByType"/> <wsdl:input name="getBooksByTypeRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBooksByTypeResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
Trang 7</wsdl:operation>
<wsdl:operation name="addBook">
<wsdlsoap:operation soapAction="urn:addBook"/>
<wsdl:input name="addBookRequest">
<wsp:PolicyReference
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
URI="#SignOnly"/>
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="addBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="library-granular">
</wsdl:service>
</wsdl:definitions>
Các chính sách và WSDL trong Liệt kê 1 tất cả đều được lấy từ các bài viết trước, mặc dù trước đó đã không được hòa trộn theo cách này Mặc dù vậy, bạn có thể
Trang 8nhận ra một sự khác biệt đáng kể trong các chính sách: tất cả các phiên bản trước
đó đã bao gồm các thông tin cấu hình Rampart, là đặc thù cho hoặc máy khách hoặc máy chủ Bây giờ chính sách này được nhúng vào trong WSDL, vì bao gồm trực tiếp cấu hình Rampart không phải là cách làm tốt (Bạn sẽ cần phải chỉnh sửa WSDL để bao gồm thông tin cấu hình Rampart của máy khách của bạn và tạo lại
mã mỗi lần thông tin cấu hình này thay đổi và trên máy chủ, thông tin cấu hình Rampart của bạn sẽ được trưng ra với bất kỳ ai truy cập vào WSDL) Vì vậy, thay vào đó mã ví dụ thiết lập thông tin cấu hình này riêng rẽ Để làm điều này, nó sử dụng các biến thể của chính kỹ thuật được sử dụng trước đây cho các chính sách
có bao gồm cả cấu hình Rampart
Cách sử dụng phía máy khách
Việc tạo mã từ WSDL vẫn làm việc như cũ theo quan điểm người dùng cho dù có bao gồm WS-Policy hay không Nếu bạn nhìn bên trong gốc máy khách được tạo
ra từ một WSDL có chứa WS-Policy, bạn sẽ thấy rằng chính sách này được gắn trực tiếp với các thành phần mô tả dịch vụ khi nó đang được xây dựng, nhưng điều này được ẩn dấu bên trong việc triển khai thực hiện và không làm ảnh hưởng đến các phương thức giao diện mà mã máy khách của bạn sử dụng
Để tiến hành sử dụng cấu hình WS-SecurityPolicy trên máy khách, bạn cần phải
thực hiện một vài hành động trong mã máy khách của bạn Ít nhất, bạn phải gài
mô đun Rampart trên org.apache.axis2.client.ServiceClient kết hợp với cá thể của bạn Bước này là cần thiết thậm chí nếu bạn bao gồm các thông tin cấu hình
Rampart của bạn trong WSDL Thật không may, ở đây dường như không có bất
kỳ cách làm nào để gài Rampart tại mức hoạt động hay mức thông báo trong mã hiện tại, do đó một phần ích lợi của WS-Security mức chi tiết mịn hơn bị mất vào lúc này khi nó được sử dụng với một máy khách Axis2
Nếu bạn duy trì cấu hình Rampart của bạn tách biệt khỏi WSDL như đã khuyến cáo, bạn cũng cần phải áp dụng cấu hình đó cho mô tả dịch vụ Liệt kê 2 cho thấy
mã máy khách được sử dụng cho mục đích này trong ứng dụng ví dụ Nó gọi phương thức applyPolicy() để thêm chính sách có chứa cấu hình Rampart vào định nghĩa dịch vụ
Liệt kê 2 Cấu hình các hoạt động phía máy khách
Trang 9// create the client stub
String target = args[0] + "://" + args[1] + ":" + args[2] + args[3];
System.out.println("Connecting to " + target);
LibraryGranularStub stub = new LibraryGranularStub(target);
// configure and engage rampart module
ServiceClient client = stub._getServiceClient();
client.getAxisService().applyPolicy(loadPolicy("rampart-client-policy.xml")); client.engageModule("rampart");
// set the username and password for requests which use them
Options options = client.getOptions();
options.setUserName("libuser");
options.setPassword("books");
Mã trong Liệt kê 2 thiết lập tên người dùng và mật khẩu cho các tùy chọn
ServiceClient có nghĩa là chúng được định nghĩa cho tất cả các hoạt động sử dụng dịch vụ đó ngay cả khi chúng được sử dụng bởi chỉ một hoạt động Không giống như việc gài mô đun Rampart cho tất cả các hoạt động, việc thiết lập tên người dùng và mật khẩu theo cách này không gây thiệt hại — các giá trị được sử dụng chỉ khi cần có Rampart để xây dựng một UsernameToken và nếu không cần thì được bỏ qua
Tài liệu chính sách có chứa cấu hình Rampart được hiển thị trong Liệt kê 3 Đây chính là chính sách đã sử dụng trong "Ký và mã hóa WS-Security của Axis2," bây giờ được trích xuất thành một tài liệu chính sách riêng biệt
Trang 10Liệt kê 3 Chính sách cấu hình máy khách Rampart
<wsp:Policy xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy"> <ramp:user>clientkey</ramp:user>
<ramp:passwordCallbackClass
>com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>
<ramp:signatureCrypto>
<ramp:crypto
provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.type"
>JKS</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file"
>client.keystore</ramp:property>
<ramp:property
Trang 11name="org.apache.ws.security.crypto.merlin.keystore.password"
>nosecret</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Tệp build.xml của Ant có trong phần mã tải về sẽ xử lý việc sinh ra cả mã máy khách và mã máy chủ từ WSDL, biên dịch mã và tạo tệp AAR dịch vụ Nó cũng sao chép chính sách cấu hình Rampart (được cung cấp trong phần tải về dưới dạng tệp rampart-client-policy.xml, trong thư mục gốc) vào trong đường dẫn lớp
(classpath) của máy khách, cùng với thực hiện một số việc xử lý chính sách phía máy chủ được thảo luận trong phần tiếp theo
Cách sử dụng phía máy chủ
Nếu bạn muốn giữ cấu hình Rampart phía máy chủ của bạn bên ngoài WSDL (nói chung đó là một ý tưởng rất tốt) bạn cần phải bao gồm nó trong tệp services.xml
để thay thế! Trong các bài viết trước, bạn đã thấy điều này đã được thực hiện với một cấu hình WS- SecurityPolicy đầy đủ, bao gồm cả cấu hình Rampart và được
áp dụng cho dịch vụ nói chung Lúc này, chính sách cấu hình Rampart là phần duy nhất được thêm vào services.xml và nó được thực hiện ở mức hoạt động