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.common.utils.Utils.*; 020import static org.apache.juneau.internal.ArrayUtils.contains; 021import static org.apache.juneau.internal.CollectionUtils.*; 022import static org.apache.juneau.internal.ConverterUtils.*; 023 024import java.util.*; 025 026import org.apache.juneau.*; 027import org.apache.juneau.common.utils.*; 028import org.apache.juneau.internal.*; 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 > 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 094 type, 095 description, 096 name, 097 in, 098 scheme, 099 bearerFormat, 100 openIdConnectUrl; 101 102 private OAuthFlow flows; 103 104 /** 105 * Default constructor. 106 */ 107 public SecuritySchemeInfo() {} 108 109 /** 110 * Copy constructor. 111 * 112 * @param copyFrom The object to copy. 113 */ 114 public SecuritySchemeInfo(SecuritySchemeInfo copyFrom) { 115 super(copyFrom); 116 117 this.name = copyFrom.name; 118 this.in = copyFrom.in; 119 this.description = copyFrom.description; 120 this.type = copyFrom.type; 121 this.scheme = copyFrom.scheme; 122 this.bearerFormat = copyFrom.bearerFormat; 123 this.openIdConnectUrl = copyFrom.openIdConnectUrl; 124 this.flows = copyFrom.flows; 125 } 126 127 /** 128 * Make a deep copy of this object. 129 * 130 * @return A deep copy of this object. 131 */ 132 public SecuritySchemeInfo copy() { 133 return new SecuritySchemeInfo(this); 134 } 135 136 @Override /* SwaggerElement */ 137 protected SecuritySchemeInfo strict() { 138 super.strict(); 139 return this; 140 } 141 142 @Override /* Overridden from OpenApiElement */ 143 public SecuritySchemeInfo strict(Object value) { 144 super.strict(value); 145 return this; 146 } 147 148 /** 149 * Bean property getter: <property>name</property>. 150 * 151 * <p> 152 * The name of the parameter. 153 * 154 * <h5 class='section'>Notes:</h5> 155 * <ul class='spaced-list'> 156 * <li> 157 * Parameter names are case sensitive. 158 * <li> 159 * If <code>in</code> is <js>"path"</js>, the <code>name</code> field MUST correspond to the associated path segment 160 * from the <code>path</code> field in the paths object. 161 * <li> 162 * For all other cases, the name corresponds to the parameter name used based on the <code>in</code> property. 163 * </ul> 164 * 165 * @return The property value, or <jk>null</jk> if it is not set. 166 */ 167 public String getName() { 168 return name; 169 } 170 171 /** 172 * Bean property setter: <property>name</property>. 173 * 174 * <p> 175 * The name of the parameter. 176 * 177 * <h5 class='section'>Notes:</h5> 178 * <ul class='spaced-list'> 179 * <li> 180 * Parameter names are case sensitive. 181 * <li> 182 * If <code>in</code> is <js>"path"</js>, the <code>name</code> field MUST correspond to the associated path segment 183 * from the <code>path</code> field in the paths object. 184 * <li> 185 * For all other cases, the name corresponds to the parameter name used based on the <code>in</code> property. 186 * </ul> 187 * 188 * @param value 189 * The new value for this property. 190 * <br>Property value is required. 191 * <br>Can be <jk>null</jk> to unset the property. 192 * @return This object 193 */ 194 public SecuritySchemeInfo setName(String value) { 195 name = value; 196 return this; 197 } 198 199 /** 200 * Bean property getter: <property>in</property>. 201 * 202 * <p> 203 * The location of the parameter. 204 * 205 * @return The property value, or <jk>null</jk> if it is not set. 206 */ 207 public String getIn() { 208 return in; 209 } 210 211 /** 212 * Bean property setter: <property>in</property>. 213 * 214 * <p> 215 * The location of the parameter. 216 * 217 * @param value 218 * The new value for this property. 219 * <br>Valid values: 220 * <ul> 221 * <li><js>"query"</js> 222 * <li><js>"header"</js> 223 * <li><js>"path"</js> 224 * <li><js>"formData"</js> 225 * <li><js>"body"</js> 226 * </ul> 227 * <br>Property value is required. 228 * <br>Can be <jk>null</jk> to unset the property. 229 * @return This object 230 */ 231 public SecuritySchemeInfo setIn(String value) { 232 if (isStrict() && ! contains(value, VALID_IN)) 233 throw new BasicRuntimeException( 234 "Invalid value passed in to setIn(String). Value=''{0}'', valid values={1}", 235 value, VALID_IN 236 ); 237 in = value; 238 return this; 239 } 240 241 /** 242 * Bean property getter: <property>description</property>. 243 * 244 * <p> 245 * A brief description of the parameter. 246 * <br>This could contain examples of use. 247 * 248 * @return The property value, or <jk>null</jk> if it is not set. 249 */ 250 public String getDescription() { 251 return description; 252 } 253 254 /** 255 * Bean property setter: <property>description</property>. 256 * 257 * <p> 258 * A brief description of the parameter. 259 * <br>This could contain examples of use. 260 * 261 * @param value 262 * The new value for this property. 263 * <br>Can be <jk>null</jk> to unset the property. 264 * @return This object 265 */ 266 public SecuritySchemeInfo setDescription(String value) { 267 description = value; 268 return this; 269 } 270 271 /** 272 * Bean property getter: <property>schema</property>. 273 * 274 * <p> 275 * The schema defining the type used for the body parameter. 276 * 277 * @return The property value, or <jk>null</jk> if it is not set. 278 */ 279 public String getScheme() { 280 return scheme; 281 } 282 283 /** 284 * Bean property setter: <property>schema</property>. 285 * 286 * <p> 287 * The schema defining the type used for the body parameter. 288 * 289 * @param value 290 * The new value for this property. 291 * <br>Property value is required. 292 * <br>Can be <jk>null</jk> to unset the property. 293 * @return This object 294 */ 295 public SecuritySchemeInfo setScheme(String value) { 296 scheme = value; 297 return this; 298 } 299 300 /** 301 * Bean property getter: <property>type</property>. 302 * 303 * <p> 304 * The type of the parameter. 305 * 306 * @return The property value, or <jk>null</jk> if it is not set. 307 */ 308 public String getType() { 309 return type; 310 } 311 312 /** 313 * Bean property setter: <property>type</property>. 314 * 315 * <p> 316 * The type of the parameter. 317 * 318 * @param value 319 * The new value for this property. 320 * <br>Valid values: 321 * <ul> 322 * <li><js>"string"</js> 323 * <li><js>"number"</js> 324 * <li><js>"integer"</js> 325 * <li><js>"boolean"</js> 326 * <li><js>"array"</js> 327 * <li><js>"file"</js> 328 * </ul> 329 * <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> 330 * or both and the parameter MUST be <code>in</code> <js>"formData"</js>. 331 * <br>Property value is required. 332 * <br>Can be <jk>null</jk> to unset the property. 333 * @return This object 334 */ 335 public SecuritySchemeInfo setType(String value) { 336 if (isStrict() && ! contains(value, VALID_TYPES)) 337 throw new BasicRuntimeException( 338 "Invalid value passed in to setType(String). Value=''{0}'', valid values={1}", 339 value, VALID_TYPES 340 ); 341 type = value; 342 return this; 343 } 344 345 /** 346 * Bean property getter: <property>format</property>. 347 * 348 * <p> 349 * The extending format for the previously mentioned type. 350 * 351 * @return The property value, or <jk>null</jk> if it is not set. 352 */ 353 public String getBearerFormat() { 354 return bearerFormat; 355 } 356 357 /** 358 * Bean property setter: <property>format</property>. 359 * 360 * <p> 361 * The extending format for the previously mentioned type. 362 * 363 * @param value The new value for this property. 364 * <br>Can be <jk>null</jk> to unset the property. 365 * @return This object 366 */ 367 public SecuritySchemeInfo setBearerFormat(String value) { 368 bearerFormat = value; 369 return this; 370 } 371 372 /** 373 * Bean property getter: <property>items</property>. 374 * 375 * <p> 376 * Describes the type of items in the array. 377 * 378 * @return The property value, or <jk>null</jk> if it is not set. 379 */ 380 public OAuthFlow getFlows() { 381 return flows; 382 } 383 384 /** 385 * Bean property setter: <property>items</property>. 386 * 387 * <p> 388 * Describes the type of items in the array. 389 * 390 * @param value 391 * The new value for this property. 392 * <br>Property value is required if <code>type</code> is <js>"array"</js>. 393 * <br>Can be <jk>null</jk> to unset the property. 394 * @return This object 395 */ 396 public SecuritySchemeInfo setFlows(OAuthFlow value) { 397 flows = value; 398 return this; 399 } 400 401 /** 402 * Bean property getter: <property>collectionFormat</property>. 403 * 404 * <p> 405 * Determines the format of the array if type array is used. 406 * 407 * @return The property value, or <jk>null</jk> if it is not set. 408 */ 409 public String getOpenIdConnectUrl() { 410 return openIdConnectUrl; 411 } 412 413 /** 414 * Bean property setter: <property>collectionFormat</property>. 415 * 416 * <p> 417 * Determines the format of the array if type array is used. 418 * 419 * @param value The new value for this property. 420 * <br>Can be <jk>null</jk> to unset the property. 421 * @return This object 422 */ 423 public SecuritySchemeInfo setOpenIdConnectUrl(String value) { 424 openIdConnectUrl = value; 425 return this; 426 } 427 428 @Override /* SwaggerElement */ 429 public <T> T get(String property, Class<T> type) { 430 assertArgNotNull("property", property); 431 return switch (property) { 432 case "name" -> toType(getName(), type); 433 case "in" -> toType(getIn(), type); 434 case "description" -> toType(getDescription(), type); 435 case "scheme" -> toType(getScheme(), type); 436 case "flows" -> toType(getFlows(), type); 437 case "bearerFormat" -> toType(getBearerFormat(), type); 438 case "openIdConnectUrl" -> toType(getOpenIdConnectUrl(), type); 439 case "type" -> toType(getType(), type); 440 default -> super.get(property, type); 441 }; 442 } 443 444 @Override /* SwaggerElement */ 445 public SecuritySchemeInfo set(String property, Object value) { 446 assertArgNotNull("property", property); 447 return switch (property) { 448 case "bearerFormat" -> setBearerFormat(Utils.s(value)); 449 case "description" -> setDescription(Utils.s(value)); 450 case "flows" -> setFlows(toType(value, OAuthFlow.class)); 451 case "in" -> setIn(Utils.s(value)); 452 case "name" -> setName(Utils.s(value)); 453 case "openIdConnectUrl" -> setOpenIdConnectUrl(Utils.s(value)); 454 case "scheme" -> setScheme(Utils.s(value)); 455 case "type" -> setType(Utils.s(value)); 456 default -> { 457 super.set(property, value); 458 yield this; 459 } 460 }; 461 } 462 463 @Override /* SwaggerElement */ 464 public Set<String> keySet() { 465 var s = setBuilder(String.class) 466 .addIf(bearerFormat != null, "bearerFormat") 467 .addIf(description != null, "description") 468 .addIf(flows != null, "flows") 469 .addIf(in != null, "in") 470 .addIf(name != null, "name") 471 .addIf(openIdConnectUrl != null, "openIdConnectUrl") 472 .addIf(scheme != null, "scheme") 473 .addIf(type != null, "type") 474 .build(); 475 return new MultiSet<>(s, super.keySet()); 476 } 477}