• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018, Google Inc. All rights reserved.
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 Inc. 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.http.HttpStatusCodes;
35 import com.google.api.client.http.LowLevelHttpRequest;
36 import com.google.api.client.http.LowLevelHttpResponse;
37 import com.google.api.client.json.GenericJson;
38 import com.google.api.client.json.Json;
39 import com.google.api.client.testing.http.MockHttpTransport;
40 import com.google.api.client.testing.http.MockLowLevelHttpRequest;
41 import com.google.api.client.testing.http.MockLowLevelHttpResponse;
42 import com.google.auth.TestUtils;
43 import com.google.common.io.BaseEncoding;
44 import java.io.IOException;
45 
46 /** Transport that simulates the IAMCredentials server for access tokens. */
47 public class MockIAMCredentialsServiceTransport extends MockHttpTransport {
48 
49   private static final String DEFAULT_IAM_ACCESS_TOKEN_ENDPOINT =
50       "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:generateAccessToken";
51   private static final String IAM_ID_TOKEN_ENDPOINT =
52       "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:generateIdToken";
53   private static final String IAM_SIGN_ENDPOINT =
54       "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/%s:signBlob";
55   private Integer tokenResponseErrorCode;
56   private String tokenResponseErrorContent;
57   private String targetPrincipal;
58   private byte[] signedBlob;
59   private int responseCode = HttpStatusCodes.STATUS_CODE_OK;
60   private String errorMessage;
61   private String iamAccessTokenEndpoint;
62 
63   private String accessToken;
64   private String expireTime;
65 
66   private String idToken;
67 
68   private MockLowLevelHttpRequest request;
69 
MockIAMCredentialsServiceTransport()70   public MockIAMCredentialsServiceTransport() {}
71 
setTokenResponseErrorCode(Integer tokenResponseErrorCode)72   public void setTokenResponseErrorCode(Integer tokenResponseErrorCode) {
73     this.tokenResponseErrorCode = tokenResponseErrorCode;
74   }
75 
setTokenResponseErrorContent(String tokenResponseErrorContent)76   public void setTokenResponseErrorContent(String tokenResponseErrorContent) {
77     this.tokenResponseErrorContent = tokenResponseErrorContent;
78   }
79 
setTargetPrincipal(String targetPrincipal)80   public void setTargetPrincipal(String targetPrincipal) {
81     this.targetPrincipal = targetPrincipal;
82   }
83 
setAccessToken(String accessToken)84   public void setAccessToken(String accessToken) {
85     this.accessToken = accessToken;
86   }
87 
setExpireTime(String expireTime)88   public void setExpireTime(String expireTime) {
89     this.expireTime = expireTime;
90   }
91 
setSignedBlob(byte[] signedBlob)92   public void setSignedBlob(byte[] signedBlob) {
93     this.signedBlob = signedBlob;
94   }
95 
setErrorResponseCodeAndMessage(int responseCode, String errorMessage)96   public void setErrorResponseCodeAndMessage(int responseCode, String errorMessage) {
97     this.responseCode = responseCode;
98     this.errorMessage = errorMessage;
99   }
100 
setIdToken(String idToken)101   public void setIdToken(String idToken) {
102     this.idToken = idToken;
103   }
104 
setAccessTokenEndpoint(String accessTokenEndpoint)105   public void setAccessTokenEndpoint(String accessTokenEndpoint) {
106     this.iamAccessTokenEndpoint = accessTokenEndpoint;
107   }
108 
getRequest()109   public MockLowLevelHttpRequest getRequest() {
110     return request;
111   }
112 
113   @Override
buildRequest(String method, String url)114   public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
115 
116     String iamAccesssTokenformattedUrl =
117         iamAccessTokenEndpoint != null
118             ? iamAccessTokenEndpoint
119             : String.format(DEFAULT_IAM_ACCESS_TOKEN_ENDPOINT, this.targetPrincipal);
120     String iamSignBlobformattedUrl = String.format(IAM_SIGN_ENDPOINT, this.targetPrincipal);
121     String iamIdTokenformattedUrl = String.format(IAM_ID_TOKEN_ENDPOINT, this.targetPrincipal);
122     if (url.equals(iamAccesssTokenformattedUrl)) {
123       this.request =
124           new MockLowLevelHttpRequest(url) {
125             @Override
126             public LowLevelHttpResponse execute() throws IOException {
127 
128               if (tokenResponseErrorCode != null) {
129                 return new MockLowLevelHttpResponse()
130                     .setStatusCode(tokenResponseErrorCode)
131                     .setContentType(Json.MEDIA_TYPE)
132                     .setContent(tokenResponseErrorContent);
133               }
134 
135               // Create the JSON response
136               GenericJson refreshContents = new GenericJson();
137               refreshContents.setFactory(OAuth2Utils.JSON_FACTORY);
138               refreshContents.put("accessToken", accessToken);
139               refreshContents.put("expireTime", expireTime);
140               String refreshText = refreshContents.toPrettyString();
141               return new MockLowLevelHttpResponse()
142                   .setContentType(Json.MEDIA_TYPE)
143                   .setContent(refreshText);
144             }
145           };
146     } else if (url.equals(iamSignBlobformattedUrl)
147         && responseCode != HttpStatusCodes.STATUS_CODE_OK) {
148       this.request =
149           new MockLowLevelHttpRequest(url) {
150             @Override
151             public LowLevelHttpResponse execute() throws IOException {
152 
153               if (tokenResponseErrorCode != null) {
154                 return new MockLowLevelHttpResponse()
155                     .setStatusCode(tokenResponseErrorCode)
156                     .setContentType(Json.MEDIA_TYPE)
157                     .setContent(tokenResponseErrorContent);
158               }
159 
160               BaseEncoding base64 = BaseEncoding.base64();
161               GenericJson refreshContents = new GenericJson();
162               refreshContents.setFactory(OAuth2Utils.JSON_FACTORY);
163               refreshContents.put("signedBlob", base64.encode(signedBlob));
164               return new MockLowLevelHttpResponse()
165                   .setStatusCode(responseCode)
166                   .setContent(TestUtils.errorJson(errorMessage));
167             }
168           };
169     } else if (url.equals(iamSignBlobformattedUrl)) {
170       this.request =
171           new MockLowLevelHttpRequest(url) {
172             @Override
173             public LowLevelHttpResponse execute() throws IOException {
174 
175               if (tokenResponseErrorCode != null) {
176                 return new MockLowLevelHttpResponse()
177                     .setStatusCode(tokenResponseErrorCode)
178                     .setContentType(Json.MEDIA_TYPE)
179                     .setContent(tokenResponseErrorContent);
180               }
181 
182               BaseEncoding base64 = BaseEncoding.base64();
183               GenericJson refreshContents = new GenericJson();
184               refreshContents.setFactory(OAuth2Utils.JSON_FACTORY);
185               refreshContents.put("signedBlob", base64.encode(signedBlob));
186               String refreshText = refreshContents.toPrettyString();
187               return new MockLowLevelHttpResponse()
188                   .setContentType(Json.MEDIA_TYPE)
189                   .setContent(refreshText);
190             }
191           };
192     } else if (url.equals(iamIdTokenformattedUrl)) {
193       this.request =
194           new MockLowLevelHttpRequest(url) {
195             @Override
196             public LowLevelHttpResponse execute() throws IOException {
197 
198               if (responseCode != HttpStatusCodes.STATUS_CODE_OK) {
199                 return new MockLowLevelHttpResponse()
200                     .setStatusCode(responseCode)
201                     .setContentType(Json.MEDIA_TYPE)
202                     .setContent(errorMessage);
203               }
204 
205               GenericJson refreshContents = new GenericJson();
206               refreshContents.setFactory(OAuth2Utils.JSON_FACTORY);
207               refreshContents.put("token", idToken);
208               String tokenContent = refreshContents.toPrettyString();
209               return new MockLowLevelHttpResponse()
210                   .setContentType(Json.MEDIA_TYPE)
211                   .setContent(tokenContent);
212             }
213           };
214     } else {
215       return super.buildRequest(method, url);
216     }
217 
218     return this.request;
219   }
220 }
221