Java tutorial
/** * Copyright 2010 Molindo GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package at.molindo.amazonclient; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.Set; import java.util.TimeZone; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.xml.namespace.QName; import javax.xml.soap.SOAPBody; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPMessage; import javax.xml.ws.handler.Handler; import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.MessageContext; import javax.xml.ws.handler.PortInfo; import javax.xml.ws.handler.soap.SOAPHandler; import javax.xml.ws.handler.soap.SOAPMessageContext; import org.apache.commons.codec.binary.Base64; import org.w3c.dom.Element; import org.w3c.dom.Node; public class AWSHandlerResolver implements HandlerResolver { private final String awsSecretKey; public AWSHandlerResolver(final String awsSecretKey) { this.awsSecretKey = awsSecretKey; } @SuppressWarnings("rawtypes") public List<Handler> getHandlerChain(final PortInfo portInfo) { final List<Handler> handlerChain = new ArrayList<Handler>(); final QName serviceQName = portInfo.getServiceName(); if (serviceQName.getLocalPart().equals("AWSECommerceService")) { handlerChain.add(new AwsHandler(awsSecretKey)); } return handlerChain; } public static class AwsHandler implements SOAPHandler<SOAPMessageContext> { private final byte[] secretBytes; public AwsHandler(final String awsSecretKey) { secretBytes = stringToUtf8(awsSecretKey); } public void close(final MessageContext messagecontext) { } public Set<QName> getHeaders() { return null; } public boolean handleFault(final SOAPMessageContext messagecontext) { return true; } public boolean handleMessage(final SOAPMessageContext messagecontext) { final Boolean outbound = (Boolean) messagecontext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY); if (outbound) { try { final SOAPMessage soapMessage = messagecontext.getMessage(); final SOAPBody soapBody = soapMessage.getSOAPBody(); final Node firstChild = soapBody.getFirstChild(); final String timeStamp = getTimestamp(); final String signature = getSignature(firstChild.getLocalName(), timeStamp, secretBytes); appendTextElement(firstChild, "Signature", signature); appendTextElement(firstChild, "Timestamp", timeStamp); } catch (final SOAPException se) { throw new RuntimeException("SOAPException was thrown.", se); } } return true; } private String getSignature(final String operation, final String timeStamp, final byte[] secretBytes) { try { final String toSign = operation + timeStamp; final byte[] toSignBytes = stringToUtf8(toSign); final Mac signer = Mac.getInstance("HmacSHA256"); final SecretKeySpec keySpec = new SecretKeySpec(secretBytes, "HmacSHA256"); signer.init(keySpec); signer.update(toSignBytes); final byte[] signBytes = signer.doFinal(); final String signature = new String(Base64.encodeBase64(signBytes)); return signature; } catch (final NoSuchAlgorithmException nsae) { throw new RuntimeException("NoSuchAlgorithmException was thrown.", nsae); } catch (final InvalidKeyException ike) { throw new RuntimeException("InvalidKeyException was thrown.", ike); } } private String getTimestamp() { final Calendar calendar = Calendar.getInstance(); final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); return dateFormat.format(calendar.getTime()); } private byte[] stringToUtf8(final String source) { try { return source.getBytes("UTF-8"); } catch (final UnsupportedEncodingException e) { // This will never happen. UTF-8 is always available. throw new RuntimeException("getBytes threw an UnsupportedEncodingException", e); } } private void appendTextElement(final Node node, final String elementName, final String elementText) { final Element element = node.getOwnerDocument().createElement(elementName); element.setTextContent(elementText); node.appendChild(element); } } }