Skip to content

Commit

Permalink
Merge pull request #40428 from nderwin-forks/feature/test-security-at…
Browse files Browse the repository at this point in the history
…tribute-values

Add test security attribute type handling
  • Loading branch information
sberyozkin authored May 4, 2024
2 parents 8790966 + bc206d7 commit 29bae6b
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 1 deletion.
18 changes: 18 additions & 0 deletions docs/src/main/asciidoc/security-testing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ identity to be present.

See xref:security-oidc-bearer-token-authentication.adoc#integration-testing-security-annotation[OpenID Connect Bearer Token Integration testing], xref:security-oidc-code-flow-authentication.adoc#integration-testing-security-annotation[OpenID Connect Authorization Code Flow Integration testing] and xref:security-jwt.adoc#integration-testing-security-annotation[SmallRye JWT Integration testing] for more details about testing the endpoint code which depends on the injected `JsonWebToken`.

Additionally, you can specify attributes for the identity, perhaps custom items that were added with identity augmentation:

[source,java]
----
@Inject
SecurityIdentity identity;
@Test
@TestSecurity(user = "testUser", "roles = {"admin, "user"}, attributes = {
@SecurityAttribute(key = "answer", value = "42", type = AttributeType.LONG) }
void someTestMethod() {
Long answer = identity.<Long>getAttribute("answer");
...
}
----

This will run the test with an identity with an attribute of type `Long` named `answer`.

[WARNING]
====
The feature is only available for `@QuarkusTest` and will **not** work on a `@QuarkusIntegrationTest`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.quarkus.it.resteasy.elytron;

import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.util.stream.Stream;
Expand All @@ -13,6 +16,7 @@
import org.junit.jupiter.params.provider.ValueSource;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.AttributeType;
import io.quarkus.test.security.SecurityAttribute;
import io.quarkus.test.security.TestSecurity;

Expand Down Expand Up @@ -94,6 +98,50 @@ void testAttributes() {
.body(is("foo=bar"));
}

@Test
@TestSecurity(user = "testUser", roles = "user", attributes = {
@SecurityAttribute(key = "foo", value = "9223372036854775807", type = AttributeType.LONG) })
void testLongAttributes() {
given()
.when()
.get("/attributes")
.then()
.statusCode(200)
.body(is("foo=" + Long.MAX_VALUE));
}

@Test
@TestSecurity(user = "testUser", roles = "user", attributes = {
@SecurityAttribute(key = "foo", value = "[\"A\",\"B\",\"C\"]", type = AttributeType.JSON_ARRAY) })
void testJsonArrayAttributes() {
given()
.when()
.get("/attributes")
.then()
.statusCode(200)
.body(is("foo=[\"A\",\"B\",\"C\"]"));
}

@Test
@TestSecurity(user = "testUser", roles = "user", attributes = {
@SecurityAttribute(key = "foo", value = "\"A\",\"B\",\"C\"", type = AttributeType.STRING_SET) })
void testStringSetAttributes() {
given()
.when()
.get("/attributes")
.then()
.statusCode(200)
.body(startsWith("foo=["))
.and()
.body(endsWith("]"))
.and()
.body(containsString("\"A\""))
.and()
.body(containsString("\"B\""))
.and()
.body(containsString("\"C\""));
}

static Stream<Arguments> arrayParams() {
return Stream.of(
arguments(new int[] { 1, 2 }, new String[] { "hello", "world" }));
Expand Down
6 changes: 6 additions & 0 deletions test-framework/security/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
<artifactId>junit-jupiter</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jsonp</artifactId>
<scope>compile</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.quarkus.test.security;

import java.io.StringReader;
import java.util.Set;

import jakarta.json.Json;
import jakarta.json.JsonReader;

public enum AttributeType {
LONG {
@Override
Object convert(String value) {
return Long.valueOf(value);
}
},
INTEGER {
@Override
Object convert(String value) {
return Integer.valueOf(value);
}
},
BOOLEAN {
@Override
Object convert(String value) {
return Boolean.valueOf(value);
}
},
STRING {
@Override
Object convert(String value) {
return value;
}
},
STRING_SET {
/**
* Returns a Set of String values, parsed from the given value.
*
* @param value a comma separated list of values
*/
@Override
Object convert(String value) {
return Set.of(value.split(","));
}
},
JSON_ARRAY {
@Override
Object convert(String value) {
try (JsonReader reader = Json.createReader(new StringReader(value))) {
return reader.readArray();
}
}
},
JSON_OBJECT {
@Override
Object convert(String value) {
try (JsonReader reader = Json.createReader(new StringReader(value))) {
return reader.readObject();
}
}
},
DEFAULT {
@Override
Object convert(String value) {
return value;
}
};

abstract Object convert(String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public void beforeEach(QuarkusTestMethodContext context) {

if (testSecurity.attributes() != null) {
user.addAttributes(Arrays.stream(testSecurity.attributes())
.collect(Collectors.toMap(s -> s.key(), s -> s.value())));
.collect(Collectors.toMap(s -> s.key(), s -> s.type().convert(s.value()))));
}

SecurityIdentity userIdentity = augment(user.build(), allAnnotations);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
String key();

String value();

AttributeType type() default AttributeType.DEFAULT;
}

0 comments on commit 29bae6b

Please sign in to comment.