package com.nimbusds.jwt;
import java.text.ParseException;
import java.util.Collections;
import java.util.Iterator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.minidev.json.JSONObject;
import com.nimbusds.jose.util.JSONObjectUtils;
/**
* JSON Web Token (JWT) claims set.
*
* <p>Supports all {@link #getReservedNames reserved claims} of the JWT
* specification:
*
* <ul>
* <li>exp - Expiration Time
* <li>nbf - Not Before
* <li>iat - Issued At
* <li>iss - Issuer
* <li>aud - Audience
* <li>prn - Principal
* <li>jti - JWT ID
* <li>typ - Type
* </ul>
*
* <p>The set may also carry {@link #setCustomClaims custom claims}; these will
* be serialised and parsed along the reserved ones.
*
* @author Vladimir Dzhuvinov
* @version $version$ (2012-09-27)
*/
public class ClaimsSet implements ReadOnlyClaimsSet {
/**
* The reserved claim names.
*/
private static final Set<String> RESERVED_CLAIM_NAMES;
/**
* Initialises the reserved claim name set.
*/
static {
Set<String> n = new HashSet<String>();
n.add("exp");
n.add("nbf");
n.add("iat");
n.add("iss");
n.add("aud");
n.add("prn");
n.add("jti");
n.add("typ");
RESERVED_CLAIM_NAMES = Collections.unmodifiableSet(n);
}
/**
* The expiration time claim.
*/
private long exp = -1l;
/**
* The not-before claim.
*/
private long nbf = -1l;
/**
* The issued-at claim.
*/
private long iat = -1l;
/**
* The issuer claim.
*/
private String iss = null;
/**
* The audience claim.
*/
private String aud = null;
/**
* The principal claim.
*/
private String prn = null;
/**
* The JWT ID claim.
*/
private String jti = null;
/**
* The type claim.
*/
private String typ = null;
/**
* Custom claims.
*/
private Map<String,Object> customClaims = new HashMap<String,Object>();
/**
* Creates a new empty claims set.
*/
public ClaimsSet() {
// Nothing to do
}
/**
* Gets the reserved claim names.
*
* @return The reserved claim names, as an unmodifiable set.
*/
public static Set<String> getReservedNames() {
return RESERVED_CLAIM_NAMES;
}
@Override
public long getExpirationTimeClaim() {
return exp;
}
/**
* Sets the expiration time ({@code exp}) claim.
*
* @param exp The expiration time, -1 if not specified.
*/
public void setExpirationTimeClaim(final long exp) {
this.exp = exp;
}
@Override
public long getNotBeforeClaim() {
return nbf;
}
/**
* Sets the not-before ({@code nbf}) claim.
*
* @param nbf The not-before claim, -1 if not specified.
*/
public void setNotBeforeClaim(final long nbf) {
this.nbf = nbf;
}
@Override
public long getIssuedAtClaim() {
return iat;
}
/**
* Sets the issued-at ({@code iat}) claim.
*
* @param iat The issued-at claim, -1 if not specified.
*/
public void setIssuedAtClaim(final long iat) {
this.iat = iat;
}
@Override
public String getIssuerClaim() {
return iss;
}
/**
* Sets the issuer ({@code iss}) claim.
*
* @param iss The issuer claim, {@code null} if not specified.
*/
public void setIssuerClaim(final String iss) {
this.iss = iss;
}
@Override
public String getAudienceClaim() {
return aud;
}
/**
* Sets the audience ({@code aud}) clam.
*
* @param aud The audience claim, {@code null} if not specified.
*/
public void setAudienceClaim(final String aud) {
this.aud = aud;
}
@Override
public String getPrincipalClaim() {
return prn;
}
/**
* Sets the principal ({@code prn}) claim.
*
* @param prn The principal claim, {@code null} if not specified.
*/
public void setPrincipalClaim(final String prn) {
this.prn = prn;
}
@Override
public String getJWTIDClaim() {
return jti;
}
/**
* Sets the JWT ID ({@code jti}) claim.
*
* @param jti The JWT ID claim, {@code null} if not specified.
*/
public void setJWTIDClaim(final String jti) {
this.jti = jti;
}
@Override
public String getTypeClaim() {
return typ;
}
/**
* Sets the type ({@code typ}) claim.
*
* @param typ The type claim, {@code null} if not specified.
*/
public void setTypeClaim(final String typ) {
this.typ = typ;
}
@Override
public Object getCustomClaim(final String name) {
return customClaims.get(name);
}
/**
* Sets a custom (public or private) claim.
*
* @param name The name of the custom claim. Must not be {@code null}.
* @param value The value of the custom claim, should map to a valid
* JSON entity, {@code null} if not specified.
*
* @throws IllegalArgumentException If the specified custom claim name
* matches a reserved claim name.
*/
public void setCustomClaim(final String name, final Object value) {
if (getReservedNames().contains(name))
throw new IllegalArgumentException("The claim name \"" + name + "\" matches a reserved name");
customClaims.put(name, value);
}
@Override
public Map<String,Object> getCustomClaims() {
return Collections.unmodifiableMap(customClaims);
}
/**
* Sets the custom (non-reserved) claims. The values must be
* serialisable to a JSON entity, otherwise will be ignored.
*
* @param customClaims The custom claims, empty map or {@code null} if
* none.
*/
public void setCustomClaims(final Map<String,Object> customClaims) {
if (customClaims == null)
return;
this.customClaims = customClaims;
}
@Override
public JSONObject toJSONObject() {
JSONObject o = new JSONObject(customClaims);
if (exp > -1)
o.put("exp", exp);
if (nbf > -1)
o.put("nbf", nbf);
if (iat > -1)
o.put("iat", iat);
if (iss != null)
o.put("iss", iss);
if (aud != null)
o.put("aud", aud);
if (prn != null)
o.put("prn", prn);
if (jti != null)
o.put("jti", jti);
if (typ != null)
o.put("typ", typ);
return o;
}
/**
* Parses a JSON Web Token (JWT) claims set from the specified
* JSON object representation.
*
* @param json The JSON object to parse. Must not be {@code null}.
*
* @return The claims set.
*
* @throws ParseException If the specified JSON object doesn't represent
* a valid JWT claims set.
*/
public static ClaimsSet parse(final JSONObject json)
throws ParseException {
ClaimsSet cs = new ClaimsSet();
// Parse reserved + custom params
Iterator<String> it = json.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
if (name.equals("exp"))
cs.setExpirationTimeClaim(JSONObjectUtils.getLong(json, "exp"));
else if (name.equals("nbf"))
cs.setNotBeforeClaim(JSONObjectUtils.getLong(json, "nbf"));
else if (name.equals("iat"))
cs.setIssuedAtClaim(JSONObjectUtils.getLong(json, "iat"));
else if (name.equals("iss"))
cs.setIssuerClaim(JSONObjectUtils.getString(json, "iss"));
else if (name.equals("aud"))
cs.setAudienceClaim(JSONObjectUtils.getString(json, "aud"));
else if (name.equals("prn"))
cs.setPrincipalClaim(JSONObjectUtils.getString(json, "prn"));
else if (name.equals("jti"))
cs.setJWTIDClaim(JSONObjectUtils.getString(json, "jti"));
else if (name.equals("typ"))
cs.setTypeClaim(JSONObjectUtils.getString(json, "typ"));
else
cs.setCustomClaim(name, json.get(name));
}
return cs;
}
}