Axis1 WS Security encryption and signing with wss4j

สำหรับที่คนทำ Web Service สาย Enterprise การ Encryption น่าจะเรียกได้ว่าเป็นท่าบังคับที่ควรจะทำเป็นก็ว่าได้ โพสต์นี้จะทำการแก้ไข Service Upload file ต่อจากตอนที่แล้ว เพราะฉะนั้นจะต้องเตรียม Service และทำ Security Username Token ผ่านก่อนจึงจะเริ่มจุดนี้ได้สะดวกขึ้น

เตรียมเครื่องมือ


ผมเพิ่ม Lib มาสองตัวที่เป็น Optional (เพื่อให้ warning ของ axis1 หายไป) และอีกตัวบังคับว่าต้องมี (เพราะในตอนที่แล้วผมยังไม่ได้เพิ่ม) ดังนี้

  1. activation-1.1.1.jar
  2. mail.jar
  3. xalan-2.7.1.jar (ต้องมี ไม่เช่นนั้นจะขึ้นข้อความแบบนี้)

Generate Key and import certificate


การ encryption และ signing จำเป็นต้องมี public/private key ทั้ง client และ server ซึ่งในสถานการณ์จริง private key ก็จะเก็บไว้ที่ keystore ของแต่ละฝ่าย แล้วนำ public key ของแต่ละฝ่ายมา import เข้า keystore ซึ่งผมจะไม่พาทำนะครับ แต่แนะนำให้ตามทำเว็บนี้เพื่อใช้ในการประกอบบทความได้ แต่ว่า password ในตัวอย่างของผมไม่เหมือนกับในตัวอย่างนะครับ โปรดระวังด้วย

ลงมือฝั่ง Server


  1. หลังจากเตรียม server.jks ที่ import client.cert เสร็จแล้วก็ทำการเพิ่ม Lib สามตัวเข้าไปยัง WEB-INF/lib
  2. เปิดไฟล์ server_config.wsdd แล้วไปแก้ไขแท็ก requestFlow ก่อนในตอนที่แล้วให้เป็นดังนี้
    <ns1:requestFlow>
    	<ns1:handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    		<ns1:parameter name="action" value="Signature Encrypt" />
    		<ns1:parameter name="signaturePropFile"
    			value="crypto.properties" />
    		<ns1:parameter name="passwordCallbackClass" value="ws.SecureCallback" />
    	</ns1:handler>
    </ns1:requestFlow>
    

    สิ่งที่เปลี่ยนไปจากตอนที่แล้วคือ action และ config ที่จะใช้ในการกำหนดค่าพวก keystore

  3. สร้างไฟล์ชื่อ crypto.properties เก็บไว้ใน src แล้วเพิ่ม config นี้เข้าไป
    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=abc123
    org.apache.ws.security.crypto.merlin.keystore.alias=server
    org.apache.ws.security.crypto.merlin.file=E:/workspace/keys/server/server.jks
  4. แก้ไขไฟล์ SecureCallback.java ใหม่ดังนี้
    package ws;
    
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.ws.security.WSPasswordCallback;
    
    public class SecureCallback implements CallbackHandler {
    
    	@Override
    	public void handle(Callback[] callbacks) throws IOException,
    			UnsupportedCallbackException {
    		for (int i = 0; i < callbacks.length; i++) {
    
    			if (callbacks[i] instanceof WSPasswordCallback) {
    				WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
    				String id = pc.getIdentifier();
    				int usage = pc.getUsage();
    
    				if (usage == WSPasswordCallback.DECRYPT
    						|| usage == WSPasswordCallback.SIGNATURE) {
    					// used to retrieve password for private key
    					if ("server".equals(id)) {
    						pc.setPassword("secret");
    					}
    				}
    			} else {
    				throw new UnsupportedCallbackException(callbacks[i],
    						"Unrecognized Callback");
    			}
    		}
    	}
    }
    
    
  5. Start Server หากไม่พบ Error ถือว่าผ่าน

ลงมือฝั่ง Client


  1. หลังจากเตรียม client.jks ที่ import server.cert เสร็จแล้วก็ทำการเพิ่ม Lib สามตัวเข้ามาแล้ว add เข้า build path
  2. แก้ไขไฟล์ client_deploy.wsdd ดังนี้
    <deployment xmlns="http://xml.apache.org/axis/wsdd/"
    	xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    
    	<transport name="http"
    		pivot="java:org.apache.axis.transport.http.HTTPSender" />
    
    	<globalConfiguration>
    		<requestFlow>
    			<handler type="java:org.apache.ws.axis.security.WSDoAllSender">
    				<parameter name="user" value="client" />
                    <parameter name="encryptionUser" value="server"/>
                    <parameter name="action" value="Signature Encrypt" />
                    <parameter name="signaturePropFile" value="crypto.properties" />
                    <parameter name="passwordCallbackClass" value="client.PWCallback" />
    			</handler>
    		</requestFlow>
    	</globalConfiguration>
    
    </deployment>
    

    user คือ align ของ client
    encryptionUser คือ align ของ server ที่ import เข้ามาใน keystore

  3. สร้างไฟล์ชื่อ crypto.properties เก็บไว้ใน src แล้วเพิ่ม config นี้เข้าไป
    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=asdf1234
    org.apache.ws.security.crypto.merlin.keystore.alias=client
    org.apache.ws.security.crypto.merlin.file=E:/workspace/keys/client/client.jks
  4. แก้ไขไฟล์ PWCallback.java ดังนี้
    package client;
    
    import java.io.IOException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    
    import org.apache.ws.security.WSPasswordCallback;
    
    public class PWCallback implements CallbackHandler {
    
    	@Override
    	public void handle(Callback[] callbacks) throws IOException,
    			UnsupportedCallbackException {
    		for (int i = 0; i < callbacks.length; i++) {
    			if (callbacks[i] instanceof WSPasswordCallback) {
    				WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
    				String id = pc.getIdentifier();
    				int usage = pc.getUsage();
    				if (usage == WSPasswordCallback.DECRYPT
    						|| usage == WSPasswordCallback.SIGNATURE) {
    					// used to retrieve password for private key
    					if ("client".equals(id)) {
    						pc.setPassword("asdf1234");
    					}
    				}
    			} else {
    				throw new UnsupportedCallbackException(callbacks[i],
    						"Unrecognized Callback");
    			}
    		}
    	}
    }
    
    
  5. หาก config ถูกต้องและมี lib xalan ใน build path เมื่อรันโปรแกรมก็จะสามารถ upload file ได้
  6. ผมสร้าง keystore ฝั่ง client อีกตัวหนึ่ง แต่ไม่ได้ส่ง public key ให้ทางฝั่ง server ทำการ import เข้าไป ทำให้เมื่อรันฝั่ง client ได้ผลลัพธ์ดังนี้
    wss4j client key failed

อ้างอิง


http://ws.apache.org/wss4j/package.html

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s