• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 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 java.util.HashMap;
35 import java.util.Locale;
36 import java.util.Map;
37 import javax.annotation.Nullable;
38 
39 /**
40  * The IdentityPool credential source. Dictates the retrieval method of the external credential,
41  * which can either be through a metadata server or a local file.
42  */
43 public class IdentityPoolCredentialSource extends ExternalAccountCredentials.CredentialSource {
44 
45   private static final long serialVersionUID = -745855247050085694L;
46   IdentityPoolCredentialSourceType credentialSourceType;
47   CredentialFormatType credentialFormatType;
48   String credentialLocation;
49   @Nullable String subjectTokenFieldName;
50   @Nullable Map<String, String> headers;
51 
52   /**
53    * The source of the 3P credential.
54    *
55    * <p>If this is a file based 3P credential, the credentials file can be retrieved using the
56    * `file` key.
57    *
58    * <p>If this is URL-based 3p credential, the metadata server URL can be retrieved using the `url`
59    * key.
60    *
61    * <p>The third party credential can be provided in different formats, such as text or JSON. The
62    * format can be specified using the `format` header, which returns a map with keys `type` and
63    * `subject_token_field_name`. If the `type` is json, the `subject_token_field_name` must be
64    * provided. If no format is provided, we expect the token to be in the raw text format.
65    *
66    * <p>Optional headers can be present, and should be keyed by `headers`.
67    */
68   @SuppressWarnings("unchecked")
IdentityPoolCredentialSource(Map<String, Object> credentialSourceMap)69   public IdentityPoolCredentialSource(Map<String, Object> credentialSourceMap) {
70     super(credentialSourceMap);
71 
72     if (credentialSourceMap.containsKey("file") && credentialSourceMap.containsKey("url")) {
73       throw new IllegalArgumentException(
74           "Only one credential source type can be set, either file or url.");
75     }
76 
77     if (credentialSourceMap.containsKey("file")) {
78       credentialLocation = (String) credentialSourceMap.get("file");
79       credentialSourceType = IdentityPoolCredentialSourceType.FILE;
80     } else if (credentialSourceMap.containsKey("url")) {
81       credentialLocation = (String) credentialSourceMap.get("url");
82       credentialSourceType = IdentityPoolCredentialSourceType.URL;
83     } else {
84       throw new IllegalArgumentException(
85           "Missing credential source file location or URL. At least one must be specified.");
86     }
87 
88     Map<String, String> headersMap = (Map<String, String>) credentialSourceMap.get("headers");
89     if (headersMap != null && !headersMap.isEmpty()) {
90       headers = new HashMap<>();
91       headers.putAll(headersMap);
92     }
93 
94     // If the format is not provided, we expect the token to be in the raw text format.
95     credentialFormatType = CredentialFormatType.TEXT;
96 
97     Map<String, String> formatMap = (Map<String, String>) credentialSourceMap.get("format");
98     if (formatMap != null && formatMap.containsKey("type")) {
99       String type = formatMap.get("type");
100 
101       if (type != null && "json".equals(type.toLowerCase(Locale.US))) {
102         // For JSON, the subject_token field name must be provided.
103         if (!formatMap.containsKey("subject_token_field_name")) {
104           throw new IllegalArgumentException(
105               "When specifying a JSON credential type, the subject_token_field_name must be set.");
106         }
107         credentialFormatType = CredentialFormatType.JSON;
108         subjectTokenFieldName = formatMap.get("subject_token_field_name");
109       } else if (type != null && "text".equals(type.toLowerCase(Locale.US))) {
110         credentialFormatType = CredentialFormatType.TEXT;
111       } else {
112         throw new IllegalArgumentException(
113             String.format("Invalid credential source format type: %s.", type));
114       }
115     }
116   }
117 
hasHeaders()118   boolean hasHeaders() {
119     return headers != null && !headers.isEmpty();
120   }
121 
122   enum IdentityPoolCredentialSourceType {
123     FILE,
124     URL
125   }
126 
127   enum CredentialFormatType {
128     TEXT,
129     JSON
130   }
131 }
132