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