Skip to content

Commit 6e19fa7

Browse files
committed
#1059 add unit and integration tests for RBAC checks using user-access details
1 parent 0b213f5 commit 6e19fa7

File tree

16 files changed

+705
-141
lines changed

16 files changed

+705
-141
lines changed

calm-hub/keycloak-dev/device-code-flow-v2.sh

Lines changed: 0 additions & 70 deletions
This file was deleted.

calm-hub/keycloak-dev/device-code-flow.sh

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/bin/bash
22

3-
CLIENT_ID="calm-hub-device-flow"
4-
SCOPE="architectures:all architectures:read"
3+
CLIENT_ID="calm-hub-admin-app"
4+
SCOPE="namespace:admin"
55
DEVICE_AUTH_ENDPOINT="https://localhost:9443/realms/calm-hub-realm/protocol/openid-connect/auth/device"
66
DEVICE_AUTH_RESPONSE=$(curl --insecure -X POST \
77
-H "Content-Type: application/x-www-form-urlencoded" \
@@ -54,11 +54,17 @@ poll_token() {
5454
#Start token polling
5555
poll_token
5656

57-
echo -e "\nPress enter to get patterns"
57+
echo -e "\nPress enter to create a sample user-access details associated to finos"
5858
read
5959
if [[ -n $ACCESS_TOKEN ]]; then
60-
curl --insecure -v "https://localhost:8443/calm/namespaces/finos/patterns" \
60+
curl -X POST --insecure -v "https://localhost:8443/calm/namespaces/finos/user-access" \
6161
-H "Content-Type: application/json" \
62-
-H "Authorization: Bearer $ACCESS_TOKEN"
62+
-H "Authorization: Bearer $ACCESS_TOKEN" \
63+
-d '{ "namespace": "finos", "resourceType": "namespaces", "permission": "read", "username": "demo" }'
64+
65+
echo -e "\nPress enter to get list of user-access details"
66+
read
67+
curl --insecure -v "https://localhost:8443/calm/namespaces/finos/user-access" \
68+
-H "Content-Type: application/json" \
69+
-H "Authorization: Bearer $ACCESS_TOKEN"
6370
fi
64-
#Reference: https://github.com/keycloak/keycloak-community/blob/main/design/oauth2-device-authorization-grant.md

calm-hub/keycloak-dev/device_code_flow_entraid.sh

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ DEVICE_AUTH_RESPONSE=$(curl -X POST \
1010
-d "client_id=$CLIENT_ID" -d "scope=$SCOPE" \
1111
$DEVICE_AUTH_ENDPOINT)
1212

13-
14-
#M467095uma
15-
1613
# Extract values from the device auth response.
1714
DEVICE_CODE=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.device_code')
1815
USER_CODE=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.user_code')

calm-hub/mongo/init-mongo.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ if (db.counters.countDocuments({ _id: "flowStoreCounter" }) === 1) {
4545
if (db.counters.countDocuments({ _id: "userAccessStoreCounter" }) === 1) {
4646
db.counters.insertOne({
4747
_id: "userAccessStoreCounter",
48-
sequence_value: 1
48+
sequence_value: 4
4949
});
50-
print("Initialized userAccessStoreCounter with sequence_value 1");
50+
print("Initialized userAccessStoreCounter with sequence_value 4");
5151
} else {
5252
print("userAccessStoreCounter already exists, no initialization needed");
5353
}
@@ -2672,21 +2672,21 @@ db.architectures.insertMany([
26722672

26732673
db.userAccess.insertMany([
26742674
{
2675-
"id": NumberInt(1),
2675+
"userAccessId": NumberInt(1),
26762676
"username": "demo_admin",
26772677
"permission": "write",
26782678
"namespace": "finos",
26792679
"resourceType": "all"
26802680
},
26812681
{
2682-
"id": NumberInt(2),
2682+
"userAccessId": NumberInt(2),
26832683
"username": "demo_admin",
26842684
"permission": "write",
26852685
"namespace": "workshop",
26862686
"resourceType": "patterns"
26872687
},
26882688
{
2689-
"id": NumberInt(3),
2689+
"userAccessId": NumberInt(3),
26902690
"username": "demo_admin",
26912691
"permission": "write",
26922692
"namespace": "traderx",

calm-hub/src/integration-test/java/integration/MongoSetup.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,11 @@ public static void counterSetup(MongoDatabase database) {
3737
Document patternStoreCounter = new Document("_id", "patternStoreCounter").append("sequence_value", 0);
3838
Document architectureStoreCounter = new Document("_id", "architectureStoreCounter").append("sequence_value", 0);
3939
Document adrStoreCounter = new Document("_id", "adrStoreCounter").append("sequence_value", 0);
40+
Document userAccessStoreCounter = new Document("_id", "userAccessStoreCounter").append("sequence_value", 0);
4041
database.getCollection("counters").insertOne(patternStoreCounter);
4142
database.getCollection("counters").insertOne(architectureStoreCounter);
4243
database.getCollection("counters").insertOne(adrStoreCounter);
44+
database.getCollection("counters").insertOne(userAccessStoreCounter);
4345
}
4446
}
4547
}

calm-hub/src/integration-test/java/integration/PermittedScopesIntegration.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import io.quarkus.test.junit.TestProfile;
88
import org.bson.Document;
99
import org.eclipse.microprofile.config.ConfigProvider;
10+
import org.finos.calm.domain.UserAccess;
1011
import org.finos.calm.security.CalmHubScopes;
1112
import org.junit.jupiter.api.*;
1213
import org.junit.jupiter.params.ParameterizedTest;
@@ -48,6 +49,17 @@ void setupPatterns() {
4849
new Document("namespace", "finos").append("patterns", new ArrayList<>())
4950
);
5051
}
52+
53+
if (!database.listCollectionNames().into(new ArrayList<>()).contains("userAccess")) {
54+
database.createCollection("userAccess");
55+
Document document = new Document("username", "test-user")
56+
.append("namespace", "finos")
57+
.append("permission", UserAccess.Permission.read.name())
58+
.append("resourceType", UserAccess.ResourceType.patterns.name())
59+
.append("userAccessId", 101);
60+
61+
database.getCollection("userAccess").insertOne(document);
62+
}
5163
counterSetup(database);
5264
namespaceSetup(database);
5365
}
@@ -58,7 +70,7 @@ void setupPatterns() {
5870
void end_to_end_get_patterns_with_valid_scopes() {
5971
String authServerUrl = ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class);
6072
logger.info("authServerUrl {}", authServerUrl);
61-
String accessToken = getAccessToken(authServerUrl, CalmHubScopes.ARCHITECTURES_READ);
73+
String accessToken = generateAccessTokenWithPasswordGrantType(authServerUrl, CalmHubScopes.ARCHITECTURES_READ);
6274
given()
6375
.auth().oauth2(accessToken)
6476
.when().get("/calm/namespaces/finos/patterns")
@@ -67,7 +79,7 @@ void end_to_end_get_patterns_with_valid_scopes() {
6779
.body("values", empty());
6880
}
6981

70-
private String getAccessToken(String authServerUrl, String scope) {
82+
private String generateAccessTokenWithClientCredentialGrant(String authServerUrl, String scope) {
7183
String accessToken = given()
7284
.auth()
7385
.preemptive()
@@ -83,12 +95,31 @@ private String getAccessToken(String authServerUrl, String scope) {
8395
return accessToken;
8496
}
8597

98+
//This is not recommended from production, this password grant type is using to embedded preferred_username in jwt token to perform RBAC checks.
99+
private String generateAccessTokenWithPasswordGrantType(String authServerUrl, String scope) {
100+
String accessToken = given()
101+
.auth()
102+
.preemptive()
103+
.basic("calm-hub-client-app", "calm-hub-client-app-secret")
104+
.formParam("grant_type", "password")
105+
.formParam("username", "test-user")
106+
.formParam("password", "changeme")
107+
.formParam("scope", scope)
108+
.when()
109+
.post(authServerUrl.concat("/protocol/openid-connect/token"))
110+
.then()
111+
.statusCode(200)
112+
.extract()
113+
.path("access_token");
114+
return accessToken;
115+
}
116+
86117
@Test
87118
@Order(2)
88119
void end_to_end_forbidden_create_pattern_when_matching_scopes_notfound() {
89120
String authServerUrl = ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class);
90121
logger.info("authServerUrl {}", authServerUrl);
91-
String accessToken = getAccessToken(authServerUrl, CalmHubScopes.ARCHITECTURES_READ);
122+
String accessToken = generateAccessTokenWithClientCredentialGrant(authServerUrl, CalmHubScopes.ARCHITECTURES_READ);
92123

93124
given()
94125
.auth().oauth2(accessToken)
@@ -118,7 +149,7 @@ void end_to_end_unauthorize_create_pattern_request_with_no_access_token() {
118149
void end_to_end_get_namespaces_with_valid_access_token(String scope) {
119150
String authServerUrl = ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class);
120151
logger.info("authServerUrl {}", authServerUrl);
121-
String accessToken = getAccessToken(authServerUrl, scope);
152+
String accessToken = generateAccessTokenWithClientCredentialGrant(authServerUrl, scope);
122153
given()
123154
.auth().oauth2(accessToken)
124155
.when().get("/calm/namespaces")
@@ -132,7 +163,7 @@ void end_to_end_get_namespaces_with_valid_access_token(String scope) {
132163
void end_to_end_forbidden_get_namespaces_when_matching_scopes_notfound() {
133164
String authServerUrl = ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class);
134165
logger.info("authServerUrl {}", authServerUrl);
135-
String accessToken = getAccessToken(authServerUrl, "deny:all");
166+
String accessToken = generateAccessTokenWithClientCredentialGrant(authServerUrl, "deny:all");
136167
given()
137168
.auth().oauth2(accessToken)
138169
.when().get("/calm/namespaces")

calm-hub/src/main/java/org/finos/calm/domain/UserAccess.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public enum ResourceType {
3131
private Permission permission;
3232
private String namespace;
3333
private ResourceType resourceType;
34-
private int id;
34+
private int userAccessId;
3535

3636
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
3737
@JsonSerialize(using = LocalDateTimeSerializer.class)
@@ -41,12 +41,12 @@ public enum ResourceType {
4141
@JsonSerialize(using = LocalDateTimeSerializer.class)
4242
private LocalDateTime updateDateTime;
4343

44-
public UserAccess(String username, Permission permission, String namespace, ResourceType resourceType, int id) {
44+
public UserAccess(String username, Permission permission, String namespace, ResourceType resourceType, int userAccessId) {
4545
this.username = username;
4646
this.permission = permission;
4747
this.namespace = namespace;
4848
this.resourceType = resourceType;
49-
this.id = id;
49+
this.userAccessId = userAccessId;
5050
}
5151

5252
public UserAccess(String username, Permission permission, String namespace, ResourceType resourceType) {
@@ -66,7 +66,7 @@ public static class UserAccessBuilder {
6666
private Permission permission;
6767
private String namespace;
6868
private ResourceType resourceType;
69-
private int id;
69+
private int userAccessId;
7070

7171
public UserAccessBuilder setUsername(String username) {
7272
this.username = username;
@@ -88,13 +88,13 @@ public UserAccessBuilder setResourceType(ResourceType resourceType) {
8888
return this;
8989
}
9090

91-
public UserAccessBuilder setId(int id) {
92-
this.id = id;
91+
public UserAccessBuilder setUserAccessId(int userAccessId) {
92+
this.userAccessId = userAccessId;
9393
return this;
9494
}
9595

9696
public UserAccess build(){
97-
return new UserAccess(username, permission, namespace, resourceType, id);
97+
return new UserAccess(username, permission, namespace, resourceType, userAccessId);
9898
}
9999
}
100100

@@ -114,8 +114,8 @@ public ResourceType getResourceType() {
114114
return resourceType;
115115
}
116116

117-
public int getId() {
118-
return id;
117+
public int getUserAccessId() {
118+
return userAccessId;
119119
}
120120

121121
public LocalDateTime getCreationDateTime() {
@@ -141,7 +141,7 @@ public boolean equals(Object o) {
141141

142142
UserAccess that = (UserAccess) o;
143143

144-
if (id != that.id) return false;
144+
if (userAccessId != that.userAccessId) return false;
145145
if (!Objects.equals(username, that.username)) return false;
146146
if (!Objects.equals(permission, that.permission)) return false;
147147
if (!Objects.equals(namespace, that.namespace)) return false;
@@ -150,7 +150,7 @@ public boolean equals(Object o) {
150150

151151
@Override
152152
public int hashCode() {
153-
return Objects.hash(username, permission, namespace, resourceType, id);
153+
return Objects.hash(username, permission, namespace, resourceType, userAccessId);
154154
}
155155

156156
@Override
@@ -160,7 +160,7 @@ public String toString() {
160160
", permission='" + permission + '\'' +
161161
", namespace='" + namespace + '\'' +
162162
", resourceType='" + resourceType + '\'' +
163-
", id=" + id +
163+
", userAccessId=" + userAccessId +
164164
'}';
165165
}
166166

@@ -180,7 +180,7 @@ public void setResourceType(ResourceType resourceType) {
180180
this.resourceType = resourceType;
181181
}
182182

183-
public void setId(int id) {
184-
this.id = id;
183+
public void setUserAccessId(int userAccessId) {
184+
this.userAccessId = userAccessId;
185185
}
186186
}

0 commit comments

Comments
 (0)