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