All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.oauth.jsontoken.JsonToken Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/**
 * Copyright 2010 Google Inc.
 *
 * 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 net.oauth.jsontoken;

import java.security.SignatureException;

import org.apache.commons.codec.binary.Base64;
import org.joda.time.Duration;
import org.joda.time.Instant;

import net.oauth.jsontoken.crypto.AsciiStringSigner;
import net.oauth.jsontoken.crypto.SignatureAlgorithm;
import net.oauth.jsontoken.crypto.Signer;

import com.google.common.base.Preconditions;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;


/**
 * A JSON Token.
 */
public class JsonToken {
  // header names
  public final static String ALGORITHM_HEADER = "alg";
  public final static String KEY_ID_HEADER = "kid";
  public final static String TYPE_HEADER = "typ";
	
  // standard claim names (payload parameters)
  public final static String ISSUER = "iss";
  public final static String ISSUED_AT = "iat";
  public final static String EXPIRATION = "exp";
  public final static String AUDIENCE = "aud";
  
  // default encoding for all Json token
  public final static String BASE64URL_ENCODING = "base64url";
  
  public final static int DEFAULT_LIFETIME_IN_MINS = 2;

  protected final Clock clock;
  private final JsonObject payload;
  
  // The following fields are only valid when signing the token.
  private final Signer signer;
  private final SignatureAlgorithm sigAlg;
  private String signature;
  private String baseString;
  
  /**
   * Public constructor, use empty data type.
   * @param signer the signer that will sign the token.
   */
  public JsonToken(Signer signer) {
    this(signer, new SystemClock());
  }

  /**
   * Public constructor.
   * @param signer the signer that will sign the token
   * @param clock a clock whose notion of current time will determine the not-before timestamp
   *   of the token, if not explicitly set.
   */
  public JsonToken(Signer signer, Clock clock) {
    Preconditions.checkNotNull(signer);
    Preconditions.checkNotNull(clock);
    
    this.payload = new JsonObject();
    this.signer = signer;
    this.clock = clock;
    this.sigAlg = signer.getSignatureAlgorithm();
    this.signature = null;
    this.baseString = null;
    String issuer = signer.getIssuer();
    if (issuer != null) {
      setParam(JsonToken.ISSUER, issuer);
    }
  }

  /**
   * Public constructor used when parsing a JsonToken {@link JsonToken}
   * (as opposed to create a token). This constructor takes Json payload
   * as parameter, set all other signing related parameters to null.
   *
   * @param payload A payload JSON object.
   */
  public JsonToken(JsonObject payload) {
    this.payload = payload;
    // when parsing a token, payload is the only field we cares about.
    this.baseString = null;
    this.signature = null;
    this.sigAlg = null;
    this.signer = null;
    this.clock = null;
  }

  /**
   * Public constructor used when parsing a JsonToken {@link JsonToken}
   * (as opposed to create a token). This constructor takes Json payload
   * and clock as parameters, set all other signing related parameters to null.
   *
   * @param payload A payload JSON object.
   * @param clock a clock whose notion of current time will determine the not-before timestamp
   *   of the token, if not explicitly set.
   */
  public JsonToken(JsonObject payload, Clock clock) {
    this.payload = payload;
    this.clock = clock;
    // when parsing a token, payload is the only field we cares about.
    this.baseString = null;
    this.signature = null;
    this.sigAlg = null;
    this.signer = null;
  }

  /**
   * Returns the serialized representation of this token, i.e.,
   * keyId.sig.base64(payload).base64(data_type).base64(encoding).base64(alg)
   *
   * This is what a client (token issuer) would send to a token verifier over the
   * wire.
   * @throws SignatureException if the token can't be signed.
   */
  public String serializeAndSign() throws SignatureException {
    String baseString = computeSignatureBaseString();
    String sig = getSignature();
    return JsonTokenUtil.toDotFormat(baseString, sig);
  }

  /**
   * Returns a human-readable version of the token.
   */
  @Override
  public String toString() {
    return JsonTokenUtil.toJson(payload);
  }

  public String getIssuer() {
    return getParamAsString(ISSUER);
  }

  public Instant getIssuedAt() {
    Long issuedAt = getParamAsLong(ISSUED_AT);
    if (issuedAt == null) {
      return null;
    }
    // JWT represents time in seconds, Instants expect milliseconds
    return new Instant(issuedAt * 1000);
  }

  public void setIssuedAt(Instant instant) {
    setParam(JsonToken.ISSUED_AT, instant.getMillis() / 1000);
  }

  public Instant getExpiration() {
    Long expiration = getParamAsLong(EXPIRATION);
    if (expiration == null) {
      return null;
    }
    // JWT represents time in seconds, Instants expect milliseconds
    return new Instant(expiration * 1000);
  }

  public void setExpiration(Instant instant) {
    setParam(JsonToken.EXPIRATION, instant.getMillis() / 1000);
  }

  public String getAudience() {
    return getParamAsString(AUDIENCE);
  }

  public void setAudience(String audience) {
    setParam(AUDIENCE, audience);
  }

  public void setParam(String name, String value) {
    payload.addProperty(name, value);
  }

  public void setParam(String name, Number value) {
    payload.addProperty(name, value);
  }

  public JsonPrimitive getParamAsPrimitive(String param) {
    return payload.getAsJsonPrimitive(param);
  }
  
  public JsonObject getPayloadAsJsonObject() {
    return payload;
  }
  
  public String getKeyId() {
    return signer.getKeyId();
  }

  public SignatureAlgorithm getSignatureAlgorithm() {
    return sigAlg;
  }
  
  private String getParamAsString(String param) {
    JsonPrimitive value = getParamAsPrimitive(param);
    if (value == null) {
      return null;
    } else {
      return value.getAsString();
    }
  }
  private Long getParamAsLong(String param) {
    JsonPrimitive value = getParamAsPrimitive(param);
    if (value == null) {
      return null;
    } else {
      return value.getAsLong();
    }
  }
  
  protected String computeSignatureBaseString() {
    if (baseString != null && !baseString.isEmpty()) {
      return baseString;
    }
    baseString = JsonTokenUtil.toDotFormat(
        JsonTokenUtil.toBase64(getHeader()),
        JsonTokenUtil.toBase64(payload)
        );
    return baseString;
  }

  public JsonObject getHeader() {
    JsonObject header = new JsonObject();
    header.addProperty(ALGORITHM_HEADER, getSignatureAlgorithm().getNameForJson());
    String keyId = getKeyId();
    if (keyId != null) {
      header.addProperty(KEY_ID_HEADER, keyId);
    }
    return header;
  }

  private String getSignature() throws SignatureException {
    if (signature != null && !signature.isEmpty()) {
      return signature;
    }
    
    if (signer == null) {
      throw new SignatureException("can't sign JsonToken with signer.");
    }
    String signature;
    // now, generate the signature
    AsciiStringSigner asciiSigner = new AsciiStringSigner(signer);
    signature = Base64.encodeBase64URLSafeString(asciiSigner.sign(baseString));
    
    return signature;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy