• 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.GenericJson;
35 import com.google.api.client.json.JsonObjectParser;
36 import com.google.api.client.util.Preconditions;
37 import com.google.errorprone.annotations.CanIgnoreReturnValue;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.nio.charset.StandardCharsets;
41 import java.util.Map;
42 
43 /**
44  * An OAuth2 user authorization Client ID and associated information.
45  *
46  * <p>Corresponds to the information in the json file downloadable for a Client ID.
47  */
48 public class ClientId {
49 
50   private static final String FIELD_TYPE_INSTALLED = "installed";
51   private static final String FIELD_TYPE_WEB = "web";
52   private static final String FIELD_CLIENT_ID = "client_id";
53   private static final String FIELD_CLIENT_SECRET = "client_secret";
54   private static final String JSON_PARSE_ERROR = "Error parsing Client ID JSON: ";
55 
56   private final String clientId;
57   private final String clientSecret;
58 
59   /**
60    * Constructs a client ID from an explicit ID and secret.
61    *
62    * <p>Note: Direct use of this factory method in application code is not recommended to avoid
63    * having secrets or values that need to be updated in source code.
64    *
65    * @param clientId Text identifier of the Client ID.
66    * @param clientSecret Secret to associated with the Client ID.
67    * @return The ClientId instance.
68    */
of(String clientId, String clientSecret)69   public static ClientId of(String clientId, String clientSecret) {
70     return new ClientId(clientId, clientSecret);
71   }
72 
73   /**
74    * Constructs a Client ID from JSON from a downloaded file.
75    *
76    * @param json the JSON from the downloaded file
77    * @return the ClientId instance based on the JSON
78    * @throws IOException the JSON could not be parsed
79    */
fromJson(Map<String, Object> json)80   public static ClientId fromJson(Map<String, Object> json) throws IOException {
81     Object rawDetail = null;
82     rawDetail = json.get(FIELD_TYPE_INSTALLED);
83     if (rawDetail == null) {
84       rawDetail = json.get(FIELD_TYPE_WEB);
85     }
86     if (rawDetail == null || !(rawDetail instanceof Map<?, ?>)) {
87       throw new IOException(
88           "Unable to parse Client ID JSON. Expecting top-level field '"
89               + FIELD_TYPE_WEB
90               + "' or '"
91               + FIELD_TYPE_INSTALLED
92               + "' of collection type");
93     }
94     @SuppressWarnings("unchecked")
95     Map<String, Object> detail = (Map<String, Object>) rawDetail;
96     String clientId = OAuth2Utils.validateString(detail, FIELD_CLIENT_ID, JSON_PARSE_ERROR);
97     if (clientId == null || clientId.length() == 0) {
98       throw new IOException(
99           "Unable to parse ClientId. Field '" + FIELD_CLIENT_ID + "' is required.");
100     }
101     String clientSecret =
102         OAuth2Utils.validateOptionalString(detail, FIELD_CLIENT_SECRET, JSON_PARSE_ERROR);
103     return new ClientId(clientId, clientSecret);
104   }
105 
106   /**
107    * Constructs a Client ID from JSON file stored as a resource.
108    *
109    * @param relativeClass a class in the same namespace as the resource
110    * @param resourceName the name of the resource
111    * @return the constructed ClientID instance based on the JSON in the resource
112    * @throws IOException The JSON could not be loaded or parsed.
113    */
fromResource(Class<?> relativeClass, String resourceName)114   public static ClientId fromResource(Class<?> relativeClass, String resourceName)
115       throws IOException {
116     InputStream stream = relativeClass.getResourceAsStream(resourceName);
117     return fromStream(stream);
118   }
119 
120   /**
121    * Constructs a Client ID from JSON file stream.
122    *
123    * @param stream the downloaded JSON file
124    * @return the constructed ClientID instance based on the JSON in the stream
125    * @throws IOException the JSON could not be read or parsed
126    */
fromStream(InputStream stream)127   public static ClientId fromStream(InputStream stream) throws IOException {
128     Preconditions.checkNotNull(stream);
129     JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY);
130     GenericJson parsedJson =
131         parser.parseAndClose(stream, StandardCharsets.UTF_8, GenericJson.class);
132     return fromJson(parsedJson);
133   }
134 
135   /**
136    * Constructs a client ID using an explicit ID and secret
137    *
138    * <p>Note: Direct use of this constructor in application code is not recommended to avoid having
139    * secrets or values that need to be updated in source code.
140    *
141    * @param clientId Text identifier of the Client ID.
142    * @param clientSecret Secret to associated with the Client ID.
143    */
ClientId(String clientId, String clientSecret)144   private ClientId(String clientId, String clientSecret) {
145     this.clientId = Preconditions.checkNotNull(clientId);
146     this.clientSecret = clientSecret;
147   }
148 
149   /**
150    * Returns the text identifier of the Client ID.
151    *
152    * @return The text identifier of the Client ID.
153    */
getClientId()154   public final String getClientId() {
155     return clientId;
156   }
157 
158   /**
159    * Returns the secret associated with the Client ID.
160    *
161    * @return The secret associated with the Client ID.
162    */
getClientSecret()163   public final String getClientSecret() {
164     return clientSecret;
165   }
166 
newBuilder()167   public static Builder newBuilder() {
168     return new Builder();
169   }
170 
toBuilder()171   public Builder toBuilder() {
172     return new Builder(this);
173   }
174 
175   public static class Builder {
176 
177     private String clientId;
178 
179     private String clientSecret;
180 
Builder()181     protected Builder() {}
182 
Builder(ClientId clientId)183     protected Builder(ClientId clientId) {
184       this.clientId = clientId.getClientId();
185       this.clientSecret = clientId.getClientSecret();
186     }
187 
188     @CanIgnoreReturnValue
setClientId(String clientId)189     public Builder setClientId(String clientId) {
190       this.clientId = clientId;
191       return this;
192     }
193 
194     @CanIgnoreReturnValue
setClientSecret(String clientSecret)195     public Builder setClientSecret(String clientSecret) {
196       this.clientSecret = clientSecret;
197       return this;
198     }
199 
getClientSecret()200     public String getClientSecret() {
201       return clientSecret;
202     }
203 
build()204     public ClientId build() {
205       return new ClientId(clientId, clientSecret);
206     }
207   }
208 }
209