Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public class CodegenOperation {
hasVersionHeaders = false, hasVersionQueryParams = false,
isResponseBinary = false, isResponseFile = false, isResponseOptional = false, hasReference = false, defaultReturnType = false,
isDeprecated, isCallbackRequest, uniqueItems,
hasErrorResponseObject; // if 4xx, 5xx responses have at least one error object defined
hasErrorResponseObject, // if 4xx, 5xx responses have at least one error object defined
allowsAnonymous = false; // if the operation allows anonymous access (empty security requirement)
public CodegenProperty returnProperty;
public String path, operationId, returnType, returnFormat, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
Expand Down Expand Up @@ -403,6 +404,7 @@ public String toString() {
final StringBuffer sb = new StringBuffer("CodegenOperation{");
sb.append("responseHeaders=").append(responseHeaders);
sb.append(", hasAuthMethods=").append(hasAuthMethods);
sb.append(", allowsAnonymous=").append(allowsAnonymous);
sb.append(", hasConsumes=").append(hasConsumes);
sb.append(", hasProduces=").append(hasProduces);
sb.append(", hasOptionalParams=").append(hasOptionalParams);
Expand Down Expand Up @@ -475,6 +477,7 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
CodegenOperation that = (CodegenOperation) o;
return hasAuthMethods == that.hasAuthMethods &&
allowsAnonymous == that.allowsAnonymous &&
hasConsumes == that.hasConsumes &&
hasProduces == that.hasProduces &&
hasOptionalParams == that.hasOptionalParams &&
Expand Down Expand Up @@ -543,7 +546,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {

return Objects.hash(responseHeaders, hasAuthMethods, hasConsumes, hasProduces, hasOptionalParams,
return Objects.hash(responseHeaders, hasAuthMethods, allowsAnonymous, hasConsumes, hasProduces, hasOptionalParams,
returnTypeIsPrimitive, returnSimpleType, subresourceOperation, isMap,
isArray, isMultipart, isVoid, isResponseBinary, isResponseFile, isResponseOptional, hasReference,
isDeprecated, isCallbackRequest, uniqueItems, path, operationId, returnType, httpMethod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1579,6 +1579,19 @@ private void processOperation(String resourcePath, String httpMethod, Operation
continue;
}

// Check if anonymous access is allowed (empty SecurityRequirement means anonymous is allowed)
// This must be checked before processing auth methods to properly handle mixed security requirements
boolean allowsAnonymous = checkAllowsAnonymous(securities);
if (!allowsAnonymous && securities == null) {
// If no operation-level securities, check global securities
allowsAnonymous = checkAllowsAnonymous(globalSecurities);
}
// If no securities at all (neither operation nor global), anonymous is allowed by default
if (!allowsAnonymous && securities == null && (globalSecurities == null || globalSecurities.isEmpty())) {
allowsAnonymous = true;
}
codegenOperation.allowsAnonymous = allowsAnonymous;

Map<String, SecurityScheme> authMethods = getAuthMethods(securities, securitySchemes);

if (authMethods != null && !authMethods.isEmpty()) {
Expand Down Expand Up @@ -1788,6 +1801,25 @@ private ModelsMap processModels(CodegenConfig config, Map<String, Schema> defini
return objs;
}

/**
* Check if the security requirements allow anonymous access.
* An empty SecurityRequirement (empty map) indicates anonymous access is allowed.
*
* @param securities List of security requirements to check
* @return true if any security requirement is empty (allows anonymous), false otherwise
*/
private boolean checkAllowsAnonymous(List<SecurityRequirement> securities) {
if (securities == null || securities.isEmpty()) {
return false;
}
for (SecurityRequirement req : securities) {
if (req == null || req.isEmpty()) {
return true;
}
}
return false;
}

private Map<String, SecurityScheme> getAuthMethods(List<SecurityRequirement> securities, Map<String, SecurityScheme> securitySchemes) {
if (securities == null || (securitySchemes == null || securitySchemes.isEmpty())) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,23 @@ private void flattenContent(Content content, String name) {
if (schema == null) {
continue;
}
String schemaName = resolveModelName(schema.getTitle(), name); // name example: testPost_request
// Check if schema has a $ref pointing to a component schema
// If so, prefer the referenced schema name over operation-based naming
String schemaName;
if (schema.get$ref() != null) {
String refName = ModelUtils.getSimpleRef(schema.get$ref());
if (refName != null && openAPI.getComponents() != null &&
openAPI.getComponents().getSchemas() != null &&
openAPI.getComponents().getSchemas().containsKey(refName)) {
// Use the referenced schema name instead of operation-based name
schemaName = resolveModelName(schema.getTitle(), refName);
} else {
// Fallback to original behavior if ref doesn't point to a component schema
schemaName = resolveModelName(schema.getTitle(), name);
}
} else {
schemaName = resolveModelName(schema.getTitle(), name); // name example: testPost_request
}
// Recursively gather/make inline models within this schema if any
gatherInlineModels(schema, schemaName);
if (isModelNeeded(schema)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;{{#vendorExtensions}}{{#hasFormParams}}
const localVarFormParams = new {{^multipartFormData}}URLSearchParams(){{/multipartFormData}}{{#multipartFormData}}((configuration && configuration.formDataCtor) || FormData)(){{/multipartFormData}};{{/hasFormParams}}{{/vendorExtensions}}
const allowsAnonymous = {{allowsAnonymous}};

{{#authMethods}}
// authentication {{name}} required
Expand All @@ -76,23 +77,23 @@ export const {{classname}}AxiosParamCreator = function (configuration?: Configur
await setAWS4SignatureInterceptor(globalAxios, configuration)
{{/withAWSV4Signature}}
{{#isKeyInHeader}}
await setApiKeyToObject(localVarHeaderParameter, "{{keyParamName}}", configuration)
await setApiKeyToObject(localVarHeaderParameter, "{{keyParamName}}", configuration, allowsAnonymous)
{{/isKeyInHeader}}
{{#isKeyInQuery}}
await setApiKeyToObject(localVarQueryParameter, "{{keyParamName}}", configuration)
await setApiKeyToObject(localVarQueryParameter, "{{keyParamName}}", configuration, allowsAnonymous)
{{/isKeyInQuery}}
{{/isApiKey}}
{{#isBasicBasic}}
// http basic authentication required
setBasicAuthToObject(localVarRequestOptions, configuration)
setBasicAuthToObject(localVarRequestOptions, configuration, allowsAnonymous)
{{/isBasicBasic}}
{{#isBasicBearer}}
// http bearer authentication required
await setBearerAuthToObject(localVarHeaderParameter, configuration)
await setBearerAuthToObject(localVarHeaderParameter, configuration, allowsAnonymous)
{{/isBasicBearer}}
{{#isOAuth}}
// oauth required
await setOAuthToObject(localVarHeaderParameter, "{{name}}", [{{#scopes}}"{{{scope}}}"{{^-last}}, {{/-last}}{{/scopes}}], configuration)
await setOAuthToObject(localVarHeaderParameter, "{{name}}", [{{#scopes}}"{{{scope}}}"{{^-last}}, {{/-last}}{{/scopes}}], configuration, allowsAnonymous)
{{/isOAuth}}

{{/authMethods}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,70 @@ export const assertParamExists = function (functionName: string, paramName: stri
}
}

export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) {
export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration, allowsAnonymous?: boolean) {
if (configuration && configuration.apiKey) {
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
? await configuration.apiKey(keyParamName)
: await configuration.apiKey;
object[keyParamName] = localVarApiKeyValue;
try {
const localVarApiKeyValue = typeof configuration.apiKey === 'function'
? await configuration.apiKey(keyParamName)
: await configuration.apiKey;
if (localVarApiKeyValue) {
object[keyParamName] = localVarApiKeyValue;
}
} catch (error) {
if (!allowsAnonymous) {
throw error;
}
// If anonymous is allowed, silently ignore authentication failures
}
}
}

export const setBasicAuthToObject = function (object: any, configuration?: Configuration) {
export const setBasicAuthToObject = function (object: any, configuration?: Configuration, allowsAnonymous?: boolean) {
if (configuration && (configuration.username || configuration.password)) {
object["auth"] = { username: configuration.username, password: configuration.password };
try {
object["auth"] = { username: configuration.username, password: configuration.password };
} catch (error) {
if (!allowsAnonymous) {
throw error;
}
// If anonymous is allowed, silently ignore authentication failures
}
}
}

export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) {
export const setBearerAuthToObject = async function (object: any, configuration?: Configuration, allowsAnonymous?: boolean) {
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
object["Authorization"] = "Bearer " + accessToken;
try {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
if (accessToken) {
object["Authorization"] = "Bearer " + accessToken;
}
} catch (error) {
if (!allowsAnonymous) {
throw error;
}
// If anonymous is allowed, silently ignore authentication failures
}
}
}

export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) {
export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration, allowsAnonymous?: boolean) {
if (configuration && configuration.accessToken) {
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
? await configuration.accessToken(name, scopes)
: await configuration.accessToken;
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
try {
const localVarAccessTokenValue = typeof configuration.accessToken === 'function'
? await configuration.accessToken(name, scopes)
: await configuration.accessToken;
if (localVarAccessTokenValue) {
object["Authorization"] = "Bearer " + localVarAccessTokenValue;
}
} catch (error) {
if (!allowsAnonymous) {
throw error;
}
// If anonymous is allowed, silently ignore authentication failures
}
}
}

Expand Down
Loading