Skip to content

Commit 60d6605

Browse files
[quarkus2] Added tests for token propagation (#436)
* Added tests for token propagation (#433) * Added tests for token propagation Signed-off-by: Helber Belmiro <[email protected]> --------- Signed-off-by: Helber Belmiro <[email protected]> * Replaced jakarta with javax --------- Signed-off-by: Helber Belmiro <[email protected]> Co-authored-by: Helber Belmiro <[email protected]>
1 parent e461b08 commit 60d6605

File tree

11 files changed

+424
-0
lines changed

11 files changed

+424
-0
lines changed

integration-tests/security/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
<artifactId>wiremock-jre8</artifactId>
2727
<scope>test</scope>
2828
</dependency>
29+
<dependency>
30+
<groupId>io.rest-assured</groupId>
31+
<artifactId>rest-assured</artifactId>
32+
<scope>test</scope>
33+
</dependency>
2934
</dependencies>
3035

3136
<build>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package io.quarkiverse.openapi.generator.it.security;
2+
3+
import javax.ws.rs.POST;
4+
import javax.ws.rs.Path;
5+
6+
import org.eclipse.microprofile.rest.client.inject.RestClient;
7+
8+
@Path("/token_propagation")
9+
public class TokenPropagationResource {
10+
11+
@RestClient
12+
org.acme.externalservice1.api.DefaultApi defaultApi1;
13+
14+
@RestClient
15+
org.acme.externalservice2.api.DefaultApi defaultApi2;
16+
17+
@RestClient
18+
org.acme.externalservice3.api.DefaultApi defaultApi3;
19+
20+
@RestClient
21+
org.acme.externalservice4.api.DefaultApi defaultApi4;
22+
23+
@RestClient
24+
org.acme.externalservice5.api.DefaultApi defaultApi5;
25+
26+
@POST
27+
@Path("service1")
28+
public String service1() {
29+
defaultApi1.executeQuery1();
30+
return "hello";
31+
}
32+
33+
@POST
34+
@Path("service2")
35+
public String service2() {
36+
defaultApi2.executeQuery2();
37+
return "hello";
38+
}
39+
40+
@POST
41+
@Path("service3")
42+
public String service3() {
43+
defaultApi3.executeQuery3();
44+
return "hello";
45+
}
46+
47+
@POST
48+
@Path("service4")
49+
public String service4() {
50+
defaultApi4.executeQuery4();
51+
return "hello";
52+
}
53+
54+
@POST
55+
@Path("service5")
56+
public String service5() {
57+
defaultApi5.executeQuery5();
58+
return "hello";
59+
}
60+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: token-propagation-external-service1 API
5+
version: 2.0.0-SNAPSHOT
6+
paths:
7+
/token-propagation-external-service1/executeQuery1:
8+
post:
9+
operationId: executeQuery1
10+
responses:
11+
"200":
12+
description: OK
13+
security:
14+
- service1-http-bearer: []
15+
components:
16+
securitySchemes:
17+
service1-http-bearer:
18+
type: http
19+
scheme: bearer
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: external-service2 API
5+
version: 2.0.0-SNAPSHOT
6+
paths:
7+
/token-propagation-external-service2/executeQuery2:
8+
post:
9+
operationId: executeQuery2
10+
responses:
11+
"200":
12+
description: OK
13+
security:
14+
- service2-oauth2: []
15+
components:
16+
securitySchemes:
17+
service2-oauth2:
18+
type: oauth2
19+
flows:
20+
clientCredentials:
21+
authorizationUrl: https://example.com/oauth
22+
tokenUrl: https://example.com/oauth/token
23+
scopes: {}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: token-propagation-external-service3 API
5+
version: 2.0.0-SNAPSHOT
6+
paths:
7+
/token-propagation-external-service3/executeQuery3:
8+
post:
9+
operationId: executeQuery3
10+
responses:
11+
"200":
12+
description: OK
13+
security:
14+
- service3-http-bearer: []
15+
components:
16+
securitySchemes:
17+
service3-http-bearer:
18+
type: http
19+
scheme: bearer
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: external-service4 API
5+
version: 2.0.0-SNAPSHOT
6+
paths:
7+
/token-propagation-external-service4/executeQuery4:
8+
post:
9+
operationId: executeQuery4
10+
responses:
11+
"200":
12+
description: OK
13+
security:
14+
- service4-oauth2: []
15+
components:
16+
securitySchemes:
17+
service4-oauth2:
18+
type: oauth2
19+
flows:
20+
clientCredentials:
21+
authorizationUrl: https://example.com/oauth
22+
tokenUrl: https://example.com/oauth/token
23+
scopes: {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
openapi: 3.0.3
3+
info:
4+
title: external-service5 API
5+
version: 2.0.0-SNAPSHOT
6+
paths:
7+
/token-propagation-external-service5/executeQuery5:
8+
post:
9+
operationId: executeQuery5
10+
responses:
11+
"200":
12+
description: OK
13+
security:
14+
- service5-oauth2: []
15+
components:
16+
securitySchemes:
17+
service5-oauth2:
18+
type: oauth2
19+
flows:
20+
clientCredentials:
21+
authorizationUrl: https://example.com/oauth
22+
tokenUrl: https://example.com/oauth/token
23+
scopes: {}

integration-tests/security/src/main/resources/application.properties

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,55 @@ quarkus.openapi-generator.open_weather_no_security_yaml.auth.app_id.api-key=1234
2424
# KOGITO-6458 (https://issues.redhat.com/browse/KOGITO-6458) - generate auth bindings even if security definition is missing
2525
# Note: The property value is the name of an existing securityScheme in the spec file
2626
quarkus.openapi-generator.codegen.default.security.scheme=app_id
27+
28+
#Token propagation
29+
quarkus.openapi-generator.codegen.spec.token_propagation_external_service1_yaml.base-package=org.acme.externalservice1
30+
quarkus.openapi-generator.codegen.spec.token_propagation_external_service2_yaml.base-package=org.acme.externalservice2
31+
quarkus.openapi-generator.codegen.spec.token_propagation_external_service3_yaml.base-package=org.acme.externalservice3
32+
quarkus.openapi-generator.codegen.spec.token_propagation_external_service4_yaml.base-package=org.acme.externalservice4
33+
quarkus.openapi-generator.codegen.spec.token_propagation_external_service5_yaml.base-package=org.acme.externalservice5
34+
35+
quarkus.rest-client.token_propagation_external_service1_yaml.url=${propagation-external-service-mock.url}
36+
quarkus.rest-client.token_propagation_external_service2_yaml.url=${propagation-external-service-mock.url}
37+
quarkus.rest-client.token_propagation_external_service3_yaml.url=${propagation-external-service-mock.url}
38+
quarkus.rest-client.token_propagation_external_service4_yaml.url=${propagation-external-service-mock.url}
39+
quarkus.rest-client.token_propagation_external_service5_yaml.url=${propagation-external-service-mock.url}
40+
41+
# default propagation for token_propagation_external_service1 invocation
42+
quarkus.openapi-generator.token_propagation_external_service1_yaml.auth.service1_http_bearer.token-propagation=true
43+
# default propagation for token_propagation_external_service2 invocation
44+
quarkus.openapi-generator.token_propagation_external_service2_yaml.auth.service2_oauth2.token-propagation=true
45+
# propagate the token coming in the header SERVICE3_HEADER_TO_PROPAGATE for token_propagation_external_service3 invocation
46+
quarkus.openapi-generator.token_propagation_external_service3_yaml.auth.service3_http_bearer.token-propagation=true
47+
quarkus.openapi-generator.token_propagation_external_service3_yaml.auth.service3_http_bearer.header-name=SERVICE3_HEADER_TO_PROPAGATE
48+
# propagate the token coming in the header SERVICE4_HEADER_TO_PROPAGATE for token_propagation_external_service4 invocation
49+
quarkus.openapi-generator.token_propagation_external_service4_yaml.auth.service4_oauth2.token-propagation=true
50+
quarkus.openapi-generator.token_propagation_external_service4_yaml.auth.service4_oauth2.header-name=SERVICE4_HEADER_TO_PROPAGATE
51+
52+
# Oidc clients for the services that has oauth2 security.
53+
# Oidc client used by the token_propagation_external_service2
54+
quarkus.oidc-client.service2_oauth2.auth-server-url=${keycloak.mock.service.url}
55+
quarkus.oidc-client.service2_oauth2.token-path=${keycloak.mock.service.token-path}
56+
quarkus.oidc-client.service2_oauth2.discovery-enabled=false
57+
quarkus.oidc-client.service2_oauth2.client-id=kogito-app
58+
quarkus.oidc-client.service2_oauth2.grant.type=client
59+
quarkus.oidc-client.service2_oauth2.credentials.client-secret.method=basic
60+
quarkus.oidc-client.service2_oauth2.credentials.client-secret.value=secret
61+
62+
# Oidc client used by the token_propagation_external_service4
63+
quarkus.oidc-client.service4_oauth2.auth-server-url=${keycloak.mock.service.url}
64+
quarkus.oidc-client.service4_oauth2.token-path=${keycloak.mock.service.token-path}
65+
quarkus.oidc-client.service4_oauth2.discovery-enabled=false
66+
quarkus.oidc-client.service4_oauth2.client-id=kogito-app
67+
quarkus.oidc-client.service4_oauth2.grant.type=client
68+
quarkus.oidc-client.service4_oauth2.credentials.client-secret.method=basic
69+
quarkus.oidc-client.service4_oauth2.credentials.client-secret.value=secret
70+
71+
# Oidc client used by the token_propagation_external_service5
72+
quarkus.oidc-client.service5_oauth2.auth-server-url=${keycloak.mock.service.url}
73+
quarkus.oidc-client.service5_oauth2.token-path=${keycloak.mock.service.token-path}
74+
quarkus.oidc-client.service5_oauth2.discovery-enabled=false
75+
quarkus.oidc-client.service5_oauth2.client-id=kogito-app
76+
quarkus.oidc-client.service5_oauth2.grant.type=client
77+
quarkus.oidc-client.service5_oauth2.credentials.client-secret.method=basic
78+
quarkus.oidc-client.service5_oauth2.credentials.client-secret.value=secret
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package io.quarkiverse.openapi.generator.it.security;
2+
3+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4+
import static com.github.tomakehurst.wiremock.client.WireMock.configureFor;
5+
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
6+
import static com.github.tomakehurst.wiremock.client.WireMock.post;
7+
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
8+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
9+
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
10+
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
11+
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
12+
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
16+
import com.github.tomakehurst.wiremock.WireMockServer;
17+
18+
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
19+
20+
/**
21+
* Lightweight Keycloak mock to use when an OidcClient is required, and we don't want/need to start a full Keycloak
22+
* container as part of the tests, etc. Keep the things simple.
23+
*/
24+
public class KeycloakServiceMock implements QuarkusTestResourceLifecycleManager {
25+
26+
public static final String KEY_CLOAK_SERVICE_URL = "keycloak.mock.service.url";
27+
public static final String KEY_CLOAK_SERVICE_TOKEN_PATH = "keycloak.mock.service.token-path";
28+
public static final String REALM = "kogito-tests";
29+
public static final String KEY_CLOAK_SERVICE_TOKEN_PATH_VALUE = "/realms/" + REALM + "/protocol/openid-connect/token";
30+
public static final String CLIENT_ID = "kogito-app";
31+
public static final String SECRET = "secret";
32+
public static final String KEYCLOAK_ACCESS_TOKEN = "KEYCLOAK_ACCESS_TOKEN";
33+
public static final String KEYCLOAK_REFRESH_TOKEN = "KEYCLOAK_REFRESH_TOKEN";
34+
public static final String KEYCLOAK_SESSION_STATE = "KEYCLOAK_SESSION_STATE";
35+
36+
public static final String AUTH_REQUEST_BODY = "grant_type=client_credentials";
37+
38+
private WireMockServer wireMockServer;
39+
40+
@Override
41+
public Map<String, String> start() {
42+
wireMockServer = new WireMockServer(options().dynamicPort());
43+
wireMockServer.start();
44+
configureFor(wireMockServer.port());
45+
46+
stubFor(post(KEY_CLOAK_SERVICE_TOKEN_PATH_VALUE)
47+
.withHeader(CONTENT_TYPE, equalTo(APPLICATION_FORM_URLENCODED))
48+
.withBasicAuth(CLIENT_ID, SECRET)
49+
.withRequestBody(equalTo(AUTH_REQUEST_BODY))
50+
.willReturn(aResponse()
51+
.withHeader(CONTENT_TYPE, APPLICATION_JSON)
52+
.withBody(getTokenResult())));
53+
54+
Map<String, String> properties = new HashMap<>();
55+
properties.put(KEY_CLOAK_SERVICE_URL, wireMockServer.baseUrl());
56+
properties.put(KEY_CLOAK_SERVICE_TOKEN_PATH, KEY_CLOAK_SERVICE_TOKEN_PATH_VALUE);
57+
return properties;
58+
}
59+
60+
private static String getTokenResult() {
61+
return "{\n" +
62+
" \"access_token\": \"" + KEYCLOAK_ACCESS_TOKEN + "\",\n" +
63+
" \"expires_in\": 300,\n" +
64+
" \"refresh_expires_in\": 1800,\n" +
65+
" \"refresh_token\": \"" + KEYCLOAK_REFRESH_TOKEN + "\",\n" +
66+
" \"token_type\": \"bearer\",\n" +
67+
" \"not-before-policy\": 0,\n" +
68+
" \"session_state\": \"" + KEYCLOAK_SESSION_STATE + "\",\n" +
69+
" \"scope\": \"email profile\"\n" +
70+
"}";
71+
}
72+
73+
@Override
74+
public void stop() {
75+
if (wireMockServer != null) {
76+
wireMockServer.stop();
77+
}
78+
}
79+
}

0 commit comments

Comments
 (0)