Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to disable security on a per test basis #10487

Merged
merged 1 commit into from
Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions bom/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,11 @@
<artifactId>quarkus-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-runtime-spi</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-deployment</artifactId>
Expand Down Expand Up @@ -1787,6 +1792,11 @@
<artifactId>quarkus-junit5</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
Expand Down
47 changes: 47 additions & 0 deletions docs/src/main/asciidoc/security.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,50 @@ This will allow you to propagate the identity throughout the reactive callbacks.
are using an executor that is capable of propagating the identity (e.g. no `CompletableFuture.supplyAsync`),
to make sure that quarkus can propagate it. For more information see the
link:context-propagation[Context Propagation Guide].

== Testing Security

Quarkus provides explicit support for testing with different users, and with the security subsystem disabled. To use
this you must include the `quarkus-test-security` artifact:

[source,xml]
----
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<scope>test</scope>
</dependency>
----

This artifact provides the `io.quarkus.test.security.TestSecurity` annotation, that can be applied to test methods and
test classes to control the security context that the test is run with. This allows you to do two things, you can disable
authorization so tests can access secured endpoints without needing to be authenticated, and you can specify the identity
that you want the tests to run under.

A test that runs with authorization disabled can just set the enabled property to false:

[source,java]
----
@Test
@TestSecurity(authorizationEnabled = false)
void someTestMethod() {
...
}
----

This will disable all access checks, which allows the test to access secured endpoints without needing to authenticate.

You can also use this to configure the current user that the test will run as:

[source,java]
----
@Test
@TestSecurity(user = "testUser", roles = {"admin", "user"})
void someTestMethod() {
...
}
----

This will run the test with an identity with the given username and roles. Note that these can be combined, so you can
disable authorisation and also provide an identity to run the test under, which can be userful if the endpoint expects an
identity to be present.
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@ public Response toResponse(UnauthorizedException exception) {
if (authenticator != null) {
ChallengeData challengeData = authenticator.getChallenge(context)
.await().indefinitely();
Response.ResponseBuilder status = Response.status(challengeData.status);
if (challengeData.headerName != null) {
status.header(challengeData.headerName.toString(), challengeData.headerContent);
if (challengeData != null) {
Response.ResponseBuilder status = Response.status(challengeData.status);
if (challengeData.headerName != null) {
status.header(challengeData.headerName.toString(), challengeData.headerContent);
}
return status.build();
} else {
return Response.status(401).build();
}
return status.build();
}
}
return Response.status(401).entity("Not authorized").build();
Expand Down
4 changes: 4 additions & 0 deletions extensions/security/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-runtime-spi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import io.quarkus.security.runtime.interceptor.SecurityHandler;
import io.quarkus.security.runtime.interceptor.check.SecurityCheck;
import io.quarkus.security.spi.AdditionalSecuredClassesBuildIem;
import io.quarkus.security.spi.runtime.AuthorizationController;

public class SecurityProcessor {

Expand All @@ -83,6 +84,11 @@ void services(BuildProducer<JCAProviderBuildItem> jcaProviders) {
}
}

@BuildStep
AdditionalBeanBuildItem authorizationController() {
return AdditionalBeanBuildItem.builder().addBeanClass(AuthorizationController.class).build();
}

/**
* Register the classes for reflection in the requested named providers
*
Expand Down
1 change: 1 addition & 0 deletions extensions/security/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
<module>runtime</module>
<module>spi</module>
<module>test-utils</module>
<module>runtime-spi</module>
</modules>
</project>
39 changes: 39 additions & 0 deletions extensions/security/runtime-spi/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-security-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-security-runtime-spi</artifactId>
<name>Quarkus - Security - Runtime SPI</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.quarkus.security.spi.runtime;

import javax.inject.Singleton;

/**
* controller that allows authorization to be disabled in tests.
*/
@Singleton
public class AuthorizationController {

public boolean isAuthorizationEnabled() {
return true;
}
}
4 changes: 4 additions & 0 deletions extensions/security/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-runtime-spi</artifactId>
</dependency>
<dependency>
<groupId>jakarta.interceptor</groupId>
<artifactId>jakarta.interceptor-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.interceptor.InvocationContext;

import io.quarkus.security.Authenticated;
import io.quarkus.security.spi.runtime.AuthorizationController;

/**
* @author Michal Szynkiewicz, [email protected]
Expand All @@ -19,8 +20,15 @@ public class AuthenticatedInterceptor {
@Inject
SecurityHandler handler;

@Inject
AuthorizationController controller;

@AroundInvoke
public Object intercept(InvocationContext ic) throws Exception {
return handler.handle(ic);
if (controller.isAuthorizationEnabled()) {
return handler.handle(ic);
} else {
return ic.proceed();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

import io.quarkus.security.spi.runtime.AuthorizationController;

/**
* @author Michal Szynkiewicz, [email protected]
*/
Expand All @@ -18,8 +20,15 @@ public class RolesAllowedInterceptor {
@Inject
SecurityHandler handler;

@Inject
AuthorizationController controller;

@AroundInvoke
public Object intercept(InvocationContext ic) throws Exception {
return handler.handle(ic);
if (controller.isAuthorizationEnabled()) {
return handler.handle(ic);
} else {
return ic.proceed();
}
}
}
4 changes: 4 additions & 0 deletions extensions/vertx-http/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-runtime-spi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-development-mode-spi</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.quarkus.runtime.ExecutorRecorder;
import io.quarkus.security.identity.IdentityProviderManager;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.spi.runtime.AuthorizationController;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.subscription.UniEmitter;
import io.smallrye.mutiny.subscription.UniSubscriber;
Expand All @@ -31,6 +32,9 @@ public class HttpAuthorizer {
@Inject
IdentityProviderManager identityProviderManager;

@Inject
AuthorizationController controller;

final List<HttpSecurityPolicy> policies;

@Inject
Expand Down Expand Up @@ -87,6 +91,10 @@ public void run() {
*
*/
public void checkPermission(RoutingContext routingContext) {
if (!controller.isAuthorizationEnabled()) {
routingContext.next();
return;
}
//check their permissions
doPermissionCheck(routingContext, QuarkusHttpUser.getSecurityIdentity(routingContext, identityProviderManager), 0, null,
policies);
Expand Down
5 changes: 5 additions & 0 deletions integration-tests/elytron-resteasy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.it.resteasy.elytron;

import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
Expand All @@ -9,6 +10,8 @@
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.SecurityContext;

import io.quarkus.security.Authenticated;

@Path("/")
public class RootResource {

Expand All @@ -32,4 +35,19 @@ public String approval(@Context SecurityContext sec) {
}
return "get success";
}

@GET
@Path("/secure")
@Authenticated
public String getSecure() {
return "secure";
}

@GET
@Path("/user")
@RolesAllowed("user")
public String user(@Context SecurityContext sec) {
return sec.getUserPrincipal().getName();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ quarkus.security.users.embedded.users.mary=mary
quarkus.security.users.embedded.roles.mary=managers
quarkus.security.users.embedded.users.poul=poul
quarkus.security.users.embedded.roles.poul=interns
quarkus.security.users.embedded.auth-mechanism=BASIC
quarkus.security.users.embedded.plain-text=true
quarkus.http.auth.basic=true
Loading