diff --git a/mitre-local b/mitre-local
index f1f301046..b81dd3091 160000
--- a/mitre-local
+++ b/mitre-local
@@ -1 +1 @@
-Subproject commit f1f301046b6c6f397bc4d40a25dd407ca6f2b757
+Subproject commit b81dd3091e53be285bbfd9f0886b5a88b2cab19c
diff --git a/pom.xml b/pom.xml
index 1a0d6dc47..0de433283 100644
--- a/pom.xml
+++ b/pom.xml
@@ -194,7 +194,7 @@
com.google.code.gson
gson
- 1.7.1
+ 2.0
org.eclipse.persistence
@@ -214,7 +214,7 @@
com.google.guava
guava
- r09
+ 10.0.1
org.apache.httpcomponents
@@ -229,7 +229,12 @@
commons-codec
commons-codec
- 1.3
+ 1.6
+
+
+ org.bouncycastle
+ bcprov-jdk16
+ 1.46
diff --git a/src/main/java/org/mitre/jwt/Jwt.java b/src/main/java/org/mitre/jwt/Jwt.java
new file mode 100644
index 000000000..fa47a2605
--- /dev/null
+++ b/src/main/java/org/mitre/jwt/Jwt.java
@@ -0,0 +1,118 @@
+package org.mitre.jwt;
+
+import java.util.List;
+
+import org.apache.commons.codec.binary.Base64;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class Jwt {
+
+ private JwtHeader header = new JwtHeader();
+
+ private JwtClaims claims = new JwtClaims();
+
+ private String signature;
+
+
+
+
+ /**
+ * @return the header
+ */
+ public JwtHeader getHeader() {
+ return header;
+ }
+
+
+
+ /**
+ * @param header the header to set
+ */
+ public void setHeader(JwtHeader header) {
+ this.header = header;
+ }
+
+
+
+ /**
+ * @return the claims
+ */
+ public JwtClaims getClaims() {
+ return claims;
+ }
+
+
+
+ /**
+ * @param claims the claims to set
+ */
+ public void setClaims(JwtClaims claims) {
+ this.claims = claims;
+ }
+
+
+
+ /**
+ * @return the signature
+ */
+ public String getSignature() {
+ return signature;
+ }
+
+
+
+ /**
+ * @param signature the signature to set
+ */
+ public void setSignature(String signature) {
+ this.signature = signature;
+ }
+
+ /**
+ * Return the canonical encoded string of this JWT
+ */
+ public String toString() {
+ JsonObject h = header.getAsJsonObject();
+ JsonObject o = claims.getAsJsonObject();
+
+ String h64 = new String(Base64.encodeBase64URLSafe(h.toString().getBytes()));
+ String o64 = new String(Base64.encodeBase64(o.toString().getBytes()));
+
+ return h64 + "." + o64 + "." + Strings.nullToEmpty(this.signature);
+ }
+
+
+ /**
+ * Parse a wire-encoded JWT
+ */
+ public static Jwt parse(String s) {
+
+ // split on the dots
+ List parts = Lists.newArrayList(Splitter.on(".").split(s));
+
+ if (parts.size() != 3) {
+ throw new IllegalArgumentException("Invalid JWT format.");
+ }
+
+ String h64 = parts.get(0);
+ String o64 = parts.get(1);
+ String s64 = parts.get(2);
+
+ JsonParser parser = new JsonParser();
+
+
+
+ // shuttle for return value
+ Jwt jwt = new Jwt();
+
+ return jwt;
+
+ }
+
+}
diff --git a/src/main/java/org/mitre/jwt/JwtClaims.java b/src/main/java/org/mitre/jwt/JwtClaims.java
new file mode 100644
index 000000000..dd4124db4
--- /dev/null
+++ b/src/main/java/org/mitre/jwt/JwtClaims.java
@@ -0,0 +1,236 @@
+package org.mitre.jwt;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.JsonObject;
+
+public class JwtClaims {
+
+ /**
+ * ISO8601 / RFC3339 Date Format
+ */
+ public static DateFormat dateFormat = new SimpleDateFormat("YYYY-MM-DD'T'HH:mm:ssz");
+
+ private Date expiration;
+
+ private Date notBefore;
+
+ private Date issuedAt;
+
+ private String issuer;
+
+ private String audience;
+
+ private String principal;
+
+ private String jwtId;
+
+ private String type;
+
+ private Map claims = new HashMap();
+
+ public JwtClaims() {
+
+ }
+
+ /**
+ * @return the expiration
+ */
+ public Date getExpiration() {
+ return expiration;
+ }
+
+ /**
+ * @param expiration the expiration to set
+ */
+ public void setExpiration(Date expiration) {
+ this.expiration = expiration;
+ }
+
+ /**
+ * @return the notBefore
+ */
+ public Date getNotBefore() {
+ return notBefore;
+ }
+
+ /**
+ * @param notBefore the notBefore to set
+ */
+ public void setNotBefore(Date notBefore) {
+ this.notBefore = notBefore;
+ }
+
+ /**
+ * @return the issuedAt
+ */
+ public Date getIssuedAt() {
+ return issuedAt;
+ }
+
+ /**
+ * @param issuedAt the issuedAt to set
+ */
+ public void setIssuedAt(Date issuedAt) {
+ this.issuedAt = issuedAt;
+ }
+
+ /**
+ * @return the issuer
+ */
+ public String getIssuer() {
+ return issuer;
+ }
+
+ /**
+ * @param issuer the issuer to set
+ */
+ public void setIssuer(String issuer) {
+ this.issuer = issuer;
+ }
+
+ /**
+ * @return the audience
+ */
+ public String getAudience() {
+ return audience;
+ }
+
+ /**
+ * @param audience the audience to set
+ */
+ public void setAudience(String audience) {
+ this.audience = audience;
+ }
+
+ /**
+ * @return the principal
+ */
+ public String getPrincipal() {
+ return principal;
+ }
+
+ /**
+ * @param principal the principal to set
+ */
+ public void setPrincipal(String principal) {
+ this.principal = principal;
+ }
+
+ /**
+ * @return the jwtId
+ */
+ public String getJwtId() {
+ return jwtId;
+ }
+
+ /**
+ * @param jwtId the jwtId to set
+ */
+ public void setJwtId(String jwtId) {
+ this.jwtId = jwtId;
+ }
+
+ /**
+ * @return the type
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * @param type the type to set
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * Get an extension claim
+ */
+ public Object getClaim(String key) {
+ return claims.get(key);
+ }
+
+ /**
+ * Set an extension claim
+ */
+ public void setClaim(String key, Object value) {
+ claims.put(key, value);
+ }
+
+ /**
+ * Remove an extension claim
+ */
+ public Object removeClaim(String key) {
+ return claims.remove(key);
+ }
+
+ /**
+ * Get a copy of this header as a JsonObject. The JsonObject is not
+ * backed by a live copy of this JwtHeader.
+ * @return a copy of the data in this header in a JsonObject
+ */
+ public JsonObject getAsJsonObject() {
+ JsonObject o = new JsonObject();
+
+ if (this.expiration != null) {
+ o.addProperty("exp", dateFormat.format(this.expiration));
+ }
+
+ if (this.notBefore != null) {
+ o.addProperty("nbf", dateFormat.format(this.notBefore));
+ }
+
+ if (this.issuedAt != null) {
+ o.addProperty("iat", dateFormat.format(this.issuedAt));
+ }
+
+ if (this.issuer != null) {
+ o.addProperty("iss", this.issuer);
+ }
+
+ if (this.audience != null) {
+ o.addProperty("aud", this.audience);
+ }
+
+ if (this.principal != null) {
+ o.addProperty("prn", this.principal);
+ }
+
+ if (this.jwtId != null) {
+ o.addProperty("jti", this.jwtId);
+ }
+
+ if (this.type != null) {
+ o.addProperty("typ", this.type);
+ }
+
+ if (this.claims != null) {
+ for (Map.Entry claim : this.claims.entrySet()) {
+ if (claim.getValue() instanceof String) {
+ o.addProperty(claim.getKey(), (String)claim.getValue());
+ } else if (claim.getValue() instanceof Number) {
+ o.addProperty(claim.getKey(), (Number)claim.getValue());
+ } else if (claim.getValue() instanceof Boolean) {
+ o.addProperty(claim.getKey(), (Boolean)claim.getValue());
+ } else if (claim.getValue() instanceof Character) {
+ o.addProperty(claim.getKey(), (Character)claim.getValue());
+ } else if (claim.getValue() != null) {
+ // try to put it in as a string
+ o.addProperty(claim.getKey(), claim.getValue().toString());
+ } else {
+ // otherwise add in as a null
+ o.add(claim.getKey(), null);
+ }
+ }
+ }
+
+ return o;
+ }
+
+}
diff --git a/src/main/java/org/mitre/jwt/JwtHeader.java b/src/main/java/org/mitre/jwt/JwtHeader.java
new file mode 100644
index 000000000..fd7560769
--- /dev/null
+++ b/src/main/java/org/mitre/jwt/JwtHeader.java
@@ -0,0 +1,133 @@
+package org.mitre.jwt;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gson.JsonObject;
+
+public class JwtHeader {
+
+ private String type;
+
+ private String algorithm;
+
+ private String encryptionMethod;
+
+ private Map claims = new HashMap();
+
+
+ public JwtHeader() {
+
+ }
+
+
+ /**
+ * @return the type
+ */
+ public String getType() {
+ return type;
+ }
+
+
+ /**
+ * @param type the type to set
+ */
+ public void setType(String type) {
+ this.type = type;
+ }
+
+
+ /**
+ * @return the algorithm
+ */
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+
+ /**
+ * @param algorithm the algorithm to set
+ */
+ public void setAlgorithm(String algorithm) {
+ this.algorithm = algorithm;
+ }
+
+
+ /**
+ * @return the encryptionMethod
+ */
+ public String getEncryptionMethod() {
+ return encryptionMethod;
+ }
+
+
+ /**
+ * @param encryptionMethod the encryptionMethod to set
+ */
+ public void setEncryptionMethod(String encryptionMethod) {
+ this.encryptionMethod = encryptionMethod;
+ }
+
+ /**
+ * Get an extension claim
+ */
+ public Object getClaim(String key) {
+ return claims.get(key);
+ }
+
+ /**
+ * Set an extension claim
+ */
+ public void setClaim(String key, Object value) {
+ claims.put(key, value);
+ }
+
+ /**
+ * Remove an extension claim
+ */
+ public Object removeClaim(String key) {
+ return claims.remove(key);
+ }
+
+ /**
+ * Get a copy of this header as a JsonObject. The JsonObject is not
+ * backed by a live copy of this JwtHeader.
+ * @return a copy of the data in this header in a JsonObject
+ */
+ public JsonObject getAsJsonObject() {
+ JsonObject o = new JsonObject();
+
+ o.addProperty("typ", this.type);
+ if (this.algorithm != null) {
+ o.addProperty("alg", this.algorithm);
+ }
+
+ if (this.encryptionMethod != null) {
+ o.addProperty("enc", this.encryptionMethod);
+ }
+
+ if (this.claims != null) {
+ for (Map.Entry claim : this.claims.entrySet()) {
+ if (claim.getValue() instanceof String) {
+ o.addProperty(claim.getKey(), (String)claim.getValue());
+ } else if (claim.getValue() instanceof Number) {
+ o.addProperty(claim.getKey(), (Number)claim.getValue());
+ } else if (claim.getValue() instanceof Boolean) {
+ o.addProperty(claim.getKey(), (Boolean)claim.getValue());
+ } else if (claim.getValue() instanceof Character) {
+ o.addProperty(claim.getKey(), (Character)claim.getValue());
+ } else if (claim.getValue() != null) {
+ // try to put it in as a string
+ o.addProperty(claim.getKey(), claim.getValue().toString());
+ } else {
+ // otherwise add in as a null
+ o.add(claim.getKey(), null);
+ }
+ }
+ }
+
+ return o;
+ }
+
+
+}
diff --git a/src/main/java/org/mitre/jwt/JwtSigner.java b/src/main/java/org/mitre/jwt/JwtSigner.java
new file mode 100644
index 000000000..3d2f3c797
--- /dev/null
+++ b/src/main/java/org/mitre/jwt/JwtSigner.java
@@ -0,0 +1,7 @@
+package org.mitre.jwt;
+
+public interface JwtSigner {
+
+ public void sign(Jwt jwt);
+
+}
diff --git a/src/main/java/org/mitre/openid/connect/model/IdToken.java b/src/main/java/org/mitre/openid/connect/model/IdToken.java
index 734f6bd9e..7e55800b9 100644
--- a/src/main/java/org/mitre/openid/connect/model/IdToken.java
+++ b/src/main/java/org/mitre/openid/connect/model/IdToken.java
@@ -2,11 +2,13 @@ package org.mitre.openid.connect.model;
import javax.persistence.Entity;
+import org.mitre.jwt.Jwt;
+
/*
* TODO: This class needs to be encoded as a JWT
*/
@Entity
-public class IdToken {
+public class IdToken extends Jwt {
private String iss;
private String user_id;
diff --git a/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml b/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
index ca62af15a..0ee38fc01 100644
--- a/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
+++ b/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
@@ -30,7 +30,7 @@
-
-
+
+