Quarkus Security 3 - Quarkus dengan Jakarta Persistence (JPA) Identity provider

Quarkus Security dan Provider Identitas dengan JPA 


 

Anda dapat mengonfigurasi aplikasi Anda untuk menggunakan Jakarta Persistence untuk menyimpan identitas pengguna.

Quarkus menyediakan provider identitas Jakarta Persistence, yang mirip dengan provider JDBC. Jakarta Persistence cocok digunakan dengan mekanisme Keamanan Quarkus yang berbasis Basic dan Form, yang memerlukan kredensial nama pengguna dan kata sandi.

Penyedia Identitas Jakarta Persistence membuat instance SecurityIdentity. Selama proses otentikasi pengguna, instance ini digunakan untuk memverifikasi dan mengotorisasi permintaan akses.

Untuk contoh praktis, lihat tutorial Memulai Belajar Keamanan Sistem menggunakan Autentikasi Dasar dan Jakarta Persistence di Qurkus di bagian bawah

Spesifikasi entitas Jakarta Persistence

Keamanan Quarkus menawarkan integrasi Jakarta Persistence untuk mengumpulkan nama pengguna, kata sandi, dan peran, serta menyimpannya ke dalam entitas basis data Jakarta Persistence.

Spesifikasi entitas Jakarta Persistence berikut menunjukkan bagaimana informasi pengguna perlu disimpan dalam entitas Jakarta Persistence dan dipetakan dengan benar agar Quarkus dapat mengambil informasi ini dari basis data.

  • Anotasi @User Definition harus ada pada entitas Jakarta Persistence, terlepas dari apakah Hibernate ORM yang disederhanakan dengan Panache digunakan atau tidak.
  • Tipe field @Username dan @Password selalu berupa String.
  • Field @Roles harus berupa String, Collection<String>, atau Collection<X>, di mana X adalah kelas entitas dengan satu field String yang dianotasi sebagai @RolesValue.
  • Setiap elemen tipe peran String diparsing sebagai daftar roles yang dipisahkan oleh koma.

Contoh berikut menunjukkan cara menyimpan informasi keamanan dengan menambahkan anotasi ke entitas pengguna: 

@Entity
@Table(name = "test_user")
@UserDefinition
public class User extends PanacheEntity {
@Username
public String username;
@Password
public String password;
@Roles
public String role;

/**
* Adds a new user to the database
* @param username the username
* @param password the unencrypted password (it is encrypted with bcrypt)
* @param role the comma-separated roles
*/
public static void add(String username, String password, String role) {
User user = new User();
user.username = username;
user.password = BcryptUtil.bcryptHash(password);
user.role = role;
user.persist();
}
}

Ekstensi quarkus-security-jpa hanya diinisialisasi jika satu entitas dianotasi dengan @User Definition.

  • Nama tabel. Jangan mendefinisikannya sebagai "user", yang merupakan kata kunci yang dibatasi di sebagian besar basis data.

  • Anotasi @User Definition harus ada pada satu entitas, baik entitas Hibernate ORM biasa atau entitas Hibernate ORM dengan Panache.

  • Menunjukkan field yang digunakan untuk nama pengguna.

  • Menunjukkan field yang digunakan untuk kata sandi. Secara default, quarkus-security-jpa menggunakan kata sandi yang di-hash dengan bcrypt, atau Anda dapat mengonfigurasi kata sandi dalam teks biasa atau kata sandi kustom sebagai gantinya.

  • Ini menunjukkan daftar peran yang dipisahkan oleh koma yang ditambahkan ke atribut representasi prinsipal target.

  • Metode ini memungkinkan Anda menambahkan pengguna sambil meng-hash kata sandi dengan hash bcrypt yang sesuai.

Entity Jakarta Persistence sebagai Penyimpanan Role

Gunakan contoh berikut untuk menyimpan Role di dalam entity Jakarta Persistence lainnya:

@UserDefinition
@Table(name = "test_user")
@Entity
public class User extends PanacheEntity {
@Username
public String name;

@Password
public String pass;

@ManyToMany
@Roles
public List<Role> roles = new ArrayList<>();
}

@Entity
public class Role extends PanacheEntity {

@ManyToMany(mappedBy = "roles")
public List<User> users;

@RolesValue
public String role;
}

Contoh ini menunjukkan cara menyimpan dan mengakses Role. Untuk memperbarui pengguna yang ada atau membuat yang baru, anotasi public List<Role> roles dengan @Cascade(CascadeType.ALL) atau pilih CascadeType tertentu. 

Penyimpanan dan Penghashan Password

Saat mengembangkan aplikasi dengan Quarkus, Anda dapat memutuskan bagaimana mengelola penyimpanan dan penghashan password. Anda dapat mempertahankan pengaturan password dan penghashan default Quarkus, atau Anda dapat menghash password secara manual.

Dengan opsi default, password disimpan dan dihash dengan bcrypt di bawah Modular Crypt Format (MCF). Saat menggunakan MCF, algoritma penghashan, jumlah iterasi, dan salt disimpan sebagai bagian dari nilai yang dihash. Dengan demikian, kita tidak memerlukan kolom khusus untuk menyimpannya.

Dalam kriptografi, salt adalah istilah untuk data acak yang digunakan sebagai input tambahan untuk fungsi satu arah yang menghash data, password, atau frasa sandi.

Untuk merepresentasikan password yang disimpan dalam basis data yang dihash dengan algoritma yang berbeda, buatlah kelas yang mengimplementasikan org.wildfly.security.password.PasswordProvider seperti yang ditunjukkan dalam contoh berikut.

Cuplikan berikut menunjukkan cara mengatur penyedia password kustom yang merepresentasikan password yang dihash dengan algoritma penghashan SHA256.

 

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import io.quarkus.security.jpa.Password;
import io.quarkus.security.jpa.PasswordType;
import io.quarkus.security.jpa.Roles;
import io.quarkus.security.jpa.UserDefinition;
import io.quarkus.security.jpa.Username;

@UserDefinition
@Table(name = "test_user")
@Entity
public class CustomPasswordUserEntity {
@Id
@GeneratedValue
public Long id;

@Column(name = "username")
@Username
public String name;

@Column(name = "password")
@Password(value = PasswordType.CUSTOM, provider = CustomPasswordProvider.class)
public String pass;

@Roles
public String role;
}
import jakarta.xml.bind.DatatypeConverter;

import org.wildfly.security.password.Password;
import org.wildfly.security.password.interfaces.SimpleDigestPassword;

import io.quarkus.security.jpa.PasswordProvider;

public class CustomPasswordProvider implements PasswordProvider {
@Override
public Password getPassword(String passwordInDatabase) {
byte[] digest = DatatypeConverter.parseHexBinary(passwordInDatabase);

// Let the security runtime know that this passwordInDatabase is hashed by using the SHA256 hashing algorithm
return SimpleDigestPassword.createRaw(SimpleDigestPassword.ALGORITHM_SIMPLE_DIGEST_SHA_256, digest);
}
}

"Untuk dengan cepat membuat password yang dihash, gunakan String BcryptUtil.bcryptHash(String password), yang secara default membuat salt acak dan menghash dalam sepuluh iterasi. Metode ini juga memungkinkan Anda untuk menentukan jumlah iterasi dan salt yang digunakan."

"Untuk aplikasi yang berjalan di lingkungan produksi, jangan menyimpan password sebagai teks biasa. Namun, adalah mungkin untuk menyimpan password sebagai teks biasa dengan anotasi @Password(PasswordType.CLEAR) saat beroperasi di lingkungan pengujian."

"Hibernate Multitenancy didukung, dan Anda dapat menyimpan entity pengguna dalam unit persistensi dengan multitenancy yang diaktifkan. Namun, jika io.quarkus.hibernate.orm.runtime.tenant.TenantResolver Anda harus mengakses io.vertx.ext.web.RoutingContext untuk menyelesaikan detail permintaan, Anda harus menonaktifkan autentikasi proaktif. Untuk informasi lebih lanjut tentang autentikasi proaktif, lihat panduan autentikasi proaktif Quarkus."

Properti Konfigurasi  

quarkus.security-jpa.persistence-unit-name

Environment variable: QUARKUS_SECURITY_JPA_PERSISTENCE_UNIT_NAME 

Pilih Hibernate ORM persistence unit. Pilihan default adalah persistence unit jika pilihan lain tidak dipilih

Referensi lainnya

Memulai Belajar Keamanan Sistem menggunakan Autentikasi Dasar dan Jakarta Persistence di Quarkus


 

Kita akan bahas  Quarkus Security dengan mengamankan endpoint aplikasi Quarkus menggunakan autentikasi dasar Quarkus yang sudah ada dengan provider Jakarta Persistence, yang memungkinkan kontrol akses berbasis role.

Provider Jakarta Persistence memverifikasi dan mengonversi pasangan nama pengguna dan password autentikasi dasar menjadi instance SecurityIdentity, yang digunakan untuk mengotorisasi permintaan akses, sehingga membuat aplikasi Quarkus Anda aman.

Untuk informasi lebih lanjut tentang Jakarta Persistence, lihat panduan Quarkus Security dengan Jakarta Persistence.

Tutorial ini mempersiapkan  untuk menerapkan mekanisme keamanan yang lebih optimal di Quarkus, misalnya, cara menggunakan mekanisme autentikasi OpenID Connect (OIDC).

Prasyarat
Untuk menyelesaikan panduan ini, Anda memerlukan:

  • Sekitar 15 menit
  • IntelliJ IDEA 
  • JDK 17+ terinstal dengan JAVA_HOME dikonfigurasi dengan benar
  • Apache Maven 3.9.9
  • Opsional: Quarkus CLI jika Anda ingin menggunakannya
  • Opsional: Mandrel atau GraalVM terinstal dan dikonfigurasi dengan benar jika Anda ingin membangun executable native (atau Docker jika Anda menggunakan build kontainer native)

Membuat Rest API

Tutorial ini memberikan langkah-langkah dan contoh untuk membuat aplikasi dengan endpoint dengan penerapan roles dan otorisasi:

Endpoint Description

/api/public

Akses tanpa authentikasi, endpoint ini bisa di akses secara anonymous.

/api/admin

Diamankan dengan role-based access control (RBAC),  endpoint ini accessible hanya untuk role admin Access dikontrol oleh anotasi @RolesAllowed.

/api/users/me

Also secured by RBAC, this endpoint is accessible only to users with the user role. It returns the caller’s username as a string.

Clone saja contoh yang sudah jadi clone  Git repository berikut:

git clone https://github.com/quarkusio/quarkus-quickstarts.git

Lalu temukan folder security-jpa-quickstart directory.

security-jpa-quickstart directory
  1. Buat dan verifikasi Maven project Agar Quarkus Security bisa memetakan security source Anda ke entitas Jakarta Persistence, pastikan Maven project dalam tutorial ini menyertakan quarkus-security-jpa atau quarkus-security-jpa-reactive extension.
    • Hibernate ORM dengan Panache digunakan untuk menyimpan user identities Anda, tetapi Anda juga bisa menggunakan Hibernate ORM dengan quarkus-security-jpa extension.

    • Baik Hibernate Reactive maupun Hibernate Reactive dengan Panache bisa digunakan dengan quarkus-security-jpa-reactive extension.

    • Anda juga harus menambahkan database connector library pilihan Anda.

    • Instruksi dalam contoh tutorial ini menggunakan PostgreSQL database untuk identity store.

      Dengan Quarkus CLI

      quarkus create app org.acme:security-jpa-quickstart \
          --extension='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
          --no-code
      cd security-jpa-quickstart 

      Dengan Maven CLI  

      mvn io.quarkus.platform:quarkus-maven-plugin:3.25.4:create \
          -DprojectGroupId=org.acme \
          -DprojectArtifactId=security-jpa-quickstart \
          -Dextensions='security-jpa,jdbc-postgresql,rest,hibernate-orm-panache' \
          -DnoCode
      cd security-jpa-quickstart 
  2. Setup Koneksi ke database via application.properties      
    quarkus.datasource.db-kind=postgresql
    quarkus.datasource.username=postgres
    quarkus.datasource.password=postgres
    quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/security_jdbc
    quarkus.hibernate-orm.schema-management.strategy=drop-and-create
     
    database security_jdbc dan table test_user
  3. Buat Controller PublicResource (atau cari di repo yang kita clone diatas)
    package org.acme.elytron.security.jpa;

    import jakarta.annotation.security.PermitAll;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    import jakarta.ws.rs.Produces;
    import jakarta.ws.rs.core.MediaType;

    @Path("/api/public")
    public class PublicResource {

    @GET
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String publicResource() {
    return "public";
    }
    }
    Public API
  4. Buat Controller Admin Resource 
    package org.acme.elytron.security.jpa;

    import jakarta.annotation.security.RolesAllowed;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    import jakarta.ws.rs.Produces;
    import jakarta.ws.rs.core.MediaType;

    @Path("/api/admin")
    public class AdminResource {

    @GET
    @RolesAllowed("admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String adminResource() {
    return "admin";
    }
    }
    Login Form    

     
    Akses halaman milik user yang seharusnya tidak bisa di akses admin 
    Logged In

     
  5.  Buat Controller User Resource 
    package org.acme.elytron.security.jpa;

    import jakarta.annotation.security.RolesAllowed;
    import jakarta.ws.rs.GET;
    import jakarta.ws.rs.Path;
    import jakarta.ws.rs.Produces;
    import jakarta.ws.rs.core.Context;
    import jakarta.ws.rs.core.MediaType;
    import jakarta.ws.rs.core.SecurityContext;

    @Path("/api/users")
    public class UserResource {

    @GET
    @RolesAllowed("user")
    @Path("/me")
    @Produces(MediaType.TEXT_PLAIN)
    public String me(@Context SecurityContext securityContext) {
    return securityContext.getUserPrincipal().getName();
    }
    }
    User akses halaman untuk users
  6. Entity User 
  7. Kelas User pada file security-jpa-quickstart/src/main/java/org/acme/elytron/security/jpa/User.java adalah entitas JPA yang mewakili tabel test_user di database. Kelas ini digunakan oleh Quarkus Security JPA sebagai penyedia data user untuk proses autentikasi dan otorisasi. Field username, password, dan role masing-masing menandai kolom username, password terenkripsi (bcrypt), dan peran user. Anotasi @UserDefinition menandakan bahwa entitas ini digunakan untuk otentikasi. Metode statis add digunakan untuk menambah user baru ke database dengan mengenkripsi password terlebih dahulu.

  8. package org.acme.elytron.security.jpa;

    import jakarta.persistence.Entity;
    import jakarta.persistence.Table;

    import io.quarkus.elytron.security.common.BcryptUtil;
    import io.quarkus.hibernate.orm.panache.PanacheEntity;
    import io.quarkus.security.jpa.Password;
    import io.quarkus.security.jpa.Roles;
    import io.quarkus.security.jpa.UserDefinition;
    import io.quarkus.security.jpa.Username;

    @Entity
    @Table(name = "test_user")
    @UserDefinition
    public class User extends PanacheEntity {
    @Username
    public String username;
    @Password
    public String password;
    @Roles
    public String role;

    /**
    * Adds a new user in the database
    * @param username the user name
    * @param password the unencrypted password (it will be encrypted with bcrypt)
    * @param role the comma-separated roles
    */
    public static void add(String username, String password, String role) {
    User user = new User();
    user.username = username;
    user.password = BcryptUtil.bcryptHash(password);
    user.role = role;
    user.persist();
    }
    }
  9. Startup (akan dijalankan setiap startup) 
  10. Kelas Startup adalah bean singleton yang dijalankan saat aplikasi mulai. Kelas ini mendengarkan event StartupEvent dan menjalankan metode loadUsers secara transaksional. Pada metode ini, semua data user dihapus, lalu dua user test (admin dan user) ditambahkan ke database. Tujuannya agar database selalu memiliki user yang bisa digunakan untuk autentikasi saat aplikasi dijalankan.

  11. package org.acme.elytron.security.jpa;

    import jakarta.enterprise.event.Observes;
    import jakarta.inject.Singleton;
    import jakarta.transaction.Transactional;

    import io.quarkus.runtime.StartupEvent;

    @Singleton
    public class Startup {
    @Transactional
    public void loadUsers(@Observes StartupEvent evt) {
    // reset and load all test users
    User.deleteAll();
    User.add("admin", "admin", "admin");
    User.add("user", "user", "user");
    }
    }

Demikian, semoga bermanfaat! 

Sumber Artikel Ini:  

  • https://quarkus.io/guides/security-basic-authentication-howto 
  • https://quarkus.io/guides/security-jpa
  • https://quarkus.io/guides/security-getting-started-tutorial

Comments

Popular posts from this blog

Numpang Kerja Remote dari Bandung Creative Hub

Numpang Kerja Remote dari Bandung Digital Valley

Cara Decompile berkas Dex dan Apk Android