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.swagger; 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.CollectionUtils.copyOf; 023import static org.apache.juneau.internal.ConverterUtils.*; 024 025import java.util.*; 026 027import org.apache.juneau.*; 028import org.apache.juneau.common.utils.*; 029import org.apache.juneau.internal.*; 030import org.apache.juneau.marshaller.*; 031 032/** 033 * Allows the definition of a security scheme that can be used by the operations. 034 * 035 * <p> 036 * The Security Scheme Object defines a security scheme that can be used by the operations in Swagger 2.0. 037 * Supported schemes are basic authentication, an API key (either as a header or as a query parameter) and OAuth2's 038 * common flows (implicit, password, application and access code). 039 * 040 * <h5 class='section'>Swagger Specification:</h5> 041 * <p> 042 * The Security Scheme Object is composed of the following fields: 043 * <ul class='spaced-list'> 044 * <li><c>type</c> (string, REQUIRED) - The type of the security scheme. Values: <js>"basic"</js>, <js>"apiKey"</js>, <js>"oauth2"</js> 045 * <li><c>description</c> (string) - A short description for security scheme 046 * <li><c>name</c> (string) - The name of the header or query parameter to be used (for <js>"apiKey"</js> type) 047 * <li><c>in</c> (string) - The location of the API key (for <js>"apiKey"</js> type). Values: <js>"query"</js>, <js>"header"</js> 048 * <li><c>flow</c> (string) - The flow used by the OAuth2 security scheme (for <js>"oauth2"</js> type). Values: <js>"implicit"</js>, <js>"password"</js>, <js>"application"</js>, <js>"accessCode"</js> 049 * <li><c>authorizationUrl</c> (string) - The authorization URL to be used for this flow (for <js>"oauth2"</js> type) 050 * <li><c>tokenUrl</c> (string) - The token URL to be used for this flow (for <js>"oauth2"</js> type) 051 * <li><c>scopes</c> (map of string) - The available scopes for the OAuth2 security scheme (for <js>"oauth2"</js> type) 052 * </ul> 053 * 054 * <h5 class='section'>Example:</h5> 055 * <p class='bjson'> 056 * <jc>// Basic authentication sample</jc> 057 * { 058 * <js>"type"</js>: <js>"basic"</js> 059 * } 060 * 061 * <jc>// API key sample</jc> 062 * { 063 * <js>"type"</js>: <js>"apiKey"</js>, 064 * <js>"name"</js>: <js>"api_key"</js>, 065 * <js>"in"</js>: <js>"header"</js> 066 * } 067 * 068 * <jc>// Implicit OAuth2 sample</jc> 069 * { 070 * <js>"type"</js>: <js>"oauth2"</js>, 071 * <js>"authorizationUrl"</js>: <js>"http://swagger.io/api/oauth/dialog"</js>, 072 * <js>"flow"</js>: <js>"implicit"</js>, 073 * <js>"scopes"</js>: { 074 * <js>"write:pets"</js>: <js>"modify pets in your account"</js>, 075 * <js>"read:pets"</js>: <js>"read your pets"</js> 076 * } 077 * } 078 * </p> 079 * 080 * <h5 class='section'>See Also:</h5><ul> 081 * <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/#security-scheme-object">Swagger 2.0 Specification > Security Scheme Object</a> 082 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/authentication/">Swagger Authentication</a> 083 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a> 084 * </ul> 085 */ 086public class SecurityScheme extends SwaggerElement { 087 088 private static final String[] VALID_TYPES = {"basic", "apiKey", "oauth2"}; 089 090 private String 091 type, 092 description, 093 name, 094 in, 095 flow, 096 authorizationUrl, 097 tokenUrl; 098 private Map<String,String> scopes; 099 100 /** 101 * Default constructor. 102 */ 103 public SecurityScheme() {} 104 105 /** 106 * Copy constructor. 107 * 108 * @param copyFrom The object to copy. 109 */ 110 public SecurityScheme(SecurityScheme copyFrom) { 111 super(copyFrom); 112 113 this.authorizationUrl = copyFrom.authorizationUrl; 114 this.description = copyFrom.description; 115 this.flow = copyFrom.flow; 116 this.in = copyFrom.in; 117 this.name = copyFrom.name; 118 this.scopes = copyOf(copyFrom.scopes); 119 this.tokenUrl = copyFrom.tokenUrl; 120 this.type = copyFrom.type; 121 } 122 123 /** 124 * Make a deep copy of this object. 125 * 126 * @return A deep copy of this object. 127 */ 128 public SecurityScheme copy() { 129 return new SecurityScheme(this); 130 } 131 132 @Override /* Overridden from SwaggerElement */ 133 public SecurityScheme strict() { 134 super.strict(); 135 return this; 136 } 137 138 /** 139 * Sets strict mode on this bean. 140 * 141 * @param value 142 * The new value for this property. 143 * <br>Non-boolean values will be converted to boolean using <code>Boolean.<jsm>valueOf</jsm>(value.toString())</code>. 144 * <br>Can be <jk>null</jk> (interpreted as <jk>false</jk>). 145 * @return This object. 146 */ 147 @Override 148 public SecurityScheme strict(Object value) { 149 super.strict(value); 150 return this; 151 } 152 153 //----------------------------------------------------------------------------------------------------------------- 154 // Properties 155 //----------------------------------------------------------------------------------------------------------------- 156 157 /** 158 * Bean property getter: <property>authorizationUrl</property>. 159 * 160 * <p> 161 * The authorization URL to be used for this flow. 162 * 163 * @return The property value, or <jk>null</jk> if it is not set. 164 */ 165 public String getAuthorizationUrl() { 166 return authorizationUrl; 167 } 168 169 /** 170 * Bean property setter: <property>authorizationUrl</property>. 171 * 172 * <p> 173 * The authorization URL to be used for this flow. 174 * 175 * @param value 176 * The new value for this property. 177 * <br>This SHOULD be in the form of a URL. 178 * <br>Can be <jk>null</jk> to unset the property. 179 * @return This object. 180 */ 181 public SecurityScheme setAuthorizationUrl(String value) { 182 authorizationUrl = value; 183 return this; 184 } 185 186 /** 187 * Bean property getter: <property>description</property>. 188 * 189 * <p> 190 * A short description for security scheme. 191 * 192 * @return The property value, or <jk>null</jk> if it is not set. 193 */ 194 public String getDescription() { 195 return description; 196 } 197 198 /** 199 * Bean property setter: <property>description</property>. 200 * 201 * <p> 202 * A short description for security scheme. 203 * 204 * @param value 205 * The new value for this property. 206 * <br>Can be <jk>null</jk> to unset the property. 207 * @return This object. 208 */ 209 public SecurityScheme setDescription(String value) { 210 description = value; 211 return this; 212 } 213 214 /** 215 * Bean property getter: <property>flow</property>. 216 * 217 * <p> 218 * The flow used by the OAuth2 security scheme. 219 * 220 * @return The property value, or <jk>null</jk> if it is not set. 221 */ 222 public String getFlow() { 223 return flow; 224 } 225 226 /** 227 * Bean property setter: <property>flow</property>. 228 * 229 * <p> 230 * The flow used by the OAuth2 security scheme. 231 * 232 * @param value 233 * The new value for this property. 234 * <br>Valid values: 235 * <ul> 236 * <li><js>"implicit"</js> 237 * <li><js>"password"</js> 238 * <li><js>"application"</js> 239 * <li><js>"accessCode"</js> 240 * </ul> 241 * <br>Can be <jk>null</jk> to unset the property. 242 * @return This object. 243 */ 244 public SecurityScheme setFlow(String value) { 245 flow = value; 246 return this; 247 } 248 249 /** 250 * Bean property getter: <property>in</property>. 251 * 252 * <p> 253 * The location of the API key. 254 * 255 * @return The property value, or <jk>null</jk> if it is not set. 256 */ 257 public String getIn() { 258 return in; 259 } 260 261 /** 262 * Bean property setter: <property>in</property>. 263 * 264 * <p> 265 * The location of the API key. 266 * 267 * @param value 268 * The new value for this property. 269 * <br>Valid values: 270 * <ul> 271 * <li><js>"query"</js> 272 * <li><js>"header"</js> 273 * </ul> 274 * <br>Can be <jk>null</jk> to unset the property. 275 * @return This object. 276 */ 277 public SecurityScheme setIn(String value) { 278 in = value; 279 return this; 280 } 281 282 /** 283 * Bean property getter: <property>name</property>. 284 * 285 * <p> 286 * The name of the header or query parameter to be used. 287 * 288 * @return The property value, or <jk>null</jk> if it is not set. 289 */ 290 public String getName() { 291 return name; 292 } 293 294 /** 295 * Bean property setter: <property>name</property>. 296 * 297 * <p> 298 * The name of the header or query parameter to be used. 299 * 300 * @param value 301 * The new value for this property. 302 * <br>Can be <jk>null</jk> to unset the property. 303 * @return This object. 304 */ 305 public SecurityScheme setName(String value) { 306 name = value; 307 return this; 308 } 309 310 /** 311 * Bean property getter: <property>scopes</property>. 312 * 313 * <p> 314 * The available scopes for the OAuth2 security scheme. 315 * 316 * @return The property value, or <jk>null</jk> if it is not set. 317 */ 318 public Map<String,String> getScopes() { 319 return scopes; 320 } 321 322 /** 323 * Bean property setter: <property>scopes</property>. 324 * 325 * <p> 326 * The available scopes for the OAuth2 security scheme. 327 * 328 * @param value 329 * The new value for this property. 330 * <br>Can be <jk>null</jk> to unset the property. 331 * @return This object. 332 */ 333 public SecurityScheme setScopes(Map<String,String> value) { 334 scopes = copyOf(value); 335 return this; 336 } 337 338 /** 339 * Bean property appender: <property>scopes</property>. 340 * 341 * <p> 342 * The available scopes for the OAuth2 security scheme. 343 * 344 * @param key The scope key. Must not be <jk>null</jk>. 345 * @param value The scope value. Must not be <jk>null</jk>. 346 * @return This object. 347 */ 348 public SecurityScheme addScope(String key, String value) { 349 assertArgNotNull("key", key); 350 assertArgNotNull("value", value); 351 scopes = mapBuilder(scopes).sparse().add(key, value).build(); 352 return this; 353 } 354 355 /** 356 * Bean property getter: <property>tokenUrl</property>. 357 * 358 * <p> 359 * The token URL to be used for this flow. 360 * 361 * @return The property value, or <jk>null</jk> if it is not set. 362 */ 363 public String getTokenUrl() { 364 return tokenUrl; 365 } 366 367 /** 368 * Bean property setter: <property>tokenUrl</property>. 369 * 370 * <p> 371 * The token URL to be used for this flow. 372 * 373 * @param value 374 * The new value for this property. 375 * <br>This SHOULD be in the form of a URL. 376 * <br>Can be <jk>null</jk> to unset the property. 377 * @return This object. 378 */ 379 public SecurityScheme setTokenUrl(String value) { 380 tokenUrl = value; 381 return this; 382 } 383 384 /** 385 * Bean property getter: <property>type</property>. 386 * 387 * <p> 388 * The type of the security scheme. 389 * 390 * @return The property value, or <jk>null</jk> if it is not set. 391 */ 392 public String getType() { 393 return type; 394 } 395 396 /** 397 * Bean property setter: <property>type</property>. 398 * 399 * <p> 400 * The type of the security scheme. 401 * 402 * @param value 403 * The new value for this property. 404 * <br>Valid values: 405 * <ul> 406 * <li><js>"basic"</js> 407 * <li><js>"apiKey"</js> 408 * <li><js>"oauth2"</js> 409 * </ul> 410 * <br>Property value is required. 411 * <br>Can be <jk>null</jk> to unset the property. 412 * @return This object. 413 */ 414 public SecurityScheme setType(String value) { 415 if (isStrict() && ! contains(value, VALID_TYPES)) 416 throw new BasicRuntimeException( 417 "Invalid value passed in to setType(String). Value=''{0}'', valid values={1}", 418 value, Json5.of(VALID_TYPES) 419 ); 420 type = value; 421 return this; 422 } 423 424 @Override /* Overridden from SwaggerElement */ 425 public <T> T get(String property, Class<T> type) { 426 assertArgNotNull("property", property); 427 return switch (property) { 428 case "authorizationUrl" -> toType(getAuthorizationUrl(), type); 429 case "description" -> toType(getDescription(), type); 430 case "flow" -> toType(getFlow(), type); 431 case "in" -> toType(getIn(), type); 432 case "name" -> toType(getName(), type); 433 case "scopes" -> toType(getScopes(), type); 434 case "tokenUrl" -> toType(getTokenUrl(), type); 435 case "type" -> toType(getType(), type); 436 default -> super.get(property, type); 437 }; 438 } 439 440 @Override /* Overridden from SwaggerElement */ 441 public SecurityScheme set(String property, Object value) { 442 assertArgNotNull("property", property); 443 return switch (property) { 444 case "authorizationUrl" -> setAuthorizationUrl(Utils.s(value)); 445 case "description" -> setDescription(Utils.s(value)); 446 case "flow" -> setFlow(Utils.s(value)); 447 case "in" -> setIn(Utils.s(value)); 448 case "name" -> setName(Utils.s(value)); 449 case "scopes" -> setScopes(mapBuilder(String.class,String.class).sparse().addAny(value).build()); 450 case "tokenUrl" -> setTokenUrl(Utils.s(value)); 451 case "type" -> setType(Utils.s(value)); 452 default -> { 453 super.set(property, value); 454 yield this; 455 } 456 }; 457 } 458 459 @Override /* Overridden from SwaggerElement */ 460 public Set<String> keySet() { 461 var s = setBuilder(String.class) 462 .addIf(authorizationUrl != null, "authorizationUrl") 463 .addIf(description != null, "description") 464 .addIf(flow != null, "flow") 465 .addIf(in != null, "in") 466 .addIf(name != null, "name") 467 .addIf(scopes != null, "scopes") 468 .addIf(tokenUrl != null, "tokenUrl") 469 .addIf(type != null, "type") 470 .build(); 471 return new MultiSet<>(s, super.keySet()); 472 } 473 474}