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.Shorts.*;
020import static org.apache.juneau.marshall.internal.ConverterUtils.*;
021
022import java.util.*;
023
024import org.apache.juneau.commons.bean.*;
025import org.apache.juneau.commons.collections.*;
026
027/**
028 * Lists the required security schemes for this operation.
029 *
030 * <h5 class='section'>See Also:</h5><ul>
031 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a>
032 * </ul>
033 */
034@SuppressWarnings({
035   "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants
036})
037public class SecurityRequirement extends OpenApiElement {
038
039   private Map<String,List<String>> requirements;
040
041   /**
042    * Default constructor.
043    */
044   public SecurityRequirement() {}
045
046   /**
047    * Copy constructor.
048    *
049    * @param copyFrom The object to copy.
050    */
051   public SecurityRequirement(SecurityRequirement copyFrom) {
052      super(copyFrom);
053      this.requirements = cp(copyFrom.requirements);
054   }
055
056   /**
057    * Adds a security requirement.
058    *
059    * @param schemeName The security scheme name.  Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown.
060    * @param scopes The required scopes.  Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown.
061    * @return This object.
062    */
063   public SecurityRequirement addRequirement(String schemeName, String...scopes) {
064      reqnn("schemeName", schemeName);
065      reqnns("scopes", scopes);
066      if (requirements == null)
067         requirements = m();
068      requirements.put(schemeName, l(scopes));
069      return this;
070   }
071
072   /**
073    * Makes a copy of this object.
074    *
075    * @return A new copy of this object.
076    */
077   public SecurityRequirement copy() {
078      return new SecurityRequirement(this);
079   }
080
081   @Override /* Overridden from OpenApiElement */
082   public <T> T get(String property, Class<T> type) {
083      reqnn("property", property);
084      return switch (property) {
085         case "requirements" -> toType(getRequirements(), type);
086         default -> super.get(property, type);
087      };
088   }
089
090   /**
091    * Returns the security requirements map.
092    *
093    * @return The security requirements map, or <jk>null</jk> if not set.
094    */
095   public Map<String,List<String>> getRequirements() { return requirements; }
096
097   @Override /* Overridden from OpenApiElement */
098   public Set<String> keySet() {
099      // @formatter:off
100      var s = stb(String.class)
101         .addIf(nn(requirements), "requirements")
102         .build();
103      // @formatter:on
104      return new MultiSet<>(s, super.keySet());
105   }
106
107   @SuppressWarnings({
108      "unchecked" // Type erasure requires cast for map operations
109   })
110   @Override /* Overridden from OpenApiElement */
111   public SecurityRequirement set(String property, Object value) {
112      reqnn("property", property);
113      return switch (property) {
114         case "requirements" -> setRequirements((Map<String,List<String>>)value);
115         default -> {
116            super.set(property, value);
117            yield this;
118         }
119      };
120   }
121
122   /**
123    * Adds a security requirement for a scheme that doesn't use scopes.
124    *
125    * <p>
126    * This is a convenience method for adding security schemes that don't use scopes, such as API keys,
127    * HTTP Basic authentication, or HTTP Bearer tokens. According to the OpenAPI specification, security
128    * schemes that don't use scopes should have an empty array as the value.
129    *
130    * <p>
131    * This method is equivalent to calling <c>addRequirement(schemeName)</c> with no scopes.
132    *
133    * <h5 class='section'>Example:</h5>
134    * <p class='bjava'>
135    *    <jc>// Add API key authentication requirement</jc>
136    *    SecurityRequirement <jv>requirement</jv> = <jk>new</jk> SecurityRequirement()
137    *       .setApiKeyAuth(<js>"api_key"</js>);
138    *    <jc>// Results in: { "api_key": [] }</jc>
139    * </p>
140    *
141    * <h5 class='section'>See Also:</h5><ul>
142    *    <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#security-requirement-object">OpenAPI Specification &gt; Security Requirement Object</a>
143    *    <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/authentication/">OpenAPI Authentication</a>
144    * </ul>
145    *
146    * @param schemeName The security scheme name.  Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown.
147    * @return This object.
148    */
149   @BeanIgnore
150   public SecurityRequirement setApiKeyAuth(String schemeName) {
151      return addRequirement(schemeName);
152   }
153
154   /**
155    * Sets the security requirements map.
156    *
157    * @param value The new value for this property.
158    * @return This object.
159    */
160   public SecurityRequirement setRequirements(Map<String,List<String>> value) {
161      requirements = value;
162      return this;
163   }
164
165   @Override /* Overridden from OpenApiElement */
166   public SecurityRequirement strict() {
167      super.strict();
168      return this;
169   }
170
171   @Override /* Overridden from OpenApiElement */
172   public SecurityRequirement strict(Object value) {
173      super.strict(value);
174      return this;
175   }
176}