From 1a6a21b806d8f35f9968ebe96da2f13ebe152c96 Mon Sep 17 00:00:00 2001 From: thcai Date: Tue, 7 Jan 2025 18:04:32 +0100 Subject: [PATCH 1/6] Fix jwt parsing Signed-off-by: thcai --- .../kafkactl/command/auth/AuthInfo.java | 26 +++++++++---------- .../michelin/kafkactl/model/JwtContent.java | 2 +- .../kafkactl/command/auth/AuthInfoTest.java | 2 +- .../kafkactl/service/LoginServiceTest.java | 8 +++--- src/test/resources/fake_login/jwt | 2 +- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java index a90d72c..92ee0fe 100644 --- a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java +++ b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java @@ -54,14 +54,9 @@ public Integer call() throws IOException { } else { JwtContent jwtContent = loginService.readJwtFile(); - StringBuilder stringBuilder = new StringBuilder(); - if (!jwtContent.getRoles().isEmpty() && jwtContent.getRoles().contains("isAdmin()")) { - stringBuilder.append("Admin "); - } else { - stringBuilder.append("User "); - } - stringBuilder.append(jwtContent.getSub()).append(" authenticated."); - commandSpec.commandLine().getOut().println(stringBuilder); + boolean isAdmin = (!jwtContent.getRoles().isEmpty() && jwtContent.getRoles().contains("isAdmin()")); + commandSpec.commandLine().getOut().println((isAdmin ? "Admin " : "User ") + + jwtContent.getSub() + " authenticated."); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(jwtContent.getExp() * 1000); @@ -70,13 +65,16 @@ public Integer call() throws IOException { if (!jwtContent.getRoleBindings().isEmpty()) { List roleBindings = jwtContent.getRoleBindings() .stream() - .map(roleBinding -> Resource.builder() - .spec(Map.of( - "namespace", roleBinding.getNamespace(), - "verbs", roleBinding.getVerbs(), - "resources", roleBinding.getResourceTypes() - )) + .flatMap(roleBinding -> roleBinding.getNamespaces() + .stream() + .map(namespace -> Resource.builder() + .spec(Map.of( + "namespace", namespace, + "verbs", roleBinding.getVerbs(), + "resources", roleBinding.getResourceTypes() + )) .build()) + ) .toList(); formatService.displayList(AUTH_INFO, roleBindings, output, commandSpec); diff --git a/src/main/java/com/michelin/kafkactl/model/JwtContent.java b/src/main/java/com/michelin/kafkactl/model/JwtContent.java index d283e2f..bb64b30 100644 --- a/src/main/java/com/michelin/kafkactl/model/JwtContent.java +++ b/src/main/java/com/michelin/kafkactl/model/JwtContent.java @@ -33,7 +33,7 @@ public class JwtContent { @NoArgsConstructor @AllArgsConstructor public static class RoleBinding { - private String namespace; + private List namespaces; private List verbs; private List resourceTypes; diff --git a/src/test/java/com/michelin/kafkactl/command/auth/AuthInfoTest.java b/src/test/java/com/michelin/kafkactl/command/auth/AuthInfoTest.java index f6119fe..34d1915 100644 --- a/src/test/java/com/michelin/kafkactl/command/auth/AuthInfoTest.java +++ b/src/test/java/com/michelin/kafkactl/command/auth/AuthInfoTest.java @@ -108,7 +108,7 @@ void shouldDisplayInfoFromJwtUserAndRoleBindings() throws IOException { .sub("user") .exp(1711241399L) .roleBindings(List.of(JwtContent.RoleBinding.builder() - .namespace("namespace") + .namespaces(List.of("namespace")) .verbs(List.of(GET)) .resourceTypes(List.of("resource")) .build())) diff --git a/src/test/java/com/michelin/kafkactl/service/LoginServiceTest.java b/src/test/java/com/michelin/kafkactl/service/LoginServiceTest.java index 496e628..0440697 100644 --- a/src/test/java/com/michelin/kafkactl/service/LoginServiceTest.java +++ b/src/test/java/com/michelin/kafkactl/service/LoginServiceTest.java @@ -309,11 +309,11 @@ void shouldReadJwtFile() throws IOException { assertIterableEquals(List.of("isAdmin()"), actual.getRoles()); - assertEquals("anotherNamespace", actual.getRoleBindings().getFirst().getNamespace()); - assertIterableEquals(List.of(GET), actual.getRoleBindings().get(0).getVerbs()); - assertIterableEquals(List.of("quota"), actual.getRoleBindings().get(0).getResourceTypes()); + assertIterableEquals(List.of("anotherNamespace"), actual.getRoleBindings().getFirst().getNamespaces()); + assertIterableEquals(List.of(GET), actual.getRoleBindings().getFirst().getVerbs()); + assertIterableEquals(List.of("quota"), actual.getRoleBindings().getFirst().getResourceTypes()); - assertEquals("anotherNamespace", actual.getRoleBindings().get(1).getNamespace()); + assertIterableEquals(List.of("anotherNamespace"), actual.getRoleBindings().get(1).getNamespaces()); assertIterableEquals(List.of(GET, POST, PUT, DELETE), actual.getRoleBindings().get(1).getVerbs()); assertIterableEquals(List.of("schemas", "schemas/config", "topics", "topics/import", "topics/delete-records", "connectors", "connectors/import", "connectors/change-state", "connect-clusters", "connect-clusters/vaults", diff --git a/src/test/resources/fake_login/jwt b/src/test/resources/fake_login/jwt index e56217e..b53bac6 100644 --- a/src/test/resources/fake_login/jwt +++ b/src/test/resources/fake_login/jwt @@ -3,7 +3,7 @@ "roles": [ "isAdmin()" ], - "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlQmluZGluZ3MiOlt7Im5hbWVzcGFjZSI6ImFub3RoZXJOYW1lc3BhY2UiLCJ2ZXJicyI6WyJHRVQiXSwicmVzb3VyY2VUeXBlcyI6WyJxdW90YSJdfSx7Im5hbWVzcGFjZSI6ImFub3RoZXJOYW1lc3BhY2UiLCJ2ZXJicyI6WyJHRVQiLCJQT1NUIiwiUFVUIiwiREVMRVRFIl0sInJlc291cmNlVHlwZXMiOlsic2NoZW1hcyIsInNjaGVtYXMvY29uZmlnIiwidG9waWNzIiwidG9waWNzL2ltcG9ydCIsInRvcGljcy9kZWxldGUtcmVjb3JkcyIsImNvbm5lY3RvcnMiLCJjb25uZWN0b3JzL2ltcG9ydCIsImNvbm5lY3RvcnMvY2hhbmdlLXN0YXRlIiwiY29ubmVjdC1jbHVzdGVycyIsImNvbm5lY3QtY2x1c3RlcnMvdmF1bHRzIiwiYWNscyIsImNvbnN1bWVyLWdyb3Vwcy9yZXNldCIsInN0cmVhbXMiXX1dLCJzdWIiOiJhZG1pbiIsIm5iZiI6MTcxMTMxMDA5MSwicm9sZXMiOlsiaXNBZG1pbigpIl0sImlzcyI6Im5zNGthZmthIiwiZXhwIjoxNzExMzEzNjkxLCJpYXQiOjE3MTEzMTAwOTF9.PtQthWXGjaL_cMkV0uqfifkqevU8E6vzRA9v43pw_Gc", + "access_token": "eyJhbGciOiJIUzI1NiJ9.eyJyb2xlQmluZGluZ3MiOlt7Im5hbWVzcGFjZXMiOlsiYW5vdGhlck5hbWVzcGFjZSJdLCJ2ZXJicyI6WyJHRVQiXSwicmVzb3VyY2VUeXBlcyI6WyJxdW90YSJdfSx7Im5hbWVzcGFjZXMiOlsiYW5vdGhlck5hbWVzcGFjZSJdLCJ2ZXJicyI6WyJHRVQiLCJQT1NUIiwiUFVUIiwiREVMRVRFIl0sInJlc291cmNlVHlwZXMiOlsic2NoZW1hcyIsInNjaGVtYXMvY29uZmlnIiwidG9waWNzIiwidG9waWNzL2ltcG9ydCIsInRvcGljcy9kZWxldGUtcmVjb3JkcyIsImNvbm5lY3RvcnMiLCJjb25uZWN0b3JzL2ltcG9ydCIsImNvbm5lY3RvcnMvY2hhbmdlLXN0YXRlIiwiY29ubmVjdC1jbHVzdGVycyIsImNvbm5lY3QtY2x1c3RlcnMvdmF1bHRzIiwiYWNscyIsImNvbnN1bWVyLWdyb3Vwcy9yZXNldCIsInN0cmVhbXMiXX1dLCJzdWIiOiJhZG1pbiIsIm5iZiI6MTcxMTMxMDA5MSwicm9sZXMiOlsiaXNBZG1pbigpIl0sImlzcyI6Im5zNGthZmthIiwiZXhwIjoxNzExMzEzNjkxLCJpYXQiOjE3MTEzMTAwOTF9.EbMakF9L3au7qDSKTzfU-LGhR1k8aKZtLbY8wcxnXHA", "token_type": "Bearer", "expires_in": 3600 } \ No newline at end of file From d87cfc8075a59c9a77afde4b0c954fe607fbc381 Mon Sep 17 00:00:00 2001 From: thcai Date: Wed, 8 Jan 2025 10:35:51 +0100 Subject: [PATCH 2/6] Sort the list of role bindings by namespace Signed-off-by: thcai --- src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java index 92ee0fe..39e40d1 100644 --- a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java +++ b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java @@ -11,6 +11,7 @@ import jakarta.inject.Inject; import java.io.IOException; import java.util.Calendar; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -75,6 +76,8 @@ public Integer call() throws IOException { )) .build()) ) + .sorted(Comparator.comparing(roleBinding -> (String) roleBinding.getSpec().get("namespace"), + Comparator.naturalOrder())) .toList(); formatService.displayList(AUTH_INFO, roleBindings, output, commandSpec); From f8dc2d355b724b564993a4167dd21504ad951914 Mon Sep 17 00:00:00 2001 From: thcai Date: Wed, 8 Jan 2025 10:44:56 +0100 Subject: [PATCH 3/6] Fix increment Signed-off-by: thcai --- src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java index 39e40d1..3a56a2a 100644 --- a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java +++ b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java @@ -74,7 +74,8 @@ public Integer call() throws IOException { "verbs", roleBinding.getVerbs(), "resources", roleBinding.getResourceTypes() )) - .build()) + .build() + ) ) .sorted(Comparator.comparing(roleBinding -> (String) roleBinding.getSpec().get("namespace"), Comparator.naturalOrder())) From 7c61ea80a7653101f73150287a67dbc26a3d000e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Greffier?= Date: Tue, 14 Jan 2025 13:11:32 +0100 Subject: [PATCH 4/6] Remove unused parenthesis --- .../com/michelin/kafkactl/command/auth/AuthInfo.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java index 3a56a2a..38d93ea 100644 --- a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java +++ b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java @@ -55,9 +55,8 @@ public Integer call() throws IOException { } else { JwtContent jwtContent = loginService.readJwtFile(); - boolean isAdmin = (!jwtContent.getRoles().isEmpty() && jwtContent.getRoles().contains("isAdmin()")); - commandSpec.commandLine().getOut().println((isAdmin ? "Admin " : "User ") - + jwtContent.getSub() + " authenticated."); + boolean isAdmin = !jwtContent.getRoles().isEmpty() && jwtContent.getRoles().contains("isAdmin()"); + commandSpec.commandLine().getOut().println((isAdmin ? "Admin " : "User ") + jwtContent.getSub() + " authenticated."); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(jwtContent.getExp() * 1000); @@ -77,8 +76,10 @@ public Integer call() throws IOException { .build() ) ) - .sorted(Comparator.comparing(roleBinding -> (String) roleBinding.getSpec().get("namespace"), - Comparator.naturalOrder())) + .sorted(Comparator.comparing( + roleBinding -> (String) roleBinding.getSpec().get("namespace"), + Comparator.naturalOrder()) + ) .toList(); formatService.displayList(AUTH_INFO, roleBindings, output, commandSpec); From 09d66b933d5b6e7952c879eee32f3e964ab7deea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Greffier?= Date: Tue, 14 Jan 2025 13:12:01 +0100 Subject: [PATCH 5/6] Remove whitespace --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index cd9435e..dd0af2a 100644 --- a/README.md +++ b/README.md @@ -215,7 +215,6 @@ Description: Get the JWT token information. Options: -h, --help Show this help message and exit. -o, --output= Output format. One of: yaml|table - ``` Example(s): From 1c5cc1ef5636da5dbf851a71cd5b68df9a73b57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Greffier?= Date: Tue, 14 Jan 2025 13:14:58 +0100 Subject: [PATCH 6/6] Checkstyle --- .../java/com/michelin/kafkactl/command/auth/AuthInfo.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java index 38d93ea..5e97687 100644 --- a/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java +++ b/src/main/java/com/michelin/kafkactl/command/auth/AuthInfo.java @@ -56,7 +56,11 @@ public Integer call() throws IOException { JwtContent jwtContent = loginService.readJwtFile(); boolean isAdmin = !jwtContent.getRoles().isEmpty() && jwtContent.getRoles().contains("isAdmin()"); - commandSpec.commandLine().getOut().println((isAdmin ? "Admin " : "User ") + jwtContent.getSub() + " authenticated."); + commandSpec.commandLine().getOut().println( + (isAdmin ? "Admin " : "User ") + + jwtContent.getSub() + + " authenticated." + ); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(jwtContent.getExp() * 1000);