Skip to content

Commit

Permalink
Merge pull request #32512 from michalvavrik/feature/security-jpa-reac…
Browse files Browse the repository at this point in the history
…tive

Introduce a Hibernate Reactive variant of the Security Jakarta Persistence extension
  • Loading branch information
sberyozkin authored Apr 13, 2023
2 parents 5f5f118 + 03df5d5 commit 3031a03
Show file tree
Hide file tree
Showing 76 changed files with 2,394 additions and 298 deletions.
20 changes: 20 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2756,6 +2756,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
16 changes: 16 additions & 0 deletions docs/src/main/asciidoc/security-basic-authentication-tutorial.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,22 @@ 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 only difference in configuration is a datasource URL.
Reactive datasource has URL set with the `quarkus.datasource.reactive.url` configuration property, instead of the `quarkus.datasource.jdbc.url`
configuration property used by JDBC datasource.

[source,properties]
----
%prod.quarkus.datasource.reactive.url=vertx-reactive:postgresql://localhost:5431/security_jpa
----

Please refer to the xref:hibernate-reactive.adoc[Hibernate Reactive guide] for more information.
On top of that, Hibernate Reactive with Panache uses its own reactive classes as `io.quarkus.hibernate.reactive.panache.PanacheEntity`.
You can learn more about it in the xref:hibernate-reactive-panache.adoc[Hibernate Reactive with Panache guide].

== 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 3031a03

Please sign in to comment.