001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.dto.swagger;
014
015import static org.apache.juneau.internal.ArrayUtils.*;
016import static org.apache.juneau.internal.StringUtils.*;
017import static org.apache.juneau.internal.CollectionUtils.*;
018import static org.apache.juneau.internal.ConverterUtils.*;
019
020import java.util.*;
021
022import org.apache.juneau.*;
023import org.apache.juneau.annotation.*;
024import org.apache.juneau.collections.*;
025import org.apache.juneau.internal.*;
026
027/**
028 * Allows the definition of a security scheme that can be used by the operations.
029 *
030 * <p>
031 * Supported schemes are basic authentication, an API key (either as a header or as a query parameter) and OAuth2's
032 * common flows (implicit, password, application and access code).
033 *
034 * <h5 class='section'>Example:</h5>
035 * <p class='bcode w800'>
036 *    <jc>// Basic authentication sample</jc>
037 *    {
038 *       <js>"type"</js>: <js>"basic"</js>
039 *    }
040 *
041 *    <jc>// API key sample</jc>
042 *    {
043 *       <js>"type"</js>: <js>"apiKey"</js>,
044 *       <js>"name"</js>: <js>"api_key"</js>,
045 *       <js>"in"</js>: <js>"header"</js>
046 *    }
047 *
048 *    <jc>// Implicit OAuth2 sample</jc>
049 *    {
050 *       <js>"type"</js>: <js>"oauth2"</js>,
051 *       <js>"authorizationUrl"</js>: <js>"http://swagger.io/api/oauth/dialog"</js>,
052 *       <js>"flow"</js>: <js>"implicit"</js>,
053 *       <js>"scopes"</js>: {
054 *          <js>"write:pets"</js>: <js>"modify pets in your account"</js>,
055 *          <js>"read:pets"</js>: <js>"read your pets"</js>
056 *       }
057 *    }
058 * </p>
059 *
060 * <ul class='seealso'>
061 *    <li class='link'>{@doc DtoSwagger}
062 * </ul>
063 */
064@Bean(bpi="type,description,name,in,flow,authorizationUrl,tokenUrl,scopes,*")
065public class SecurityScheme extends SwaggerElement {
066
067   private static final String[] VALID_TYPES = {"basic", "apiKey", "oauth2"};
068
069   private String
070      type,
071      description,
072      name,
073      in,
074      flow,
075      authorizationUrl,
076      tokenUrl;
077   private Map<String,String> scopes;
078
079   /**
080    * Default constructor.
081    */
082   public SecurityScheme() {}
083
084   /**
085    * Copy constructor.
086    *
087    * @param copyFrom The object to copy.
088    */
089   public SecurityScheme(SecurityScheme copyFrom) {
090      super(copyFrom);
091
092      this.type = copyFrom.type;
093      this.description = copyFrom.description;
094      this.name = copyFrom.name;
095      this.in = copyFrom.in;
096      this.flow = copyFrom.flow;
097      this.authorizationUrl = copyFrom.authorizationUrl;
098      this.tokenUrl = copyFrom.tokenUrl;
099
100      if (copyFrom.scopes == null)
101         this.scopes = null;
102      else
103         this.scopes = new LinkedHashMap<>(copyFrom.scopes);
104   }
105
106   /**
107    * Make a deep copy of this object.
108    *
109    * @return A deep copy of this object.
110    */
111   public SecurityScheme copy() {
112      return new SecurityScheme(this);
113   }
114
115
116   @Override /* SwaggerElement */
117   protected SecurityScheme strict() {
118      super.strict();
119      return this;
120   }
121
122   /**
123    * Bean property getter:  <property>type</property>.
124    *
125    * <p>
126    * The type of the security scheme.
127    *
128    * @return The property value, or <jk>null</jk> if it is not set.
129    */
130   public String getType() {
131      return type;
132   }
133
134   /**
135    * Bean property setter:  <property>type</property>.
136    *
137    * <p>
138    * The type of the security scheme.
139    *
140    * @param value
141    *    The new value for this property.
142    *    <br>Valid values:
143    *    <ul>
144    *       <li><js>"basic"</js>
145    *       <li><js>"apiKey"</js>
146    *       <li><js>"oauth2"</js>
147    *    </ul>
148    *    <br>Property value is required.
149    * @return This object (for method chaining).
150    */
151   public SecurityScheme setType(String value) {
152      if (isStrict() && ! contains(value, VALID_TYPES))
153         throw new BasicRuntimeException(
154            "Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}",
155            value, VALID_TYPES
156         );
157      type = value;
158      return this;
159   }
160
161   /**
162    * Same as {@link #setType(String)}.
163    *
164    * @param value
165    *    The new value for this property.
166    *    <br>Non-String values will be converted to String using <c>toString()</c>.
167    *    <br>Valid values:
168    *    <ul>
169    *       <li><js>"basic"</js>
170    *       <li><js>"apiKey"</js>
171    *       <li><js>"oauth2"</js>
172    *    </ul>
173    *    <br>Can be <jk>null</jk> to unset the property.
174    * @return This object (for method chaining).
175    */
176   public SecurityScheme type(Object value) {
177      return setType(stringify(value));
178   }
179
180   /**
181    * Bean property getter:  <property>description</property>.
182    *
183    * <p>
184    * A short description for security scheme.
185    *
186    * @return The property value, or <jk>null</jk> if it is not set.
187    */
188   public String getDescription() {
189      return description;
190   }
191
192   /**
193    * Bean property setter:  <property>description</property>.
194    *
195    * <p>
196    * A short description for security scheme.
197    *
198    * @param value
199    *    The new value for this property.
200    *    <br>Can be <jk>null</jk> to unset the property.
201    * @return This object (for method chaining).
202    */
203   public SecurityScheme setDescription(String value) {
204      description = value;
205      return this;
206   }
207
208   /**
209    * Same as {@link #setDescription(String)}.
210    *
211    * @param value
212    *    The new value for this property.
213    *    <br>Non-String values will be converted to String using <c>toString()</c>.
214    *    <br>Can be <jk>null</jk> to unset the property.
215    * @return This object (for method chaining).
216    */
217   public SecurityScheme description(Object value) {
218      return setDescription(stringify(value));
219   }
220
221   /**
222    * Bean property getter:  <property>name</property>.
223    *
224    * <p>
225    * The name of the header or query parameter to be used.
226    *
227    * @return The property value, or <jk>null</jk> if it is not set.
228    */
229   public String getName() {
230      return name;
231   }
232
233   /**
234    * Bean property setter:  <property>name</property>.
235    *
236    * <p>
237    * The name of the header or query parameter to be used.
238    *
239    * @param value
240    *    The new value for this property.
241    *    <br>Can be <jk>null</jk> to unset the property.
242    * @return This object (for method chaining).
243    */
244   public SecurityScheme setName(String value) {
245      name = value;
246      return this;
247   }
248
249   /**
250    * Same as {@link #setName(String)}.
251    *
252    * @param value
253    *    The new value for this property.
254    *    <br>Non-String values will be converted to String using <c>toString()</c>.
255    *    <br>Can be <jk>null</jk> to unset the property.
256    * @return This object (for method chaining).
257    */
258   public SecurityScheme name(Object value) {
259      return setName(stringify(value));
260   }
261
262   /**
263    * Bean property getter:  <property>in</property>.
264    *
265    * <p>
266    * The location of the API key.
267    *
268    * @return The property value, or <jk>null</jk> if it is not set.
269    */
270   public String getIn() {
271      return in;
272   }
273
274   /**
275    * Bean property setter:  <property>in</property>.
276    *
277    * <p>
278    * The location of the API key.
279    *
280    * @param value
281    *    The new value for this property.
282    *    <br>Valid values:
283    *    <ul>
284    *       <li><js>"query"</js>
285    *       <li><js>"header"</js>
286    *    </ul>
287    *    <br>Can be <jk>null</jk> to unset the property.
288    * @return This object (for method chaining).
289    */
290   public SecurityScheme setIn(String value) {
291      in = value;
292      return this;
293   }
294
295   /**
296    * Same as {@link #setIn(String)}.
297    *
298    * @param value
299    *    The new value for this property.
300    *    <br>Non-String values will be converted to String using <c>toString()</c>.
301    *    <br>Valid values:
302    *    <ul>
303    *       <li><js>"query"</js>
304    *       <li><js>"header"</js>
305    *    </ul>
306    *    <br>Can be <jk>null</jk> to unset the property.
307    * @return This object (for method chaining).
308    */
309   public SecurityScheme in(Object value) {
310      return setIn(stringify(value));
311   }
312
313   /**
314    * Bean property getter:  <property>flow</property>.
315    *
316    * <p>
317    * The flow used by the OAuth2 security scheme.
318    *
319    * @return The property value, or <jk>null</jk> if it is not set.
320    */
321   public String getFlow() {
322      return flow;
323   }
324
325   /**
326    * Bean property setter:  <property>flow</property>.
327    *
328    * <p>
329    * The flow used by the OAuth2 security scheme.
330    *
331    * @param value
332    *    The new value for this property.
333    *    <br>Valid values:
334    *    <ul>
335    *       <li><js>"implicit"</js>
336    *       <li><js>"password"</js>
337    *       <li><js>"application"</js>
338    *       <li><js>"accessCode"</js>
339    *    </ul>
340    *    <br>Can be <jk>null</jk> to unset the property.
341    * @return This object (for method chaining).
342    */
343   public SecurityScheme setFlow(String value) {
344      flow = value;
345      return this;
346   }
347
348   /**
349    * Same as {@link #setFlow(String)}.
350    *
351    * @param value
352    *    The new value for this property.
353    *    <br>Non-String values will be converted to String using <c>toString()</c>.
354    *    <br>Valid values:
355    *    <ul>
356    *       <li><js>"implicit"</js>
357    *       <li><js>"password"</js>
358    *       <li><js>"application"</js>
359    *       <li><js>"accessCode"</js>
360    *    </ul>
361    *    <br>Can be <jk>null</jk> to unset the property.
362    * @return This object (for method chaining).
363    */
364   public SecurityScheme flow(Object value) {
365      return setFlow(stringify(value));
366   }
367
368   /**
369    * Bean property getter:  <property>authorizationUrl</property>.
370    *
371    * <p>
372    * The authorization URL to be used for this flow.
373    *
374    * @return The property value, or <jk>null</jk> if it is not set.
375    */
376   public String getAuthorizationUrl() {
377      return authorizationUrl;
378   }
379
380   /**
381    * Bean property setter:  <property>authorizationUrl</property>.
382    *
383    * <p>
384    * The authorization URL to be used for this flow.
385    *
386    * @param value
387    *    The new value for this property.
388    *    <br>This SHOULD be in the form of a URL.
389    *    <br>Can be <jk>null</jk> to unset the property.
390    * @return This object (for method chaining).
391    */
392   public SecurityScheme setAuthorizationUrl(String value) {
393      authorizationUrl = value;
394      return this;
395   }
396
397   /**
398    * Same as {@link #setAuthorizationUrl(String)}.
399    *
400    * @param value
401    *    The new value for this property.
402    *    <br>Non-String values will be converted to String using <c>toString()</c>.
403    *    <br>This SHOULD be in the form of a URL.
404    *    <br>Can be <jk>null</jk> to unset the property.
405    * @return This object (for method chaining).
406    */
407   public SecurityScheme authorizationUrl(Object value) {
408      return setAuthorizationUrl(stringify(value));
409   }
410
411   /**
412    * Bean property getter:  <property>tokenUrl</property>.
413    *
414    * <p>
415    * The token URL to be used for this flow.
416    *
417    * @return The property value, or <jk>null</jk> if it is not set.
418    */
419   public String getTokenUrl() {
420      return tokenUrl;
421   }
422
423   /**
424    * Bean property setter:  <property>tokenUrl</property>.
425    *
426    * <p>
427    * The token URL to be used for this flow.
428    *
429    * @param value
430    *    The new value for this property.
431    *    <br>This SHOULD be in the form of a URL.
432    *    <br>Can be <jk>null</jk> to unset the property.
433    * @return This object (for method chaining).
434    */
435   public SecurityScheme setTokenUrl(String value) {
436      tokenUrl = value;
437      return this;
438   }
439
440   /**
441    * Same as {@link #setTokenUrl(String)}.
442    *
443    * @param value
444    *    The new value for this property.
445    *    <br>Non-String values will be converted to String using <c>toString()</c>.
446    *    <br>This SHOULD be in the form of a URL.
447    *    <br>Can be <jk>null</jk> to unset the property.
448    * @return This object (for method chaining).
449    */
450   public SecurityScheme tokenUrl(Object value) {
451      return setTokenUrl(stringify(value));
452   }
453
454   /**
455    * Bean property getter:  <property>scopes</property>.
456    *
457    * <p>
458    * The available scopes for the OAuth2 security scheme.
459    *
460    * @return The property value, or <jk>null</jk> if it is not set.
461    */
462   public Map<String,String> getScopes() {
463      return scopes;
464   }
465
466   /**
467    * Bean property setter:  <property>scopes</property>.
468    *
469    * <p>
470    * The available scopes for the OAuth2 security scheme.
471    *
472    * @param value
473    *    The new value for this property.
474    *    <br>Can be <jk>null</jk> to unset the property.
475    * @return This object (for method chaining).
476    */
477   public SecurityScheme setScopes(Map<String,String> value) {
478      scopes = newMap(value);
479      return this;
480   }
481
482   /**
483    * Adds one or more values to the <property>scopes</property> property.
484    *
485    * @param values
486    *    The values to add to this property.
487    *    <br>Ignored if <jk>null</jk>.
488    * @return This object (for method chaining).
489    */
490   public SecurityScheme addScopes(Map<String,String> values) {
491      scopes = addToMap(scopes, values);
492      return this;
493   }
494
495   /**
496    * Adds one or more values to the <property>enum</property> property.
497    *
498    * @param values
499    *    The values to add to this property.
500    *    <br>Valid types:
501    *    <ul>
502    *       <li><c>Map&lt;String,{@link HeaderInfo}|String&gt;</c>
503    *       <li><c>String</c> - JSON object representation of <c>Map&lt;String,{@link HeaderInfo}&gt;</c>
504    *          <p class='bcode w800'>
505    *    <jc>// Example </jc>
506    *    scopes(<js>"{name:'value'}"</js>);
507    *          </p>
508    *    </ul>
509    *    <br>Ignored if <jk>null</jk>.
510    * @return This object (for method chaining).
511    */
512   public SecurityScheme scopes(Object...values) {
513      scopes = addToMap(scopes, values, String.class, String.class);
514      return this;
515   }
516
517   @Override /* SwaggerElement */
518   public <T> T get(String property, Class<T> type) {
519      if (property == null)
520         return null;
521      switch (property) {
522         case "type": return toType(getType(), type);
523         case "description": return toType(getDescription(), type);
524         case "name": return toType(getName(), type);
525         case "in": return toType(getIn(), type);
526         case "flow": return toType(getFlow(), type);
527         case "authorizationUrl": return toType(getAuthorizationUrl(), type);
528         case "tokenUrl": return toType(getTokenUrl(), type);
529         case "scopes": return toType(getScopes(), type);
530         default: return super.get(property, type);
531      }
532   }
533
534   @Override /* SwaggerElement */
535   public SecurityScheme set(String property, Object value) {
536      if (property == null)
537         return this;
538      switch (property) {
539         case "type": return type(value);
540         case "description": return description(value);
541         case "name": return name(value);
542         case "in": return in(value);
543         case "flow": return flow(value);
544         case "authorizationUrl": return authorizationUrl(value);
545         case "tokenUrl": return tokenUrl(value);
546         case "scopes": return setScopes(null).scopes(value);
547         default:
548            super.set(property, value);
549            return this;
550      }
551   }
552
553   @Override /* SwaggerElement */
554   public Set<String> keySet() {
555      ASet<String> s = ASet.<String>of()
556         .aif(type != null, "type")
557         .aif(description != null, "description")
558         .aif(name != null, "name")
559         .aif(in != null, "in")
560         .aif(flow != null, "flow")
561         .aif(authorizationUrl != null, "authorizationUrl")
562         .aif(tokenUrl != null, "tokenUrl")
563         .aif(scopes != null, "scopes");
564      return new MultiSet<>(s, super.keySet());
565   }
566}