package org.jboss.resteasy.jose.jws; import org.jboss.resteasy.jose.Base64Url; import org.jboss.resteasy.jose.i18n.Messages; import org.jboss.resteasy.jose.jws.crypto.HMACProvider; import org.jboss.resteasy.jose.jws.crypto.RSAProvider; import org.jboss.resteasy.spi.ResteasyProviderFactory; import javax.crypto.SecretKey; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.ext.MessageBodyWriter; import javax.ws.rs.ext.Providers; import java.io.ByteArrayOutputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; /** * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @version $Revision: 1 $ */ public class JWSBuilder { String type; String contentType; Object content; byte[] contentBytes; MediaType marshalTo; Providers providers; public JWSBuilder() { this(ResteasyProviderFactory.getInstance()); } public JWSBuilder(Providers providers) { this.providers = providers; } public JWSBuilder type(String type) { this.type = type; return this; } public JWSBuilder contentType(String type) { this.contentType = type; return this; } public JWSBuilder contentType(MediaType type) { this.contentType = type.toString(); return this; } public EncodingBuilder content(byte[] bytes) { this.contentBytes = bytes; return new EncodingBuilder(); } public EncodingBuilder content(Object object, MediaType marshalTo) { this.content = object; this.marshalTo = marshalTo; return new EncodingBuilder(); } protected String encodeHeader(Algorithm alg) { StringBuilder builder = new StringBuilder("{"); builder.append("\"alg\":\"").append(alg.toString()).append("\""); if (type != null) builder.append(",\"typ\" : \"").append(type).append("\""); if (contentType != null) builder.append(",\"cty\":\"").append(contentType).append("\""); builder.append("}"); return Base64Url.encode(builder.toString().getBytes(StandardCharsets.UTF_8)); } protected String encode(Algorithm alg, byte[] data, byte[] signature) { StringBuffer encoding = new StringBuffer(); encoding.append(encodeHeader(alg)); encoding.append('.'); encoding.append(Base64Url.encode(data)); encoding.append('.'); if (alg != Algorithm.none) { encoding.append(Base64Url.encode(signature)); } return encoding.toString(); } @SuppressWarnings({"rawtypes", "unchecked"}) protected byte[] marshalContent() { if (contentBytes != null) return contentBytes; ByteArrayOutputStream baos = new ByteArrayOutputStream(); Class<?> type = content.getClass(); Type genericType = null; Object obj = content; if (content instanceof GenericEntity) { GenericEntity<?> ge = (GenericEntity<?>)content; obj = ge.getEntity(); type = ge.getRawType(); genericType = ge.getType(); } if (genericType == null) genericType = type; MessageBodyWriter writer = providers.getMessageBodyWriter(type, genericType, null, marshalTo); if (writer == null) throw new IllegalStateException(Messages.MESSAGES.unableToFindMessageBodyWriter()); try { writer.writeTo(obj, type, genericType, null, marshalTo, new MultivaluedHashMap<String, Object>(), baos); } catch (Exception e) { throw new RuntimeException(e); } return baos.toByteArray(); } public class EncodingBuilder { public String none() { byte[] data = marshalContent(); return encode(Algorithm.none, data, null); } public String rsa256(PrivateKey privateKey) { byte[] data = marshalContent(); byte[] signature = RSAProvider.sign(data, Algorithm.RS256, privateKey); return encode(Algorithm.RS256, data, signature); } public String rsa384(PrivateKey privateKey) { byte[] data = marshalContent(); byte[] signature = RSAProvider.sign(data, Algorithm.RS384, privateKey); return encode(Algorithm.RS384, data, signature); } public String rsa512(PrivateKey privateKey) { byte[] data = marshalContent(); byte[] signature = RSAProvider.sign(data, Algorithm.RS512, privateKey); return encode(Algorithm.RS512, data, signature); } public String hmac256(byte[] sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret); return encode(Algorithm.HS256, data, signature); } public String hmac384(byte[] sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret); return encode(Algorithm.HS384, data, signature); } public String hmac512(byte[] sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret); return encode(Algorithm.HS512, data, signature); } public String hmac256(SecretKey sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS256, sharedSecret); return encode(Algorithm.HS256, data, signature); } public String hmac384(SecretKey sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS384, sharedSecret); return encode(Algorithm.HS384, data, signature); } public String hmac512(SecretKey sharedSecret) { byte[] data = marshalContent(); byte[] signature = HMACProvider.sign(data, Algorithm.HS512, sharedSecret); return encode(Algorithm.HS512, data, signature); } } }