Skip to content

Commit

Permalink
Introduce a Hibernate Reactive variant of the security JPA extension
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik committed Apr 10, 2023
1 parent 4799f2a commit 62a2f1e
Show file tree
Hide file tree
Showing 76 changed files with 2,385 additions and 299 deletions.
22 changes: 21 additions & 1 deletion bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
<liquibase.version>4.20.0</liquibase.version>
<snakeyaml.version>2.0</snakeyaml.version>
<osgi.version>6.0.0</osgi.version>
<mongo-client.version>4.9.0</mongo-client.version>
<mongo-client.version>4.9.1</mongo-client.version>
<mongo-crypt.version>1.7.1</mongo-crypt.version>
<proton-j.version>0.34.1</proton-j.version>
<javaparser.version>3.25.1</javaparser.version>
Expand Down Expand Up @@ -2747,6 +2747,26 @@
<artifactId>quarkus-security-jpa-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-reactive</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-reactive-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-webauthn</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public enum Feature {
SECURITY_JDBC,
SECURITY_LDAP,
SECURITY_JPA,
SECURITY_JPA_REACTIVE,
SECURITY_PROPERTIES_FILE,
SECURITY_OAUTH2,
SECURITY_WEBAUTHN,
Expand Down
26 changes: 26 additions & 0 deletions devtools/bom-descriptor-json/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,32 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-reactive</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-webauthn</artifactId>
Expand Down
26 changes: 26 additions & 0 deletions docs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,32 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-reactive-deployment</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-webauthn-deployment</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ When you run either command, the following XML is added to your build file:
implementation("io.quarkus:quarkus-security-jpa")
----

=== Using Hibernate Reactive

If you plan to use Hibernate Reactive and non-blocking database drivers, you will need to use the `security-jpa-reactive` extension instead.
The `security-jpa-reactive` extension works with the same annotations and you will only need to adjust configuration specific for Hibernate Reactive.
Please refer to the xref:hibernate-reactive.adoc[Hibernate Reactive guide] for more information.

== Write the application

* Let's start by implementing the `/api/public` endpoint to allow all users access to access the application.
Expand Down
2 changes: 2 additions & 0 deletions extensions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@
<!-- Security -->
<module>security</module>
<module>security-jpa</module>
<module>security-jpa-reactive</module>
<module>security-jpa-common</module>
<module>security-webauthn</module>
<module>elytron-security-common</module>
<module>elytron-security</module>
Expand Down
52 changes: 52 additions & 0 deletions extensions/security-jpa-common/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common-parent</artifactId>
<version>999-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>quarkus-security-jpa-common-deployment</artifactId>
<name>Quarkus - Security Jakarta Persistence - Common - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-jpa-common</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-common-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-security-deployment</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<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
@@ -1,24 +1,35 @@
package io.quarkus.security.jpa.deployment;
package io.quarkus.security.jpa.common.deployment;

import java.lang.reflect.Modifier;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.Index;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;

import io.quarkus.arc.processor.DotNames;
import io.quarkus.deployment.bean.JavaBeanUtil;
import io.quarkus.gizmo.AssignableResultHandle;
import io.quarkus.gizmo.BytecodeCreator;
import io.quarkus.gizmo.FieldDescriptor;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;

public class JpaSecurityDefinition {

public boolean haveRolesAnnotation(DotName... annotations) {
for (DotName annotation : annotations) {
if (roles.annotation(annotation) != null) {
return true;
}
}
return false;
}

public static class FieldOrMethod {
public final FieldInfo field;
public final MethodInfo getter;
Expand All @@ -42,12 +53,12 @@ public String name() {
return JavaBeanUtil.getPropertyNameFromGetter(getter.name());
}

public ResultHandle readValue(BytecodeCreator methodCreator, AssignableResultHandle userVar) {
public ResultHandle readValue(BytecodeCreator bytecodeCreator, ResultHandle userVar) {
// favour the getter
if (getter != null) {
return methodCreator.invokeVirtualMethod(MethodDescriptor.of(getter), userVar);
return bytecodeCreator.invokeVirtualMethod(MethodDescriptor.of(getter), userVar);
}
return methodCreator.readInstanceField(FieldDescriptor.of(field), userVar);
return bytecodeCreator.readInstanceField(FieldDescriptor.of(field), userVar);
}

public Type type() {
Expand Down Expand Up @@ -78,6 +89,11 @@ public JpaSecurityDefinition(Index index,

public static FieldOrMethod getFieldOrMethod(Index index, ClassInfo annotatedClass,
AnnotationTarget annotatedFieldOrMethod, boolean isPanache) {

if (annotatedFieldOrMethod == null) {
return null;
}

switch (annotatedFieldOrMethod.kind()) {
case FIELD:
// try to find a getter for this field
Expand All @@ -93,6 +109,14 @@ public static FieldOrMethod getFieldOrMethod(Index index, ClassInfo annotatedCla
}
}

public AnnotationValue passwordType() {
return password.annotation(QuarkusSecurityJpaCommonProcessor.DOTNAME_PASSWORD).value();
}

public AnnotationValue customPasswordProvider() {
return password.annotation(QuarkusSecurityJpaCommonProcessor.DOTNAME_PASSWORD).value("provider");
}

// FIXME: in order to check for the getter type we need to apply type parameters, that's too complex so assume it matches
private static MethodInfo findGetter(Index index, ClassInfo annotatedClass, FieldInfo field, boolean isPanache) {
// if it's a panache field, we won't see the getter but it will be there
Expand All @@ -109,7 +133,7 @@ private static MethodInfo findGetter(Index index, ClassInfo annotatedClass, Stri
return method;
}
DotName superName = annotatedClass.superName();
if (superName != null && !superName.equals(QuarkusSecurityJpaProcessor.DOTNAME_OBJECT)) {
if (superName != null && !superName.equals(DotNames.OBJECT)) {
ClassInfo superClass = index.getClassByName(superName);
if (superClass != null) {
method = findGetter(index, superClass, methodName);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.quarkus.security.jpa.common.deployment;

import io.quarkus.builder.item.SimpleBuildItem;

/**
* This build items holds {@link JpaSecurityDefinition} common for reactive and classic Jakarta Persistence Security.
*/
public final class JpaSecurityDefinitionBuildItem extends SimpleBuildItem {

private final JpaSecurityDefinition jpaSecurityDefinition;

JpaSecurityDefinitionBuildItem(JpaSecurityDefinition jpaSecurityDefinition) {
this.jpaSecurityDefinition = jpaSecurityDefinition;
}

public JpaSecurityDefinition get() {
return jpaSecurityDefinition;
}
}
Loading

0 comments on commit 62a2f1e

Please sign in to comment.