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.api.client.util.Preconditions; 35 import com.google.common.base.MoreObjects; 36 import com.google.errorprone.annotations.CanIgnoreReturnValue; 37 import java.io.IOException; 38 import java.util.List; 39 import java.util.Objects; 40 41 /** 42 * IdTokenCredentials provides a Google Issued OpenIdConnect token. <br> 43 * Use an ID token to access services that require presenting an ID token for authentication such as 44 * Cloud Functions or Cloud Run.<br> 45 * The following Credential subclasses support IDTokens: ServiceAccountCredentials, 46 * ComputeEngineCredentials, ImpersonatedCredentials. 47 * 48 * <p>For more information see <br> 49 * Usage:<br> 50 * 51 * <pre> 52 * String credPath = "/path/to/svc_account.json"; 53 * String targetAudience = "https://example.com"; 54 * 55 * // For Application Default Credentials (as ServiceAccountCredentials) 56 * // export GOOGLE_APPLICATION_CREDENTIALS=/path/to/svc.json 57 * GoogleCredentials adcCreds = GoogleCredentials.getApplicationDefault(); 58 * if (!adcCreds instanceof IdTokenProvider) { 59 * // handle error message 60 * } 61 * 62 * IdTokenCredentials tokenCredential = IdTokenCredentials.newBuilder() 63 * .setIdTokenProvider(adcCreds) 64 * .setTargetAudience(targetAudience).build(); 65 * 66 * // for ServiceAccountCredentials 67 * ServiceAccountCredentials saCreds = ServiceAccountCredentials.fromStream(new FileInputStream(credPath)); 68 * saCreds = (ServiceAccountCredentials) saCreds.createScoped(Arrays.asList("https://www.googleapis.com/auth/iam")); 69 * IdTokenCredentials tokenCredential = IdTokenCredentials.newBuilder() 70 * .setIdTokenProvider(saCreds) 71 * .setTargetAudience(targetAudience).build(); 72 * 73 * // for ComputeEngineCredentials 74 * ComputeEngineCredentials caCreds = ComputeEngineCredentials.create(); 75 * IdTokenCredentials tokenCredential = IdTokenCredentials.newBuilder() 76 * .setIdTokenProvider(caCreds) 77 * .setTargetAudience(targetAudience) 78 * .setOptions(Arrays.asList(ComputeEngineCredentials.ID_TOKEN_FORMAT_FULL)) 79 * .build(); 80 * 81 * // for ImpersonatedCredentials 82 * ImpersonatedCredentials imCreds = ImpersonatedCredentials.create(saCreds, 83 * "impersonated-account@project.iam.gserviceaccount.com", null, 84 * Arrays.asList("https://www.googleapis.com/auth/cloud-platform"), 300); 85 * IdTokenCredentials tokenCredential = IdTokenCredentials.newBuilder() 86 * .setIdTokenProvider(imCreds) 87 * .setTargetAudience(targetAudience) 88 * .setOptions(Arrays.asList(ImpersonatedCredentials.INCLUDE_EMAIL)) 89 * .build(); 90 * 91 * // Use the IdTokenCredential in an authorized transport 92 * GenericUrl genericUrl = new GenericUrl("https://example.com"); 93 * HttpCredentialsAdapter adapter = new HttpCredentialsAdapter(tokenCredential); 94 * HttpTransport transport = new NetHttpTransport(); 95 * HttpRequest request = transport.createRequestFactory(adapter).buildGetRequest(genericUrl); 96 * HttpResponse response = request.execute(); 97 * 98 * // Print the token, expiration and the audience 99 * System.out.println(tokenCredential.getIdToken().getTokenValue()); 100 * System.out.println(tokenCredential.getIdToken().getJsonWebSignature().getPayload().getAudienceAsList()); 101 * System.out.println(tokenCredential.getIdToken().getJsonWebSignature().getPayload().getExpirationTimeSeconds()); 102 * </pre> 103 */ 104 public class IdTokenCredentials extends OAuth2Credentials { 105 106 private static final long serialVersionUID = -2133257318957588431L; 107 108 private IdTokenProvider idTokenProvider; 109 private String targetAudience; 110 private List<IdTokenProvider.Option> options; 111 IdTokenCredentials(Builder builder)112 private IdTokenCredentials(Builder builder) { 113 this.idTokenProvider = Preconditions.checkNotNull(builder.getIdTokenProvider()); 114 115 // target audience can't be used for UserCredentials 116 if (!(this.idTokenProvider instanceof UserCredentials)) { 117 this.targetAudience = Preconditions.checkNotNull(builder.getTargetAudience()); 118 } 119 120 this.options = builder.getOptions(); 121 } 122 123 @Override refreshAccessToken()124 public AccessToken refreshAccessToken() throws IOException { 125 return this.idTokenProvider.idTokenWithAudience(targetAudience, options); 126 } 127 getIdToken()128 public IdToken getIdToken() { 129 return (IdToken) getAccessToken(); 130 } 131 132 @Override hashCode()133 public int hashCode() { 134 return Objects.hash(options, targetAudience); 135 } 136 137 @Override toString()138 public String toString() { 139 return MoreObjects.toStringHelper(this).toString(); 140 } 141 142 @Override equals(Object obj)143 public boolean equals(Object obj) { 144 if (!(obj instanceof IdTokenCredentials)) { 145 return false; 146 } 147 IdTokenCredentials other = (IdTokenCredentials) obj; 148 return Objects.equals(this.idTokenProvider, other.idTokenProvider) 149 && Objects.equals(this.targetAudience, other.targetAudience); 150 } 151 152 @Override toBuilder()153 public Builder toBuilder() { 154 return new Builder() 155 .setIdTokenProvider(this.idTokenProvider) 156 .setTargetAudience(this.targetAudience) 157 .setOptions(this.options); 158 } 159 newBuilder()160 public static Builder newBuilder() { 161 return new Builder(); 162 } 163 164 public static class Builder extends OAuth2Credentials.Builder { 165 166 private IdTokenProvider idTokenProvider; 167 private String targetAudience; 168 private List<IdTokenProvider.Option> options; 169 Builder()170 protected Builder() {} 171 172 @CanIgnoreReturnValue setIdTokenProvider(IdTokenProvider idTokenProvider)173 public Builder setIdTokenProvider(IdTokenProvider idTokenProvider) { 174 this.idTokenProvider = idTokenProvider; 175 return this; 176 } 177 getIdTokenProvider()178 public IdTokenProvider getIdTokenProvider() { 179 return this.idTokenProvider; 180 } 181 182 @CanIgnoreReturnValue setTargetAudience(String targetAudience)183 public Builder setTargetAudience(String targetAudience) { 184 this.targetAudience = targetAudience; 185 return this; 186 } 187 getTargetAudience()188 public String getTargetAudience() { 189 return this.targetAudience; 190 } 191 192 @CanIgnoreReturnValue setOptions(List<IdTokenProvider.Option> options)193 public Builder setOptions(List<IdTokenProvider.Option> options) { 194 this.options = options; 195 return this; 196 } 197 getOptions()198 public List<IdTokenProvider.Option> getOptions() { 199 return this.options; 200 } 201 202 @Override build()203 public IdTokenCredentials build() { 204 return new IdTokenCredentials(this); 205 } 206 } 207 } 208