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