1 /* 2 * Copyright 2019, Google LLC 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * * Neither the name of Google LLC nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package com.google.auth.oauth2; 33 34 import com.google.auto.value.AutoValue; 35 import com.google.common.collect.ImmutableMap; 36 import java.io.Serializable; 37 import java.util.Map; 38 import javax.annotation.Nullable; 39 40 /** 41 * Value class representing the set of fields used as the payload of a JWT token. 42 * 43 * <p>To create and customize claims, use the builder: 44 * 45 * <pre><code> 46 * Claims claims = Claims.newBuilder() 47 * .setAudience("https://example.com/some-audience") 48 * .setIssuer("some-issuer@example.com") 49 * .setSubject("some-subject@example.com") 50 * .build(); 51 * </code></pre> 52 */ 53 @AutoValue 54 public abstract class JwtClaims implements Serializable { 55 private static final long serialVersionUID = 4974444151019426702L; 56 57 @Nullable getAudience()58 abstract String getAudience(); 59 60 @Nullable getIssuer()61 abstract String getIssuer(); 62 63 @Nullable getSubject()64 abstract String getSubject(); 65 66 /** 67 * Returns additional claims for this object. The returned map is not guaranteed to be mutable. 68 * 69 * @return additional claims 70 */ getAdditionalClaims()71 abstract Map<String, String> getAdditionalClaims(); 72 newBuilder()73 public static Builder newBuilder() { 74 return new AutoValue_JwtClaims.Builder().setAdditionalClaims(ImmutableMap.<String, String>of()); 75 } 76 77 /** 78 * Returns a new Claims instance with overridden fields. 79 * 80 * <p>Any non-null field will overwrite the value from the original claims instance. 81 * 82 * @param other claims to override 83 * @return new claims 84 */ merge(JwtClaims other)85 public JwtClaims merge(JwtClaims other) { 86 ImmutableMap.Builder<String, String> newClaimsBuilder = ImmutableMap.builder(); 87 newClaimsBuilder.putAll(getAdditionalClaims()); 88 newClaimsBuilder.putAll(other.getAdditionalClaims()); 89 90 return newBuilder() 91 .setAudience(other.getAudience() == null ? getAudience() : other.getAudience()) 92 .setIssuer(other.getIssuer() == null ? getIssuer() : other.getIssuer()) 93 .setSubject(other.getSubject() == null ? getSubject() : other.getSubject()) 94 .setAdditionalClaims(newClaimsBuilder.build()) 95 .build(); 96 } 97 98 /** 99 * Returns whether or not this set of claims is complete. 100 * 101 * <p>Audience, issuer, and subject are required to be set in order to use the claim set for a JWT 102 * token. An incomplete Claims instance is useful for overriding claims when using {@link 103 * ServiceAccountJwtAccessCredentials#jwtWithClaims(JwtClaims)} or {@link 104 * JwtCredentials#jwtWithClaims(JwtClaims)}. 105 * 106 * @return true if all required fields have been set; false otherwise 107 */ isComplete()108 public boolean isComplete() { 109 boolean hasScopes = 110 getAdditionalClaims().containsKey("scope") && !getAdditionalClaims().get("scope").isEmpty(); 111 return (getAudience() != null || hasScopes) && getIssuer() != null && getSubject() != null; 112 } 113 114 @AutoValue.Builder 115 public abstract static class Builder { setAudience(String audience)116 public abstract Builder setAudience(String audience); 117 setIssuer(String issuer)118 public abstract Builder setIssuer(String issuer); 119 setSubject(String subject)120 public abstract Builder setSubject(String subject); 121 setAdditionalClaims(Map<String, String> additionalClaims)122 public abstract Builder setAdditionalClaims(Map<String, String> additionalClaims); 123 build()124 public abstract JwtClaims build(); 125 } 126 } 127