001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bean.openapi3;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020import static org.apache.juneau.commons.utils.CollectionUtils.*;
021import static org.apache.juneau.commons.utils.StringUtils.*;
022import static org.apache.juneau.commons.utils.ThrowableUtils.*;
023import static org.apache.juneau.commons.utils.Utils.*;
024import static org.apache.juneau.internal.ConverterUtils.*;
025
026import java.util.*;
027
028import org.apache.juneau.commons.collections.*;
029
030/**
031 * Defines a security scheme that can be used by the operations.
032 *
033 * <p>
034 * The Security Scheme Object defines a security scheme that can be used by the operations. Supported schemes are
035 * HTTP authentication, an API key (either as a header or as a query parameter), OAuth2's common flows (implicit,
036 * password, client credentials and authorization code) as defined in RFC6749, and OpenID Connect Discovery.
037 *
038 * <h5 class='section'>OpenAPI Specification:</h5>
039 * <p>
040 * The Security Scheme Object is composed of the following fields:
041 * <ul class='spaced-list'>
042 *    <li><c>type</c> (string, REQUIRED) - The type of the security scheme. Values: <js>"apiKey"</js>, <js>"http"</js>, <js>"oauth2"</js>, <js>"openIdConnect"</js>
043 *    <li><c>description</c> (string) - A short description for security scheme (CommonMark syntax may be used)
044 *    <li><c>name</c> (string) - The name of the header, query or cookie parameter to be used (for <js>"apiKey"</js> type)
045 *    <li><c>in</c> (string) - The location of the API key (for <js>"apiKey"</js> type). Values: <js>"query"</js>, <js>"header"</js>, <js>"cookie"</js>
046 *    <li><c>scheme</c> (string) - The name of the HTTP Authorization scheme to be used in the Authorization header (for <js>"http"</js> type)
047 *    <li><c>bearerFormat</c> (string) - A hint to the client to identify how the bearer token is formatted (for <js>"http"</js> type with <js>"bearer"</js> scheme)
048 *    <li><c>flows</c> ({@link OAuthFlows}) - An object containing configuration information for the flow types supported (for <js>"oauth2"</js> type)
049 *    <li><c>openIdConnectUrl</c> (string) - OpenId Connect URL to discover OAuth2 configuration values (for <js>"openIdConnect"</js> type)
050 * </ul>
051 *
052 * <h5 class='section'>Example:</h5>
053 * <p class='bjava'>
054 *    <jc>// Create an API key security scheme</jc>
055 *    SecuritySchemeInfo <jv>scheme</jv> = <jk>new</jk> SecuritySchemeInfo()
056 *       .setType(<js>"apiKey"</js>)
057 *       .setDescription(<js>"API key authentication"</js>)
058 *       .setName(<js>"X-API-Key"</js>)
059 *       .setIn(<js>"header"</js>);
060 * </p>
061 * <p class='bjava'>
062 *    <jc>// Create an OAuth2 security scheme</jc>
063 *    SecuritySchemeInfo <jv>oauthScheme</jv> = <jk>new</jk> SecuritySchemeInfo()
064 *       .setType(<js>"oauth2"</js>)
065 *       .setDescription(<js>"OAuth2 authentication"</js>)
066 *       .setFlows(
067 *          <jk>new</jk> OAuthFlows()
068 *             .setAuthorizationCode(
069 *                <jk>new</jk> OAuthFlow()
070 *                   .setAuthorizationUrl(<js>"https://example.com/oauth/authorize"</js>)
071 *                   .setTokenUrl(<js>"https://example.com/oauth/token"</js>)
072 *                   .setScopes(
073 *                      JsonMap.<jsm>of</jsm>(
074 *                         <js>"read"</js>, <js>"Read access to resources"</js>,
075 *                         <js>"write"</js>, <js>"Write access to resources"</js>
076 *                      )
077 *                   )
078 *             )
079 *       );
080 * </p>
081 *
082 * <h5 class='section'>See Also:</h5><ul>
083 *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#security-scheme-object">OpenAPI Specification &gt; Security Scheme Object</a>
084 *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/authentication/">OpenAPI Authentication</a>
085 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
086 * </ul>
087 */
088public class SecuritySchemeInfo extends OpenApiElement {
089
090   private static final String[] VALID_IN = { "query", "header", "cookie" };
091   private static final String[] VALID_TYPES = { "apiKey", "http", "oauth2", "openIdConnect" };
092
093   private String type, description, name, in, scheme, bearerFormat, openIdConnectUrl;
094
095   private OAuthFlow flows;
096
097   /**
098    * Default constructor.
099    */
100   public SecuritySchemeInfo() {}
101
102   /**
103    * Copy constructor.
104    *
105    * @param copyFrom The object to copy.
106    */
107   public SecuritySchemeInfo(SecuritySchemeInfo copyFrom) {
108      super(copyFrom);
109
110      this.name = copyFrom.name;
111      this.in = copyFrom.in;
112      this.description = copyFrom.description;
113      this.type = copyFrom.type;
114      this.scheme = copyFrom.scheme;
115      this.bearerFormat = copyFrom.bearerFormat;
116      this.openIdConnectUrl = copyFrom.openIdConnectUrl;
117      this.flows = copyFrom.flows;
118   }
119
120   /**
121    * Make a deep copy of this object.
122    *
123    * @return A deep copy of this object.
124    */
125   public SecuritySchemeInfo copy() {
126      return new SecuritySchemeInfo(this);
127   }
128
129   @Override /* Overridden from SwaggerElement */
130   public <T> T get(String property, Class<T> type) {
131      assertArgNotNull("property", property);
132      return switch (property) {
133         case "name" -> toType(getName(), type);
134         case "in" -> toType(getIn(), type);
135         case "description" -> toType(getDescription(), type);
136         case "scheme" -> toType(getScheme(), type);
137         case "flows" -> toType(getFlows(), type);
138         case "bearerFormat" -> toType(getBearerFormat(), type);
139         case "openIdConnectUrl" -> toType(getOpenIdConnectUrl(), type);
140         case "type" -> toType(getType(), type);
141         default -> super.get(property, type);
142      };
143   }
144
145   /**
146    * Bean property getter:  <property>format</property>.
147    *
148    * <p>
149    * The extending format for the previously mentioned type.
150    *
151    * @return The property value, or <jk>null</jk> if it is not set.
152    */
153   public String getBearerFormat() { return bearerFormat; }
154
155   /**
156    * Bean property getter:  <property>description</property>.
157    *
158    * <p>
159    * A brief description of the parameter.
160    * <br>This could contain examples of use.
161    *
162    * @return The property value, or <jk>null</jk> if it is not set.
163    */
164   public String getDescription() { return description; }
165
166   /**
167    * Bean property getter:  <property>items</property>.
168    *
169    * <p>
170    * Describes the type of items in the array.
171    *
172    * @return The property value, or <jk>null</jk> if it is not set.
173    */
174   public OAuthFlow getFlows() { return flows; }
175
176   /**
177    * Bean property getter:  <property>in</property>.
178    *
179    * <p>
180    * The location of the parameter.
181    *
182    * @return The property value, or <jk>null</jk> if it is not set.
183    */
184   public String getIn() { return in; }
185
186   /**
187    * Bean property getter:  <property>name</property>.
188    *
189    * <p>
190    * The name of the parameter.
191    *
192    * <h5 class='section'>Notes:</h5>
193    * <ul class='spaced-list'>
194    *    <li>
195    *       Parameter names are case sensitive.
196    *    <li>
197    *       If <code>in</code> is <js>"path"</js>, the <code>name</code> field MUST correspond to the associated path segment
198    *       from the <code>path</code> field in the paths object.
199    *    <li>
200    *       For all other cases, the name corresponds to the parameter name used based on the <code>in</code> property.
201    * </ul>
202    *
203    * @return The property value, or <jk>null</jk> if it is not set.
204    */
205   public String getName() { return name; }
206
207   /**
208    * Bean property getter:  <property>collectionFormat</property>.
209    *
210    * <p>
211    * Determines the format of the array if type array is used.
212    *
213    * @return The property value, or <jk>null</jk> if it is not set.
214    */
215   public String getOpenIdConnectUrl() { return openIdConnectUrl; }
216
217   /**
218    * Bean property getter:  <property>schema</property>.
219    *
220    * <p>
221    * The schema defining the type used for the body parameter.
222    *
223    * @return The property value, or <jk>null</jk> if it is not set.
224    */
225   public String getScheme() { return scheme; }
226
227   /**
228    * Bean property getter:  <property>type</property>.
229    *
230    * <p>
231    * The type of the parameter.
232    *
233    * @return The property value, or <jk>null</jk> if it is not set.
234    */
235   public String getType() { return type; }
236
237   @Override /* Overridden from SwaggerElement */
238   public Set<String> keySet() {
239      // @formatter:off
240      var s = setb(String.class)
241         .addIf(nn(bearerFormat), "bearerFormat")
242         .addIf(nn(description), "description")
243         .addIf(nn(flows), "flows")
244         .addIf(nn(in), "in")
245         .addIf(nn(name), "name")
246         .addIf(nn(openIdConnectUrl), "openIdConnectUrl")
247         .addIf(nn(scheme), "scheme")
248         .addIf(nn(type), "type")
249         .build();
250      // @formatter:on
251      return new MultiSet<>(s, super.keySet());
252   }
253
254   @Override /* Overridden from SwaggerElement */
255   public SecuritySchemeInfo set(String property, Object value) {
256      assertArgNotNull("property", property);
257      return switch (property) {
258         case "bearerFormat" -> setBearerFormat(s(value));
259         case "description" -> setDescription(s(value));
260         case "flows" -> setFlows(toType(value, OAuthFlow.class));
261         case "in" -> setIn(s(value));
262         case "name" -> setName(s(value));
263         case "openIdConnectUrl" -> setOpenIdConnectUrl(s(value));
264         case "scheme" -> setScheme(s(value));
265         case "type" -> setType(s(value));
266         default -> {
267            super.set(property, value);
268            yield this;
269         }
270      };
271   }
272
273   /**
274    * Bean property setter:  <property>format</property>.
275    *
276    * <p>
277    * The extending format for the previously mentioned type.
278    *
279    * @param value The new value for this property.
280    *    <br>Can be <jk>null</jk> to unset the property.
281    * @return This object
282    */
283   public SecuritySchemeInfo setBearerFormat(String value) {
284      bearerFormat = value;
285      return this;
286   }
287
288   /**
289    * Bean property setter:  <property>description</property>.
290    *
291    * <p>
292    * A brief description of the parameter.
293    * <br>This could contain examples of use.
294    *
295    * @param value
296    *    The new value for this property.
297    *    <br>Can be <jk>null</jk> to unset the property.
298    * @return This object
299    */
300   public SecuritySchemeInfo setDescription(String value) {
301      description = value;
302      return this;
303   }
304
305   /**
306    * Bean property setter:  <property>items</property>.
307    *
308    * <p>
309    * Describes the type of items in the array.
310    *
311    * @param value
312    *    The new value for this property.
313    *    <br>Property value is required if <code>type</code> is <js>"array"</js>.
314    *    <br>Can be <jk>null</jk> to unset the property.
315    * @return This object
316    */
317   public SecuritySchemeInfo setFlows(OAuthFlow value) {
318      flows = value;
319      return this;
320   }
321
322   /**
323    * Bean property setter:  <property>in</property>.
324    *
325    * <p>
326    * The location of the parameter.
327    *
328    * @param value
329    *    The new value for this property.
330    *    <br>Valid values:
331    *    <ul>
332    *       <li><js>"query"</js>
333    *       <li><js>"header"</js>
334    *       <li><js>"path"</js>
335    *       <li><js>"formData"</js>
336    *       <li><js>"body"</js>
337    *    </ul>
338    *    <br>Property value is required.
339    *    <br>Can be <jk>null</jk> to unset the property.
340    * @return This object
341    */
342   public SecuritySchemeInfo setIn(String value) {
343      if (isStrict() && ! contains(value, VALID_IN))
344         throw rex("Invalid value passed in to setIn(String).  Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_IN));
345      in = value;
346      return this;
347   }
348
349   /**
350    * Bean property setter:  <property>name</property>.
351    *
352    * <p>
353    * The name of the parameter.
354    *
355    * <h5 class='section'>Notes:</h5>
356    * <ul class='spaced-list'>
357    *    <li>
358    *       Parameter names are case sensitive.
359    *    <li>
360    *       If <code>in</code> is <js>"path"</js>, the <code>name</code> field MUST correspond to the associated path segment
361    *       from the <code>path</code> field in the paths object.
362    *    <li>
363    *       For all other cases, the name corresponds to the parameter name used based on the <code>in</code> property.
364    * </ul>
365    *
366    * @param value
367    *    The new value for this property.
368    *    <br>Property value is required.
369    *    <br>Can be <jk>null</jk> to unset the property.
370    * @return This object
371    */
372   public SecuritySchemeInfo setName(String value) {
373      name = value;
374      return this;
375   }
376
377   /**
378    * Bean property setter:  <property>collectionFormat</property>.
379    *
380    * <p>
381    * Determines the format of the array if type array is used.
382    *
383    * @param value The new value for this property.
384    *    <br>Can be <jk>null</jk> to unset the property.
385    * @return This object
386    */
387   public SecuritySchemeInfo setOpenIdConnectUrl(String value) {
388      openIdConnectUrl = value;
389      return this;
390   }
391
392   /**
393    * Bean property setter:  <property>schema</property>.
394    *
395    * <p>
396    * The schema defining the type used for the body parameter.
397    *
398    * @param value
399    *    The new value for this property.
400    *    <br>Property value is required.
401    *    <br>Can be <jk>null</jk> to unset the property.
402    * @return This object
403    */
404   public SecuritySchemeInfo setScheme(String value) {
405      scheme = value;
406      return this;
407   }
408
409   /**
410    * Bean property setter:  <property>type</property>.
411    *
412    * <p>
413    * The type of the parameter.
414    *
415    * @param value
416    *    The new value for this property.
417    *    <br>Valid values:
418    *    <ul>
419    *       <li><js>"string"</js>
420    *       <li><js>"number"</js>
421    *       <li><js>"integer"</js>
422    *       <li><js>"boolean"</js>
423    *       <li><js>"array"</js>
424    *       <li><js>"file"</js>
425    *    </ul>
426    *    <br>If type is <js>"file"</js>, the <code>consumes</code> MUST be either <js>"multipart/form-data"</js>, <js>"application/x-www-form-urlencoded"</js>
427    *       or both and the parameter MUST be <code>in</code> <js>"formData"</js>.
428    *    <br>Property value is required.
429    *    <br>Can be <jk>null</jk> to unset the property.
430    * @return This object
431    */
432   public SecuritySchemeInfo setType(String value) {
433      if (isStrict() && ! contains(value, VALID_TYPES))
434         throw rex("Invalid value passed in to setType(String).  Value=''{0}'', valid values=[{1}]", value, toCdl(VALID_TYPES));
435      type = value;
436      return this;
437   }
438
439   @Override /* Overridden from OpenApiElement */
440   public SecuritySchemeInfo strict(Object value) {
441      super.strict(value);
442      return this;
443   }
444
445   @Override /* Overridden from SwaggerElement */
446   protected SecuritySchemeInfo strict() {
447      super.strict();
448      return this;
449   }
450}