Quarkus Panache Reactive + Postgresql View - quarkus

I am using the latest version of quarkus and hibernate reactive connecting to a postgresql database. Below is my Entity.
#Entity
class Balance: PanacheEntityBase {
#Id
#Convert(converter = EncryptionConverter.class)
#Column(name="encrypted_col", columnDefinition="CLOB")
lateinit var encryptedCol: String
#Column(name="balance")
var balance: Double = 0.0
}
#ApplicationScoped
class BalanceRepository: PanacheRepository<Balance> {
fun findByEncryptedCol(col: String) = find("encryptedCol", col).singleResult()
}
The balance entity is connected to a view on the database. I notice that when I execute this query the converter is not being using and I get a persistence error of no resultset found. This occurs if I send the unencrypted value. If I send the encrypted value then I get back a result.
The expected behaviour should be that the value is encrypted using the converter then pass to the database query. It seems like the converter with Panache doesn't work with database views and only with tables.
Is there another way to do this or a workaround?

Related

FindById doesn't work with UUID in Mongodb SpringData

I try to use Mongodb with Spring Data.
I wanted to use UUID instead of ObjectId. I have followed this tutorial: https://www.baeldung.com/java-mongodb-uuid (some differences might exist because I use Kotlin). I took path 2 where I added Entity callback. When I create a new entity it is saved to the database with UUID as I wanted. If I use mongo console I can type:
db.home.find({_id: UUID("18aafcf9-0c5a-46f3-84ff-1c25b00dd1ab")})
And I will find my entity by id.
However, when I try to do it by code it doesn't work as it should. It will always throw here DataOperationException(NOT_FOUND) because findById returns null.
fun findHomeById(id: String): Home {
val home = homeRepository.findById(id)
return home.unwrap() ?: throw DataOperationException(NOT_FOUND)
}
Here is repository
#Repository
interface HomeRepository: MongoRepository<Home, String>
Abstraction with id.
abstract class UuidIdentifiedEntity {
#Id
var id: UUID? = null // I tried use UUID type and String with the same result
}
And my home class
class Home(
var address: String,
var rooms: Int,
): UuidIdentifiedEntity()
Not sure if this will help, but see if changing your #Id annotation to #MongoId fixes this. Under certain circumstances, Mongo needs to know more about a field being used for an id. #MongoId should give you more control on how the field is stored too.
What is use of #MongoId in Spring Data MongoDB over #Id?

Get back autogenerated columns from database when saving an entity with Spring Data R2dbc

I have an issue when I create an entity like this
#Table("event_service.EVENT")
public class Event implements Persistable<UUID> {
#Id
private UUID id;
//Autogenerated by database if null
private UUID eventId;
}
I have a normal repository like this defined:
interface EventRepository extends ReactiveCrudRepository<Event, UUID>
When I use the repository to save this entity, the entity that is return still has eventId as null and I have to refetch the entity again from the DB to get it populated correctly. I can see that the query generated does only include the ID field in the RETURNING clause of the auto generated SQL. Is there a way to get the other auto generated field back automatically on the save method?

Spring Boot - Change connection dynamically

I have a Spring Boot project with multiple databases of different years and these databases have same tables so the only difference is the year (..., DB2016, DB2017). In the controller of the application i need to return data that belong to "different" years. Moreover in future years other databases will be created (eg. in 2018 there's going to be a db named "DB2018"). So my problem is how to switch the connection among databases without creating a new datasource and a new repository every new year.
In an other question posted by me (Spring Boot - Same repository and same entity for different databases) the answer was to create different datasources and different repositories for every existing database, but in this case i want to return data from existing databases on the basis of the current year. More specifically:
SomeEntity.java
#Entity(name = "SOMETABLE")
public class SomeEntity implements Serializable {
#Id
#Column(name="ID", nullable=false)
private Integer id;
#Column(name="NAME")
private String name;
}
SomeRepository.java
public interface SomeRepository extends PagingAndSortingRepository<SomeEntity, Integer> {
#Query(nativeQuery= true, value = "SELECT * FROM SOMETABLE WHERE NAME = ?1")
List<SomeEntity> findByName(String name);
}
SomeController.java
#RequestMapping(value="/foo/{name}", method=RequestMethod.GET)
public ResponseEntity<List<SomeEntity>> findByName(#PathVariable("name") String name) {
List<SomeEntity> list = autowiredRepo.findByName(name);
return new ResponseEntity<List<SomeEntity>>(list,HttpStatus.OK);
}
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/DB
spring.datasource.username=xxx
spring.datasource.password=xxx
So if the current year is 2017 i want something like this:
int currentyear = Calendar.getInstance().get(Calendar.YEAR);
int oldestDbYear = 2014;
List<SomeEntity> listToReturn = new LinkedList<SomeEntity>();
//the method getProperties is a custom method to get properties from a file
String url = getProperties("application.properties", "spring.datasource.url");
props.setProperty("user", getProperties("application.properties","spring.datasource.username"));
props.setProperty("password", getProperties("application.properties","spring.datasource.password"));
for (int i = currentYear, i>oldestDbYear, i--) {
//this is the connection that must be used by autowiredRepo Repository, but i don't know how to do this.
//So the repository uses different connection for every year.
Connection conn = getConnection(url+year,props);
List<SomeEntity> list_of_specific_year = autowiredRepo.findByName(name);
conn.close;
listToReturn.addAll(list_of_specific_year);
}
return listToReturn;
Hope everithing is clear
The thing that is probably most suitable to your needs here is Spring's AbstractRoutingDataSource. You do need to define multiple DataSources but you will only need a single repository. Multiple data sources is not an issue here as there is always a way to create the DataSource beans programatically at run time and register them with the application context.
How it works is you basically register a Map<Object, DataSource> inside your #Configuration class when creating your AbstractRoutingDataSource #Bean and in this case the lookup key would be the year.
Then you need create a class that implements AbstractRoutingDataSource and implement the determineCurrentLookupKey() method. Anytime a database call is made, this method is called in the current context to lookup which DataSource should be returned. In your case it sounds like you simply want to have the year as a #PathVariable in the URL and then as the implementation of determineCurrentLookupKey() grab that #PathVariable out of the URL (e.g in your controller you have mappings like #GetMapping("/{year}/foo/bar/baz")).
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder
.getRequestAttributes()).getRequest();
HashMap templateVariables =
(HashMap)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return templateVariables.get("year");
I used this approach when writing a testing tool for a product where there were many instances running on multiple different servers and I wanted a unified programming model from my #Controllers but still wanted it to be hitting the right database for the server/deployment combination in the url. Worked like a charm.
The drawback if you are using Hibernate is that all connections will go through a single SessionFactory which will mean you can't take advantage of Hibernate's 2nd level caching as I understand it, but I guess that depends on your needs.

Restrict access to spring REST data based on credentials

I have a CrudRepository throug which I can access my entities. Let's say I have an entity called Report (all oversimplified and not compiling):
#Entity
public class Report{
#Id
private Long id;
private boolean classified;
private Date date;
private String reportdata;
}
And a CrudRepository:
#RepositoryRestResource(collectionResourceRel = "reports", path = "report")
public interface ReportRepository extends CrudRepository<Report, Long>
{
findByDate(Date date); // <---- I want this to return only reports which are not classified for users who do not have the appropriate role
}
The findByDate will return all reports, including all classified reports for all users making the request. I want to restrict the access to the data based on the currently authenticated user. Is this possible?
You need Spring Security 4. It now integrates with Spring Data.
http://docs.spring.io/spring-security/site/docs/4.0.2.RELEASE/reference/htmlsingle/#data
Something like:
#Repository
public interface ReportRepository extends CrudRepository<Report,Long> {
#Query("select r from Report r where r.date=?1 and r.owner.id = ?#{ principal?.id }")
Report findByDate(Date date);
}
REST is stateless. It means that the server stores NO runtime informations (session, role etc.) about client. So if you want to use REST you should generate an API key for you client. Use a simple path filter to check whether the API key valid or not.
But perhaps you mean AJAX ?

obscuring url strings in spring mvc

How do I obscure the values of fields used in url strings in a spring mvc web app?
For example, if I want to send the record with recordID=1 into the view, I give the user a hyperlink with the following url:
https://myapp.com/urlpattern?recordID=1
As you can see, this not only exposes the recordID=1, it also tempts a malicious user to start typing other numbers to mine other records such as recordID=5 or recordID=9.
Does the spring framework or spring security have a built-in way of encrypting url strings? Or do I need to change the id values in the underlying database using hibernate?
The controller code for the above url pattern is:
#RequestMapping(value = "/urlpattern", method = RequestMethod.GET)
public String processUrlPattern(#RequestParam("recordID") String recordId,
HttpServletRequest request, BindingResult result, Map<String, Object> model) {
Long recId = Long.valueOf(recordId).longValue();
RecordObject sel_record = this.appService.findRecordById(recId);
model.put("sel_record", sel_record);
return "foldername/jspname";
}
Note that all entities in the app inherit from the same BaseEntity whose id-generating code is as follows:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'BaseEntity' ELSE dtype END)")
#org.hibernate.annotations.DiscriminatorOptions(force=true)
public abstract class BaseEntity {
#Transient
private String dtype = this.getClass().getSimpleName();
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="TBL_GEN")
#TableGenerator(
name="TBL_GEN",
table="GENERATOR_TABLE",
pkColumnName = "mykey",
valueColumnName = "hi",
pkColumnValue="id",
allocationSize=20
)
protected Integer id;
//other stuff
}
NOTE: All the users are authenticated/authorized using Spring security. However, the data is very sensitive, and it is important that no one be able to manipulate url strings.
Use HDIV, it does this out of the box:
http://hdiv.org/hdiv-documentation-single/doc.html
"A6 (Sensitive data exposure) : HDIV offers a confidentially property to all data generated at sever side. That is to say, HDIV replace original parameter values generated at server side by relative values (0,1,2,4, etc.) that avoid exposing critical data to the client side."

Resources