• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015, 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.json.JsonParser;
35 import com.google.common.base.Charsets;
36 import com.google.common.base.MoreObjects;
37 import com.google.errorprone.annotations.CanIgnoreReturnValue;
38 import java.io.BufferedReader;
39 import java.io.IOException;
40 import java.io.InputStreamReader;
41 import java.io.OutputStream;
42 import java.net.Socket;
43 import java.util.ArrayList;
44 import java.util.List;
45 import java.util.Objects;
46 
47 /** OAuth2 credentials representing the built-in service account for Google Cloud Shell. */
48 public class CloudShellCredentials extends GoogleCredentials {
49 
50   private static final long serialVersionUID = -2133257318957488451L;
51   private static final int ACCESS_TOKEN_INDEX = 2;
52   private static final int READ_TIMEOUT_MS = 5000;
53 
54   /**
55    * The Cloud Shell back authorization channel uses serialized Javascript Protobuffers, preceded by
56    * the message length and a new line character. However, the request message has no content, so a
57    * token request consists of an empty JsPb, and its 2 character length prefix.
58    */
59   protected static final String GET_AUTH_TOKEN_REQUEST = "2\n[]";
60 
61   protected static final byte[] GET_AUTH_TOKEN_REQUEST_BYTES =
62       (GET_AUTH_TOKEN_REQUEST + "\n").getBytes(Charsets.UTF_8);
63 
64   private final int authPort;
65 
create(int authPort)66   public static CloudShellCredentials create(int authPort) {
67     return CloudShellCredentials.newBuilder().setAuthPort(authPort).build();
68   }
69 
CloudShellCredentials(Builder builder)70   private CloudShellCredentials(Builder builder) {
71     super(builder);
72     this.authPort = builder.getAuthPort();
73   }
74 
getAuthPort()75   protected int getAuthPort() {
76     return this.authPort;
77   }
78 
79   @Override
refreshAccessToken()80   public AccessToken refreshAccessToken() throws IOException {
81     Socket socket = new Socket("localhost", this.getAuthPort());
82     socket.setSoTimeout(READ_TIMEOUT_MS);
83     AccessToken token;
84     try {
85       OutputStream os = socket.getOutputStream();
86       os.write(GET_AUTH_TOKEN_REQUEST_BYTES);
87 
88       BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
89       input.readLine(); // Skip over the first line
90       JsonParser parser = OAuth2Utils.JSON_FACTORY.createJsonParser(input);
91       List<Object> messageArray = (List<Object>) parser.parseArray(ArrayList.class, Object.class);
92       String accessToken = messageArray.get(ACCESS_TOKEN_INDEX).toString();
93       token = new AccessToken(accessToken, null);
94     } finally {
95       socket.close();
96     }
97     return token;
98   }
99 
100   @Override
hashCode()101   public int hashCode() {
102     return Objects.hash(authPort);
103   }
104 
105   @Override
toString()106   public String toString() {
107     return MoreObjects.toStringHelper(this).add("authPort", authPort).toString();
108   }
109 
110   @Override
equals(Object obj)111   public boolean equals(Object obj) {
112     if (!(obj instanceof CloudShellCredentials)) {
113       return false;
114     }
115     CloudShellCredentials other = (CloudShellCredentials) obj;
116     return this.authPort == other.authPort;
117   }
118 
119   @Override
toBuilder()120   public Builder toBuilder() {
121     return new Builder(this);
122   }
123 
newBuilder()124   public static Builder newBuilder() {
125     return new Builder();
126   }
127 
128   public static class Builder extends GoogleCredentials.Builder {
129     private int authPort;
130 
Builder()131     protected Builder() {}
132 
Builder(CloudShellCredentials credentials)133     protected Builder(CloudShellCredentials credentials) {
134       this.authPort = credentials.authPort;
135     }
136 
137     @CanIgnoreReturnValue
setAuthPort(int authPort)138     public Builder setAuthPort(int authPort) {
139       this.authPort = authPort;
140       return this;
141     }
142 
143     @CanIgnoreReturnValue
setQuotaProjectId(String quotaProjectId)144     public Builder setQuotaProjectId(String quotaProjectId) {
145       super.quotaProjectId = quotaProjectId;
146       return this;
147     }
148 
getAuthPort()149     public int getAuthPort() {
150       return authPort;
151     }
152 
153     @Override
build()154     public CloudShellCredentials build() {
155       return new CloudShellCredentials(this);
156     }
157   }
158 }
159