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