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.common.internal.StringUtils.*;
016import static org.apache.juneau.internal.ArrayUtils.contains;
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.internal.*;
025import org.apache.juneau.marshaller.*;
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='bjson'>
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 * <h5 class='section'>See Also:</h5><ul>
061 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.Swagger">Overview &gt; juneau-rest-server &gt; Swagger</a>
062 * </ul>
063 */
064@Bean(properties="type,description,name,in,flow,authorizationUrl,tokenUrl,scopes,*")
065@FluentSetters
066public class SecurityScheme extends SwaggerElement {
067
068   private static final String[] VALID_TYPES = {"basic", "apiKey", "oauth2"};
069
070   private String
071      type,
072      description,
073      name,
074      in,
075      flow,
076      authorizationUrl,
077      tokenUrl;
078   private Map<String,String> scopes;
079
080   /**
081    * Default constructor.
082    */
083   public SecurityScheme() {}
084
085   /**
086    * Copy constructor.
087    *
088    * @param copyFrom The object to copy.
089    */
090   public SecurityScheme(SecurityScheme copyFrom) {
091      super(copyFrom);
092
093      this.authorizationUrl = copyFrom.authorizationUrl;
094      this.description = copyFrom.description;
095      this.flow = copyFrom.flow;
096      this.in = copyFrom.in;
097      this.name = copyFrom.name;
098      this.scopes = copyOf(copyFrom.scopes);
099      this.tokenUrl = copyFrom.tokenUrl;
100      this.type = copyFrom.type;
101   }
102
103   /**
104    * Make a deep copy of this object.
105    *
106    * @return A deep copy of this object.
107    */
108   public SecurityScheme copy() {
109      return new SecurityScheme(this);
110   }
111
112
113   @Override /* SwaggerElement */
114   protected SecurityScheme strict() {
115      super.strict();
116      return this;
117   }
118
119   //-----------------------------------------------------------------------------------------------------------------
120   // Properties
121   //-----------------------------------------------------------------------------------------------------------------
122
123   /**
124    * Bean property getter:  <property>authorizationUrl</property>.
125    *
126    * <p>
127    * The authorization URL to be used for this flow.
128    *
129    * @return The property value, or <jk>null</jk> if it is not set.
130    */
131   public String getAuthorizationUrl() {
132      return authorizationUrl;
133   }
134
135   /**
136    * Bean property setter:  <property>authorizationUrl</property>.
137    *
138    * <p>
139    * The authorization URL to be used for this flow.
140    *
141    * @param value
142    *    The new value for this property.
143    *    <br>This SHOULD be in the form of a URL.
144    *    <br>Can be <jk>null</jk> to unset the property.
145    * @return This object.
146    */
147   public SecurityScheme setAuthorizationUrl(String value) {
148      authorizationUrl = value;
149      return this;
150   }
151
152   /**
153    * Bean property getter:  <property>description</property>.
154    *
155    * <p>
156    * A short description for security scheme.
157    *
158    * @return The property value, or <jk>null</jk> if it is not set.
159    */
160   public String getDescription() {
161      return description;
162   }
163
164   /**
165    * Bean property setter:  <property>description</property>.
166    *
167    * <p>
168    * A short description for security scheme.
169    *
170    * @param value
171    *    The new value for this property.
172    *    <br>Can be <jk>null</jk> to unset the property.
173    * @return This object.
174    */
175   public SecurityScheme setDescription(String value) {
176      description = value;
177      return this;
178   }
179
180   /**
181    * Bean property getter:  <property>flow</property>.
182    *
183    * <p>
184    * The flow used by the OAuth2 security scheme.
185    *
186    * @return The property value, or <jk>null</jk> if it is not set.
187    */
188   public String getFlow() {
189      return flow;
190   }
191
192   /**
193    * Bean property setter:  <property>flow</property>.
194    *
195    * <p>
196    * The flow used by the OAuth2 security scheme.
197    *
198    * @param value
199    *    The new value for this property.
200    *    <br>Valid values:
201    *    <ul>
202    *       <li><js>"implicit"</js>
203    *       <li><js>"password"</js>
204    *       <li><js>"application"</js>
205    *       <li><js>"accessCode"</js>
206    *    </ul>
207    *    <br>Can be <jk>null</jk> to unset the property.
208    * @return This object.
209    */
210   public SecurityScheme setFlow(String value) {
211      flow = value;
212      return this;
213   }
214
215   /**
216    * Bean property getter:  <property>in</property>.
217    *
218    * <p>
219    * The location of the API key.
220    *
221    * @return The property value, or <jk>null</jk> if it is not set.
222    */
223   public String getIn() {
224      return in;
225   }
226
227   /**
228    * Bean property setter:  <property>in</property>.
229    *
230    * <p>
231    * The location of the API key.
232    *
233    * @param value
234    *    The new value for this property.
235    *    <br>Valid values:
236    *    <ul>
237    *       <li><js>"query"</js>
238    *       <li><js>"header"</js>
239    *    </ul>
240    *    <br>Can be <jk>null</jk> to unset the property.
241    * @return This object.
242    */
243   public SecurityScheme setIn(String value) {
244      in = value;
245      return this;
246   }
247
248   /**
249    * Bean property getter:  <property>name</property>.
250    *
251    * <p>
252    * The name of the header or query parameter to be used.
253    *
254    * @return The property value, or <jk>null</jk> if it is not set.
255    */
256   public String getName() {
257      return name;
258   }
259
260   /**
261    * Bean property setter:  <property>name</property>.
262    *
263    * <p>
264    * The name of the header or query parameter to be used.
265    *
266    * @param value
267    *    The new value for this property.
268    *    <br>Can be <jk>null</jk> to unset the property.
269    * @return This object.
270    */
271   public SecurityScheme setName(String value) {
272      name = value;
273      return this;
274   }
275
276   /**
277    * Bean property getter:  <property>scopes</property>.
278    *
279    * <p>
280    * The available scopes for the OAuth2 security scheme.
281    *
282    * @return The property value, or <jk>null</jk> if it is not set.
283    */
284   public Map<String,String> getScopes() {
285      return scopes;
286   }
287
288   /**
289    * Bean property setter:  <property>scopes</property>.
290    *
291    * <p>
292    * The available scopes for the OAuth2 security scheme.
293    *
294    * @param value
295    *    The new value for this property.
296    *    <br>Can be <jk>null</jk> to unset the property.
297    * @return This object.
298    */
299   public SecurityScheme setScopes(Map<String,String> value) {
300      scopes = copyOf(value);
301      return this;
302   }
303
304   /**
305    * Bean property appender:  <property>scopes</property>.
306    *
307    * <p>
308    * The available scopes for the OAuth2 security scheme.
309    *
310    * @param key The scope key.
311    * @param value The scope value.
312    * @return This object.
313    */
314   public SecurityScheme addScope(String key, String value) {
315      scopes = mapBuilder(scopes).sparse().add(key, value).build();
316      return this;
317   }
318
319   /**
320    * Bean property getter:  <property>tokenUrl</property>.
321    *
322    * <p>
323    * The token URL to be used for this flow.
324    *
325    * @return The property value, or <jk>null</jk> if it is not set.
326    */
327   public String getTokenUrl() {
328      return tokenUrl;
329   }
330
331   /**
332    * Bean property setter:  <property>tokenUrl</property>.
333    *
334    * <p>
335    * The token URL to be used for this flow.
336    *
337    * @param value
338    *    The new value for this property.
339    *    <br>This SHOULD be in the form of a URL.
340    *    <br>Can be <jk>null</jk> to unset the property.
341    * @return This object.
342    */
343   public SecurityScheme setTokenUrl(String value) {
344      tokenUrl = value;
345      return this;
346   }
347
348   /**
349    * Bean property getter:  <property>type</property>.
350    *
351    * <p>
352    * The type of the security scheme.
353    *
354    * @return The property value, or <jk>null</jk> if it is not set.
355    */
356   public String getType() {
357      return type;
358   }
359
360   /**
361    * Bean property setter:  <property>type</property>.
362    *
363    * <p>
364    * The type of the security scheme.
365    *
366    * @param value
367    *    The new value for this property.
368    *    <br>Valid values:
369    *    <ul>
370    *       <li><js>"basic"</js>
371    *       <li><js>"apiKey"</js>
372    *       <li><js>"oauth2"</js>
373    *    </ul>
374    *    <br>Property value is required.
375    * @return This object.
376    */
377   public SecurityScheme setType(String value) {
378      if (isStrict() && ! contains(value, VALID_TYPES))
379         throw new BasicRuntimeException(
380            "Invalid value passed in to setType(String).  Value=''{0}'', valid values={1}",
381            value, Json5.of(VALID_TYPES)
382         );
383      type = value;
384      return this;
385   }
386
387   // <FluentSetters>
388
389   // </FluentSetters>
390
391   @Override /* SwaggerElement */
392   public <T> T get(String property, Class<T> type) {
393      if (property == null)
394         return null;
395      switch (property) {
396         case "authorizationUrl": return toType(getAuthorizationUrl(), type);
397         case "description": return toType(getDescription(), type);
398         case "flow": return toType(getFlow(), type);
399         case "in": return toType(getIn(), type);
400         case "name": return toType(getName(), type);
401         case "scopes": return toType(getScopes(), type);
402         case "tokenUrl": return toType(getTokenUrl(), type);
403         case "type": return toType(getType(), type);
404         default: return super.get(property, type);
405      }
406   }
407
408   @Override /* SwaggerElement */
409   public SecurityScheme set(String property, Object value) {
410      if (property == null)
411         return this;
412      switch (property) {
413         case "authorizationUrl": return setAuthorizationUrl(stringify(value));
414         case "description": return setDescription(stringify(value));
415         case "flow": return setFlow(stringify(value));
416         case "in": return setIn(stringify(value));
417         case "name": return setName(stringify(value));
418         case "scopes": return setScopes(mapBuilder(String.class,String.class).sparse().addAny(value).build());
419         case "tokenUrl": return setTokenUrl(stringify(value));
420         case "type": return setType(stringify(value));
421         default:
422            super.set(property, value);
423            return this;
424      }
425   }
426
427   @Override /* SwaggerElement */
428   public Set<String> keySet() {
429      Set<String> s = setBuilder(String.class)
430         .addIf(authorizationUrl != null, "authorizationUrl")
431         .addIf(description != null, "description")
432         .addIf(flow != null, "flow")
433         .addIf(in != null, "in")
434         .addIf(name != null, "name")
435         .addIf(scopes != null, "scopes")
436         .addIf(tokenUrl != null, "tokenUrl")
437         .addIf(type != null, "type")
438         .build();
439      return new MultiSet<>(s, super.keySet());
440   }
441}