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.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.*; 026 027/** 028 * Configuration details for a supported OAuth Flow. 029 * 030 * <p> 031 * The OAuthFlow Object provides configuration details for a supported OAuth Flow. This object contains the URLs and 032 * scopes needed to configure a specific OAuth 2.0 flow. Different flows require different combinations of URLs and 033 * have different security characteristics. 034 * 035 * <h5 class='section'>OpenAPI Specification:</h5> 036 * <p> 037 * The OAuthFlow Object is composed of the following fields: 038 * <ul class='spaced-list'> 039 * <li><c>authorizationUrl</c> (string) - The authorization URL to be used for this flow. This MUST be in the form of a URL 040 * <li><c>tokenUrl</c> (string) - The token URL to be used for this flow. This MUST be in the form of a URL 041 * <li><c>refreshUrl</c> (string) - The URL to be used for obtaining refresh tokens. This MUST be in the form of a URL 042 * <li><c>scopes</c> (map of strings) - The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it 043 * </ul> 044 * 045 * <h5 class='section'>Example:</h5> 046 * <p class='bcode'> 047 * <jc>// Construct using SwaggerBuilder.</jc> 048 * OAuthFlow <jv>x</jv> = <jsm>oauthFlow</jsm>() 049 * .setAuthorizationUrl(<js>"https://example.com/oauth/authorize"</js>) 050 * .setTokenUrl(<js>"https://example.com/oauth/token"</js>) 051 * .setScopes(<jsm>map</jsm>(<js>"read"</js>, <js>"Read access"</js>, <js>"write"</js>, <js>"Write access"</js>)); 052 * 053 * <jc>// Serialize using JsonSerializer.</jc> 054 * String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>x</jv>); 055 * 056 * <jc>// Or just use toString() which does the same as above.</jc> 057 * <jv>json</jv> = <jv>x</jv>.toString(); 058 * </p> 059 * <p class='bcode'> 060 * <jc>// Output</jc> 061 * { 062 * <js>"authorizationUrl"</js>: <js>"https://example.com/oauth/authorize"</js>, 063 * <js>"tokenUrl"</js>: <js>"https://example.com/oauth/token"</js>, 064 * <js>"scopes"</js>: { 065 * <js>"read"</js>: <js>"Read access"</js>, 066 * <js>"write"</js>: <js>"Write access"</js> 067 * } 068 * } 069 * </p> 070 * 071 * <h5 class='section'>See Also:</h5><ul> 072 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#oauth-flow-object">OpenAPI Specification > OAuth Flow Object</a> 073 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/authentication/oauth2/">OpenAPI OAuth2 Authentication</a> 074 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 075 * </ul> 076 */ 077@SuppressWarnings({ 078 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 079}) 080public class OAuthFlow extends OpenApiElement { 081 082 private String authorizationUrl; 083 private String tokenUrl; 084 private String refreshUrl; 085 private final Map<String,String> scopes = map(); 086 087 /** 088 * Default constructor. 089 */ 090 public OAuthFlow() {} 091 092 /** 093 * Copy constructor. 094 * 095 * @param copyFrom The object to copy. 096 */ 097 public OAuthFlow(OAuthFlow copyFrom) { 098 super(copyFrom); 099 100 this.authorizationUrl = copyFrom.authorizationUrl; 101 this.tokenUrl = copyFrom.tokenUrl; 102 this.refreshUrl = copyFrom.refreshUrl; 103 scopes.putAll(copyFrom.scopes); 104 } 105 106 /** 107 * Adds a single value to the <property>scopes</property> property. 108 * 109 * @param name The scope name. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 110 * @param description A short description for the scope. Must not be <jk>null</jk>, or an {@link IllegalArgumentException} is thrown. 111 * @return This object 112 */ 113 public OAuthFlow addScope(String name, String description) { 114 reqnn("name", name); 115 reqnn("description", description); 116 scopes.put(name, description); 117 return this; 118 } 119 120 /** 121 * Make a deep copy of this object. 122 * 123 * @return A deep copy of this object. 124 */ 125 public OAuthFlow copy() { 126 return new OAuthFlow(this); 127 } 128 129 @Override /* Overridden from OpenApiElement */ 130 public <T> T get(String property, Class<T> type) { 131 reqnn("property", property); 132 return switch (property) { 133 case "refreshUrl" -> toType(getRefreshUrl(), type); 134 case "tokenUrl" -> toType(getTokenUrl(), type); 135 case "authorizationUrl" -> toType(getAuthorizationUrl(), type); 136 case "scopes" -> toType(getScopes(), type); 137 default -> super.get(property, type); 138 }; 139 } 140 141 /** 142 * Bean property getter: <property>authorizationUrl</property>. 143 * 144 * <p> 145 * The authorization URL to be used for this flow. 146 * 147 * @return The property value, or <jk>null</jk> if it is not set. 148 */ 149 public String getAuthorizationUrl() { return authorizationUrl; } 150 151 /** 152 * Bean property getter: <property>refreshUrl</property>. 153 * 154 * <p> 155 * The URL to be used for obtaining refresh tokens. 156 * 157 * @return The property value, or <jk>null</jk> if it is not set. 158 */ 159 public String getRefreshUrl() { return refreshUrl; } 160 161 /** 162 * Bean property getter: <property>scopes</property>. 163 * 164 * <p> 165 * The available scopes for the OAuth2 security scheme. 166 * 167 * @return The property value, or <jk>null</jk> if it is not set. 168 */ 169 public Map<String,String> getScopes() { return nie(scopes); } 170 171 /** 172 * Bean property getter: <property>tokenUrl</property>. 173 * 174 * <p> 175 * The token URL to be used for this flow. 176 * 177 * @return The property value, or <jk>null</jk> if it is not set. 178 */ 179 public String getTokenUrl() { return tokenUrl; } 180 181 @Override /* Overridden from OpenApiElement */ 182 public Set<String> keySet() { 183 // @formatter:off 184 var s = stb(String.class) 185 .addIf(nn(authorizationUrl), "authorizationUrl") 186 .addIf(nn(refreshUrl), "refreshUrl") 187 .addIf(ine(scopes), "scopes") 188 .addIf(nn(tokenUrl), "tokenUrl") 189 .build(); 190 // @formatter:on 191 return new MultiSet<>(s, super.keySet()); 192 } 193 194 @Override /* Overridden from OpenApiElement */ 195 public OAuthFlow set(String property, Object value) { 196 reqnn("property", property); 197 return switch (property) { 198 case "authorizationUrl" -> setAuthorizationUrl(s(value)); 199 case "refreshUrl" -> setRefreshUrl(s(value)); 200 case "scopes" -> setScopes(toMapBuilder(value, String.class, String.class).sparse().build()); 201 case "tokenUrl" -> setTokenUrl(s(value)); 202 default -> { 203 super.set(property, value); 204 yield this; 205 } 206 }; 207 } 208 209 /** 210 * Bean property setter: <property>authorizationUrl</property>. 211 * 212 * <p> 213 * The authorization URL to be used for this flow. 214 * 215 * @param value 216 * The new value for this property. 217 * <br>Can be <jk>null</jk> to unset the property. 218 * @return This object 219 */ 220 public OAuthFlow setAuthorizationUrl(String value) { 221 authorizationUrl = value; 222 return this; 223 } 224 225 /** 226 * Bean property setter: <property>refreshUrl</property>. 227 * 228 * <p> 229 * The URL to be used for obtaining refresh tokens. 230 * 231 * @param value 232 * The new value for this property. 233 * <br>Can be <jk>null</jk> to unset the property. 234 * @return This object 235 */ 236 public OAuthFlow setRefreshUrl(String value) { 237 refreshUrl = value; 238 return this; 239 } 240 241 /** 242 * Bean property setter: <property>scopes</property>. 243 * 244 * <p> 245 * The available scopes for the OAuth2 security scheme. 246 * 247 * @param value 248 * The new value for this property. 249 * <br>Can be <jk>null</jk> to unset the property. 250 * @return This object 251 */ 252 public OAuthFlow setScopes(Map<String,String> value) { 253 scopes.clear(); 254 if (nn(value)) 255 scopes.putAll(value); 256 return this; 257 } 258 259 /** 260 * Bean property setter: <property>tokenUrl</property>. 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 OAuthFlow setTokenUrl(String value) { 267 tokenUrl = value; 268 return this; 269 } 270 271 @Override /* Overridden from OpenApiElement */ 272 public OAuthFlow strict() { 273 super.strict(); 274 return this; 275 } 276 277 @Override /* Overridden from OpenApiElement */ 278 public OAuthFlow strict(Object value) { 279 super.strict(value); 280 return this; 281 } 282}