Skip to content

Commit 9b2aa6e

Browse files
committed
squash
1 parent ba67ed7 commit 9b2aa6e

21 files changed

Lines changed: 726 additions & 0 deletions

File tree

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaJAXRSSpecServerCodegen.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,13 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<Mo
367367
additionalProperties.put("hasResponseStatusAnnotations", true);
368368
}
369369
}
370+
if (QUARKUS_LIBRARY.equals(getLibrary())) {
371+
for (CodegenOperation op : objs.getOperations().getOperation()) {
372+
if (shouldAddAuthenticatedAnnotation(op)){
373+
op.vendorExtensions.put("x-quarkus-authenticated", true);
374+
}
375+
}
376+
}
370377
return objs;
371378
}
372379

@@ -391,4 +398,17 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
391398
}
392399
return result;
393400
}
401+
402+
protected boolean shouldAddAuthenticatedAnnotation(CodegenOperation op) {
403+
if (!op.hasAuthMethods) {
404+
return false;
405+
}
406+
return op.authMethods.stream().anyMatch(m ->
407+
(Boolean.TRUE.equals(m.isOAuth) && (m.scopes == null || m.scopes.isEmpty())) ||
408+
(Boolean.TRUE.equals(m.isOpenId) && (m.scopes == null || m.scopes.isEmpty())) ||
409+
Boolean.TRUE.equals(m.isBasicBasic) ||
410+
Boolean.TRUE.equals(m.isBasicBearer) ||
411+
Boolean.TRUE.equals(m.isApiKey)
412+
);
413+
}
394414
}

modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/apiInterface.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,7 @@
5353
{{#vendorExtensions.x-java-success-response-code}}
5454
@ResponseStatus({{{vendorExtensions.x-java-success-response-code}}})
5555
{{/vendorExtensions.x-java-success-response-code}}
56+
{{#vendorExtensions.x-quarkus-authenticated}}
57+
@io.quarkus.security.Authenticated
58+
{{/vendorExtensions.x-quarkus-authenticated}}
5659
{{#supportAsync}}{{>returnAsyncTypeInterface}}{{/supportAsync}}{{^supportAsync}}{{#returnJBossResponse}}{{>returnResponseTypeInterface}}{{/returnJBossResponse}}{{^returnJBossResponse}}{{#returnResponse}}Response{{/returnResponse}}{{^returnResponse}}{{>returnTypeInterface}}{{/returnResponse}}{{/returnJBossResponse}}{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}});

modules/openapi-generator/src/main/resources/JavaJaxRS/spec/libraries/quarkus/apiMethod.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
{{^vendorExtensions.x-java-is-response-void}}@org.eclipse.microprofile.openapi.annotations.media.Content(schema = @org.eclipse.microprofile.openapi.annotations.media.Schema(implementation = {{{baseType}}}.class{{#vendorExtensions.x-microprofile-open-api-return-schema-container}}, type = {{{.}}} {{/vendorExtensions.x-microprofile-open-api-return-schema-container}}{{#vendorExtensions.x-microprofile-open-api-return-unique-items}}, uniqueItems = true {{/vendorExtensions.x-microprofile-open-api-return-unique-items}})){{/vendorExtensions.x-java-is-response-void}}
4848
}){{^-last}},{{/-last}}{{/responses}}
4949
}){{/hasProduces}}{{/useMicroProfileOpenAPIAnnotations}}
50+
{{#vendorExtensions.x-quarkus-authenticated}}
51+
@io.quarkus.security.Authenticated
52+
{{/vendorExtensions.x-quarkus-authenticated}}
5053
public {{#supportAsync}}{{#useMutiny}}Uni{{/useMutiny}}{{^useMutiny}}CompletionStage{{/useMutiny}}<{{/supportAsync}}{{#returnJBossResponse}}{{>returnResponseTypeInterface}}{{/returnJBossResponse}}{{^returnJBossResponse}}Response{{/returnJBossResponse}}{{#supportAsync}}>{{/supportAsync}} {{nickname}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>cookieParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}},{{/-last}}{{/allParams}}) {
5154
return {{#supportAsync}}{{#useMutiny}}Uni.createFrom().item({{/useMutiny}}{{^useMutiny}}CompletableFuture.supplyAsync(() -> {{/useMutiny}}{{/supportAsync}}Response.ok().entity("magic!").build(){{#supportAsync}}){{/supportAsync}};
5255
}

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/jaxrs/JavaJAXRSSpecServerCodegenTest.java

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import org.openapitools.codegen.testutils.ConfigAssert;
1616
import org.testng.Assert;
1717
import org.testng.annotations.BeforeMethod;
18+
import org.testng.annotations.DataProvider;
19+
import org.testng.annotations.DataProvider;
1820
import org.testng.annotations.Test;
1921

2022
import java.io.File;
@@ -1586,4 +1588,198 @@ public void useQuarkusSecurityAnnotationsNotProcessedForNonQuarkusLibrary() {
15861588
// written back as a boolean — the key holds the raw Object we put in, not false
15871589
Assert.assertNotEquals(false, codegen.additionalProperties().get(USE_QUARKUS_SECURITY_ANNOTATIONS));
15881590
}
1591+
1592+
/**
1593+
* Parameterized test covering all @Authenticated annotation scenarios for Quarkus + OAuth2.
1594+
* Each row: (spec path, interfaceOnly, expected count of @io.quarkus.security.Authenticated).
1595+
*/
1596+
@DataProvider(name = "quarkusOAuth2AuthenticatedCases")
1597+
public Object[][] quarkusOAuth2AuthenticatedCases() {
1598+
return new Object[][] {
1599+
// single OAuth2 flow, no scopes → @Authenticated
1600+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-no-scopes.yaml", true, 1},
1601+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-no-scopes.yaml", false, 1},
1602+
// single OAuth2 flow, non-empty scopes → no @Authenticated
1603+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-with-scopes.yaml", true, 0},
1604+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-with-scopes.yaml", false, 0},
1605+
// multiple OAuth2 flows, all no scopes → @Authenticated exactly once (no per-flow duplication)
1606+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-multi-flow-no-scopes.yaml", true, 1},
1607+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-multi-flow-no-scopes.yaml", false, 1},
1608+
// OR: one scheme no-scope + one scheme scoped → one op gets @Authenticated, scoped-only op gets none
1609+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-or-empty-and-scoped.yaml", true, 1},
1610+
{"src/test/resources/3_0/jaxrs-spec/quarkus-oauth2-or-empty-and-scoped.yaml", false, 1},
1611+
};
1612+
}
1613+
1614+
@Test(dataProvider = "quarkusOAuth2AuthenticatedCases")
1615+
public void quarkusEmitsAuthenticatedAnnotationForOAuth2(String specPath, boolean interfaceOnly, int expectedCount) throws Exception {
1616+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1617+
output.deleteOnExit();
1618+
1619+
final OpenAPI openAPI = new OpenAPIParser()
1620+
.readLocation(specPath, null, new ParseOptions()).getOpenAPI();
1621+
1622+
codegen.setOutputDir(output.getAbsolutePath());
1623+
codegen.setLibrary(QUARKUS_LIBRARY);
1624+
codegen.additionalProperties().put(INTERFACE_ONLY, interfaceOnly);
1625+
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
1626+
1627+
final ClientOptInput input = new ClientOptInput()
1628+
.openAPI(openAPI)
1629+
.config(codegen);
1630+
1631+
final DefaultGenerator generator = new DefaultGenerator();
1632+
final List<File> files = generator.opts(input).generate();
1633+
1634+
validateJavaSourceFiles(files);
1635+
1636+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java");
1637+
final String content = Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java"));
1638+
Assert.assertEquals(TestUtils.countOccurrences(content, "@io\\.quarkus\\.security\\.Authenticated"), expectedCount);
1639+
}
1640+
1641+
/**
1642+
* Parameterized test covering all @Authenticated annotation scenarios for Quarkus + httpBasic.
1643+
* Each row: (interfaceOnly).
1644+
*/
1645+
@DataProvider(name = "quarkusHttpBasicCases")
1646+
public Object[][] quarkusHttpBasicCases() {
1647+
return new Object[][] {
1648+
{true}, // interface-only
1649+
{false}, // concrete stub
1650+
};
1651+
}
1652+
1653+
@Test(dataProvider = "quarkusHttpBasicCases")
1654+
public void quarkusEmitsAuthenticatedAnnotationForHttpBasic(boolean interfaceOnly) throws Exception {
1655+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1656+
output.deleteOnExit();
1657+
1658+
final OpenAPI openAPI = new OpenAPIParser()
1659+
.readLocation("src/test/resources/3_0/jaxrs-spec/quarkus-http-basic.yaml", null, new ParseOptions()).getOpenAPI();
1660+
1661+
codegen.setOutputDir(output.getAbsolutePath());
1662+
codegen.setLibrary(QUARKUS_LIBRARY);
1663+
codegen.additionalProperties().put(INTERFACE_ONLY, interfaceOnly);
1664+
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
1665+
1666+
final DefaultGenerator generator = new DefaultGenerator();
1667+
final List<File> files = generator.opts(new ClientOptInput().openAPI(openAPI).config(codegen)).generate();
1668+
1669+
validateJavaSourceFiles(files);
1670+
1671+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java");
1672+
final String content = Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java"));
1673+
Assert.assertEquals(TestUtils.countOccurrences(content, "@io\\.quarkus\\.security\\.Authenticated"), 1);
1674+
}
1675+
1676+
/**
1677+
* Parameterized test covering all @Authenticated annotation scenarios for Quarkus + http bearer.
1678+
* Each row: (interfaceOnly).
1679+
*/
1680+
@DataProvider(name = "quarkusHttpBearerCases")
1681+
public Object[][] quarkusHttpBearerCases() {
1682+
return new Object[][] {
1683+
{true},
1684+
{false},
1685+
};
1686+
}
1687+
1688+
@Test(dataProvider = "quarkusHttpBearerCases")
1689+
public void quarkusEmitsAuthenticatedAnnotationForHttpBearer(boolean interfaceOnly) throws Exception {
1690+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1691+
output.deleteOnExit();
1692+
1693+
final OpenAPI openAPI = new OpenAPIParser()
1694+
.readLocation("src/test/resources/3_0/jaxrs-spec/quarkus-http-bearer.yaml", null, new ParseOptions()).getOpenAPI();
1695+
1696+
codegen.setOutputDir(output.getAbsolutePath());
1697+
codegen.setLibrary(QUARKUS_LIBRARY);
1698+
codegen.additionalProperties().put(INTERFACE_ONLY, interfaceOnly);
1699+
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
1700+
1701+
final DefaultGenerator generator = new DefaultGenerator();
1702+
final List<File> files = generator.opts(new ClientOptInput().openAPI(openAPI).config(codegen)).generate();
1703+
1704+
validateJavaSourceFiles(files);
1705+
1706+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java");
1707+
final String content = Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java"));
1708+
Assert.assertEquals(TestUtils.countOccurrences(content, "@io\\.quarkus\\.security\\.Authenticated"), 1);
1709+
}
1710+
1711+
/**
1712+
* Parameterized test covering all @Authenticated annotation scenarios for Quarkus + api key.
1713+
* Each row: (interfaceOnly).
1714+
*/
1715+
@DataProvider(name = "quarkusApiKeyCases")
1716+
public Object[][] quarkusApiKeyCases() {
1717+
return new Object[][] {
1718+
{true},
1719+
{false},
1720+
};
1721+
}
1722+
1723+
@Test(dataProvider = "quarkusApiKeyCases")
1724+
public void quarkusEmitsAuthenticatedAnnotationForApiKey(boolean interfaceOnly) throws Exception {
1725+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1726+
output.deleteOnExit();
1727+
1728+
final OpenAPI openAPI = new OpenAPIParser()
1729+
.readLocation("src/test/resources/3_0/jaxrs-spec/quarkus-api-key.yaml", null, new ParseOptions()).getOpenAPI();
1730+
1731+
codegen.setOutputDir(output.getAbsolutePath());
1732+
codegen.setLibrary(QUARKUS_LIBRARY);
1733+
codegen.additionalProperties().put(INTERFACE_ONLY, interfaceOnly);
1734+
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
1735+
1736+
final DefaultGenerator generator = new DefaultGenerator();
1737+
final List<File> files = generator.opts(new ClientOptInput().openAPI(openAPI).config(codegen)).generate();
1738+
1739+
validateJavaSourceFiles(files);
1740+
1741+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java");
1742+
final String content = Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java"));
1743+
Assert.assertEquals(TestUtils.countOccurrences(content, "@io\\.quarkus\\.security\\.Authenticated"), 1);
1744+
}
1745+
1746+
/**
1747+
* Parameterized test for OpenID Connect: empty scopes → @Authenticated; explicit scopes → absent
1748+
* (explicit scopes will be handled by @RolesAllowed in a future PR).
1749+
* Each row: (spec path, interfaceOnly, expected occurrence count).
1750+
*/
1751+
@DataProvider(name = "quarkusOpenIdConnectCases")
1752+
public Object[][] quarkusOpenIdConnectCases() {
1753+
return new Object[][] {
1754+
// no scopes → @Authenticated
1755+
{"src/test/resources/3_0/jaxrs-spec/quarkus-openidconnect-no-scopes.yaml", true, 1},
1756+
{"src/test/resources/3_0/jaxrs-spec/quarkus-openidconnect-no-scopes.yaml", false, 1},
1757+
// explicit scopes → no @Authenticated
1758+
{"src/test/resources/3_0/jaxrs-spec/quarkus-openidconnect-with-scopes.yaml", true, 0},
1759+
{"src/test/resources/3_0/jaxrs-spec/quarkus-openidconnect-with-scopes.yaml", false, 0},
1760+
};
1761+
}
1762+
1763+
@Test(dataProvider = "quarkusOpenIdConnectCases")
1764+
public void quarkusEmitsAuthenticatedAnnotationForOpenIdConnect(String specPath, boolean interfaceOnly, int expectedCount) throws Exception {
1765+
final File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
1766+
output.deleteOnExit();
1767+
1768+
final OpenAPI openAPI = new OpenAPIParser()
1769+
.readLocation(specPath, null, new ParseOptions()).getOpenAPI();
1770+
1771+
codegen.setOutputDir(output.getAbsolutePath());
1772+
codegen.setLibrary(QUARKUS_LIBRARY);
1773+
codegen.additionalProperties().put(INTERFACE_ONLY, interfaceOnly);
1774+
codegen.additionalProperties().put(USE_JAKARTA_EE, true);
1775+
1776+
final DefaultGenerator generator = new DefaultGenerator();
1777+
final List<File> files = generator.opts(new ClientOptInput().openAPI(openAPI).config(codegen)).generate();
1778+
1779+
validateJavaSourceFiles(files);
1780+
1781+
TestUtils.ensureContainsFile(files, output, "src/gen/java/org/openapitools/api/ItemsApi.java");
1782+
final String content = Files.readString(output.toPath().resolve("src/gen/java/org/openapitools/api/ItemsApi.java"));
1783+
Assert.assertEquals(TestUtils.countOccurrences(content, "@io\\.quarkus\\.security\\.Authenticated"), expectedCount);
1784+
}
15891785
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Quarkus API Key auth test
4+
version: '1.0'
5+
servers:
6+
- url: 'http://localhost:8080/'
7+
paths:
8+
/items:
9+
get:
10+
operationId: getItems
11+
summary: Get items
12+
security:
13+
- api_key: []
14+
responses:
15+
'200':
16+
description: OK
17+
post:
18+
operationId: createItem
19+
summary: Create item
20+
responses:
21+
'201':
22+
description: Created
23+
components:
24+
securitySchemes:
25+
api_key:
26+
type: apiKey
27+
in: header
28+
name: X-API-Key
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Quarkus HTTP Basic auth test
4+
version: '1.0'
5+
servers:
6+
- url: 'http://localhost:8080/'
7+
paths:
8+
/items:
9+
get:
10+
operationId: getItems
11+
summary: Get items
12+
security:
13+
- basic_auth: []
14+
responses:
15+
'200':
16+
description: OK
17+
post:
18+
operationId: createItem
19+
summary: Create item
20+
responses:
21+
'201':
22+
description: Created
23+
components:
24+
securitySchemes:
25+
basic_auth:
26+
type: http
27+
scheme: basic
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Quarkus HTTP Bearer auth test
4+
version: '1.0'
5+
servers:
6+
- url: 'http://localhost:8080/'
7+
paths:
8+
/items:
9+
get:
10+
operationId: getItems
11+
summary: Get items
12+
security:
13+
- bearer_auth: []
14+
responses:
15+
'200':
16+
description: OK
17+
post:
18+
operationId: createItem
19+
summary: Create item
20+
responses:
21+
'201':
22+
description: Created
23+
components:
24+
securitySchemes:
25+
bearer_auth:
26+
type: http
27+
scheme: bearer
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Quarkus OAuth2 multi-flow no scopes test
4+
version: '1.0'
5+
servers:
6+
- url: 'http://localhost:8080/'
7+
paths:
8+
/items:
9+
get:
10+
operationId: getItems
11+
summary: Get items
12+
security:
13+
- oauth2_scheme: []
14+
responses:
15+
'200':
16+
description: OK
17+
post:
18+
operationId: createItem
19+
summary: Create item
20+
responses:
21+
'201':
22+
description: Created
23+
components:
24+
securitySchemes:
25+
oauth2_scheme:
26+
type: oauth2
27+
flows:
28+
authorizationCode:
29+
authorizationUrl: https://example.com/oauth/authorize
30+
tokenUrl: https://example.com/oauth/token
31+
scopes: {}
32+
implicit:
33+
authorizationUrl: https://example.com/api/oauth/dialog
34+
scopes: {}

0 commit comments

Comments
 (0)