• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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.auth.http.HttpTransportFactory;
35 import com.google.common.annotations.VisibleForTesting;
36 import com.google.errorprone.annotations.CanIgnoreReturnValue;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.Map;
41 
42 /**
43  * Url-sourced, file-sourced, or user provided supplier method-sourced external account credentials.
44  *
45  * <p>By default, attempts to exchange the external credential for a GCP access token.
46  */
47 public class IdentityPoolCredentials extends ExternalAccountCredentials {
48 
49   static final String FILE_METRICS_HEADER_VALUE = "file";
50   static final String URL_METRICS_HEADER_VALUE = "url";
51   private static final long serialVersionUID = 2471046175477275881L;
52   private final IdentityPoolSubjectTokenSupplier subjectTokenSupplier;
53   private final ExternalAccountSupplierContext supplierContext;
54   private final String metricsHeaderValue;
55 
56   /** Internal constructor. See {@link Builder}. */
IdentityPoolCredentials(Builder builder)57   IdentityPoolCredentials(Builder builder) {
58     super(builder);
59     IdentityPoolCredentialSource credentialSource =
60         (IdentityPoolCredentialSource) builder.credentialSource;
61     this.supplierContext =
62         ExternalAccountSupplierContext.newBuilder()
63             .setAudience(this.getAudience())
64             .setSubjectTokenType(this.getSubjectTokenType())
65             .build();
66     // Check that one and only one of supplier or credential source are provided.
67     if (builder.subjectTokenSupplier != null && credentialSource != null) {
68       throw new IllegalArgumentException(
69           "IdentityPoolCredentials cannot have both a subjectTokenSupplier and a credentialSource.");
70     }
71     if (builder.subjectTokenSupplier == null && credentialSource == null) {
72       throw new IllegalArgumentException(
73           "A subjectTokenSupplier or a credentialSource must be provided.");
74     }
75     if (builder.subjectTokenSupplier != null) {
76       this.subjectTokenSupplier = builder.subjectTokenSupplier;
77       this.metricsHeaderValue = PROGRAMMATIC_METRICS_HEADER_VALUE;
78     } else if (credentialSource.credentialSourceType
79         == IdentityPoolCredentialSource.IdentityPoolCredentialSourceType.FILE) {
80       this.subjectTokenSupplier = new FileIdentityPoolSubjectTokenSupplier(credentialSource);
81       this.metricsHeaderValue = FILE_METRICS_HEADER_VALUE;
82     } else {
83       this.subjectTokenSupplier =
84           new UrlIdentityPoolSubjectTokenSupplier(credentialSource, this.transportFactory);
85       this.metricsHeaderValue = URL_METRICS_HEADER_VALUE;
86     }
87   }
88 
89   @Override
refreshAccessToken()90   public AccessToken refreshAccessToken() throws IOException {
91     String credential = retrieveSubjectToken();
92     StsTokenExchangeRequest.Builder stsTokenExchangeRequest =
93         StsTokenExchangeRequest.newBuilder(credential, getSubjectTokenType())
94             .setAudience(getAudience());
95 
96     Collection<String> scopes = getScopes();
97     if (scopes != null && !scopes.isEmpty()) {
98       stsTokenExchangeRequest.setScopes(new ArrayList<>(scopes));
99     }
100 
101     return exchangeExternalCredentialForAccessToken(stsTokenExchangeRequest.build());
102   }
103 
104   @Override
retrieveSubjectToken()105   public String retrieveSubjectToken() throws IOException {
106     return this.subjectTokenSupplier.getSubjectToken(supplierContext);
107   }
108 
109   @Override
getCredentialSourceType()110   String getCredentialSourceType() {
111     return this.metricsHeaderValue;
112   }
113 
114   @VisibleForTesting
getIdentityPoolSubjectTokenSupplier()115   IdentityPoolSubjectTokenSupplier getIdentityPoolSubjectTokenSupplier() {
116     return this.subjectTokenSupplier;
117   }
118 
119   /** Clones the IdentityPoolCredentials with the specified scopes. */
120   @Override
createScoped(Collection<String> newScopes)121   public IdentityPoolCredentials createScoped(Collection<String> newScopes) {
122     return new IdentityPoolCredentials(
123         (IdentityPoolCredentials.Builder) newBuilder(this).setScopes(newScopes));
124   }
125 
newBuilder()126   public static Builder newBuilder() {
127     return new Builder();
128   }
129 
newBuilder(IdentityPoolCredentials identityPoolCredentials)130   public static Builder newBuilder(IdentityPoolCredentials identityPoolCredentials) {
131     return new Builder(identityPoolCredentials);
132   }
133 
134   public static class Builder extends ExternalAccountCredentials.Builder {
135 
136     private IdentityPoolSubjectTokenSupplier subjectTokenSupplier;
137 
Builder()138     Builder() {}
139 
Builder(IdentityPoolCredentials credentials)140     Builder(IdentityPoolCredentials credentials) {
141       super(credentials);
142       if (this.credentialSource == null) {
143         this.subjectTokenSupplier = credentials.subjectTokenSupplier;
144       }
145     }
146 
147     /**
148      * Sets the subject token supplier. The supplier should return a valid subject token string.
149      *
150      * @param subjectTokenSupplier the supplier to use.
151      * @return this {@code Builder} object
152      */
153     @CanIgnoreReturnValue
setSubjectTokenSupplier(IdentityPoolSubjectTokenSupplier subjectTokenSupplier)154     public Builder setSubjectTokenSupplier(IdentityPoolSubjectTokenSupplier subjectTokenSupplier) {
155       this.subjectTokenSupplier = subjectTokenSupplier;
156       return this;
157     }
158 
159     @CanIgnoreReturnValue
setHttpTransportFactory(HttpTransportFactory transportFactory)160     public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) {
161       super.setHttpTransportFactory(transportFactory);
162       return this;
163     }
164 
165     @CanIgnoreReturnValue
setAudience(String audience)166     public Builder setAudience(String audience) {
167       super.setAudience(audience);
168       return this;
169     }
170 
171     @CanIgnoreReturnValue
setSubjectTokenType(String subjectTokenType)172     public Builder setSubjectTokenType(String subjectTokenType) {
173       super.setSubjectTokenType(subjectTokenType);
174       return this;
175     }
176 
177     @CanIgnoreReturnValue
setSubjectTokenType(SubjectTokenTypes subjectTokenType)178     public Builder setSubjectTokenType(SubjectTokenTypes subjectTokenType) {
179       super.setSubjectTokenType(subjectTokenType);
180       return this;
181     }
182 
183     @CanIgnoreReturnValue
setTokenUrl(String tokenUrl)184     public Builder setTokenUrl(String tokenUrl) {
185       super.setTokenUrl(tokenUrl);
186       return this;
187     }
188 
189     @CanIgnoreReturnValue
setCredentialSource(IdentityPoolCredentialSource credentialSource)190     public Builder setCredentialSource(IdentityPoolCredentialSource credentialSource) {
191       super.setCredentialSource(credentialSource);
192       return this;
193     }
194 
195     @CanIgnoreReturnValue
setServiceAccountImpersonationUrl(String serviceAccountImpersonationUrl)196     public Builder setServiceAccountImpersonationUrl(String serviceAccountImpersonationUrl) {
197       super.setServiceAccountImpersonationUrl(serviceAccountImpersonationUrl);
198       return this;
199     }
200 
201     @CanIgnoreReturnValue
setTokenInfoUrl(String tokenInfoUrl)202     public Builder setTokenInfoUrl(String tokenInfoUrl) {
203       super.setTokenInfoUrl(tokenInfoUrl);
204       return this;
205     }
206 
207     @CanIgnoreReturnValue
setQuotaProjectId(String quotaProjectId)208     public Builder setQuotaProjectId(String quotaProjectId) {
209       super.setQuotaProjectId(quotaProjectId);
210       return this;
211     }
212 
213     @CanIgnoreReturnValue
setClientId(String clientId)214     public Builder setClientId(String clientId) {
215       super.setClientId(clientId);
216       return this;
217     }
218 
219     @CanIgnoreReturnValue
setClientSecret(String clientSecret)220     public Builder setClientSecret(String clientSecret) {
221       super.setClientSecret(clientSecret);
222       return this;
223     }
224 
225     @CanIgnoreReturnValue
setScopes(Collection<String> scopes)226     public Builder setScopes(Collection<String> scopes) {
227       super.setScopes(scopes);
228       return this;
229     }
230 
231     @Override
232     @CanIgnoreReturnValue
setWorkforcePoolUserProject(String workforcePoolUserProject)233     public Builder setWorkforcePoolUserProject(String workforcePoolUserProject) {
234       super.setWorkforcePoolUserProject(workforcePoolUserProject);
235       return this;
236     }
237 
238     @CanIgnoreReturnValue
setServiceAccountImpersonationOptions(Map<String, Object> optionsMap)239     public Builder setServiceAccountImpersonationOptions(Map<String, Object> optionsMap) {
240       super.setServiceAccountImpersonationOptions(optionsMap);
241       return this;
242     }
243 
244     @CanIgnoreReturnValue
setUniverseDomain(String universeDomain)245     public Builder setUniverseDomain(String universeDomain) {
246       super.setUniverseDomain(universeDomain);
247       return this;
248     }
249 
250     @CanIgnoreReturnValue
setEnvironmentProvider(EnvironmentProvider environmentProvider)251     Builder setEnvironmentProvider(EnvironmentProvider environmentProvider) {
252       super.setEnvironmentProvider(environmentProvider);
253       return this;
254     }
255 
256     @Override
build()257     public IdentityPoolCredentials build() {
258       return new IdentityPoolCredentials(this);
259     }
260   }
261 }
262