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