grails encrypt password in mysql database - mysql

I am trying to encrypt password which are stored in my mysql database, the connection to the databse work well but i don't understand how to encrypt the password i tried something i saw on a tutorial but it doesn"t work here is my domain class
I am using the 2.4.4 version of grails
package jweb
class Clients {
transient springSecurityService
int id
String name
String password
static constraints = {
id()
name()
password()
}
def beforeInsert(){
encodePassword()
}
def encodePassword(){
password = springSecurityService.encodePassword(password,null)
}
}
Edit
I found a way to do it, but i think that you are right Burt, i should certainly use sprinSecurity but i am a beginner in grails and i didn't succeed to make it work so at this time i have this
package jweb
import java.security.MessageDigest
class Clients {
int id
String name
String password
String cart_id
boolean admin
static constraints = {
id()
name()
password()
cart_id nullable:true
admin()
}
def beforeInsert(){
encodePassword()
}
def beforeUpdate(){
encodePassword()
}
def encodePassword(){
MessageDigest md5Digest;
byte[] digest;
md5Digest = MessageDigest.getInstance("SHA-512");
md5Digest.reset();
md5Digest.update(password.getBytes());
digest = md5Digest.digest();
password = new BigInteger(1,digest).toString(16)
}
}

Related

Spring data r2dbc is not auto creating tables in mysql [duplicate]

I am creating a quick project using R2DBC and H2 to familiarize myself with this new reactive stuff. Made a repository that extends ReactiveCrudRepository and all is well with the world, as long as i use the DatabaseClient to issue a CREATE TABLE statement that matches my entity first...
I understand spring data R2DBC is not as fully featured as spring data JPA (yet?) but is there currently a way to generate the schema from the entity classes?
Thanks
No, there is currently no way to generate schema from entities with Spring Data R2DBC.
I'm using it in a project with Postgres DB and it's complicated to manage database migrations, but I managed to wire in Flyway with synchronous Postgre driver (Flyway doesn't work with reactive drivers yet) at startup to handle schema migrations.
Even though you still have to write your own CREATE TABLE statements which shouldn't be that hard and you could even modify your entities in some simple project to create JPA entities and let Hibernate create schema then copy-paste it into a migration file in your R2DBC project.
It is possible for tests and for production.
I production make sure your user has no access to change schema otherwise you may delete tables by mistake!!! or use a migration tool like flyway.
You need to put your schema.sql in the main resources and add the relevant properties
spring.r2dbc.initialization-mode=always
h2 for test and postgres for prod
I use gradle and the versions of driver are:
implementation 'org.springframework.boot.experimental:spring-boot-actuator-autoconfigure-r2dbc'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'io.r2dbc:r2dbc-h2'
runtimeOnly 'io.r2dbc:r2dbc-postgresql'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot.experimental:spring-boot-test-autoconfigure-r2dbc'
The BOM version is
dependencyManagement {
imports {
mavenBom 'org.springframework.boot.experimental:spring-boot-bom-r2dbc:0.1.0.M3'
}
}
That's how I solved this problem:
Controller:
#PostMapping(MAP + PATH_DDL_PROC_DB) //PATH_DDL_PROC_DB = "/database/{db}/{schema}/{table}"
public Flux<Object> createDbByDb(
#PathVariable("db") String db,
#PathVariable("schema") String schema,
#PathVariable("table") String table) {
return ddlProcService.createDbByDb(db,schema,table);
Service:
public Flux<Object> createDbByDb(String db,String schema,String table) {
return ddl.createDbByDb(db,schema,table);
}
Repository:
#Autowired
PostgresqlConnectionConfiguration.Builder connConfig;
public Flux<Object> createDbByDb(String db,String schema,String table) {
return createDb(db).thenMany(
Mono.from(connFactory(connConfig.database(db)).create())
.flatMapMany(
connection ->
Flux.from(connection
.createBatch()
.add(sqlCreateSchema(db))
.add(sqlCreateTable(db,table))
.add(sqlPopulateTable(db,table))
.execute()
)));
}
private Mono<Void> createDb(String db) {
PostgresqlConnectionFactory
connectionFactory = connFactory(connConfig);
DatabaseClient ddl = DatabaseClient.create(connectionFactory);
return ddl
.execute(sqlCreateDb(db))
.then();
}
Connection Class:
#Slf4j
#Configuration
#EnableR2dbcRepositories
public class Connection extends AbstractR2dbcConfiguration {
/*
**********************************************
* Spring Data JDBC:
* DDL: does not support JPA.
*
* R2DBC
* DDL:
* -does no support JPA
* -To achieve DDL, uses R2dbc.DataBaseClient
*
* DML:
* -it uses R2dbcREpositories
* -R2dbcRepositories is different than
* R2dbc.DataBaseClient
* ********************************************
*/
#Bean
public PostgresqlConnectionConfiguration.Builder connectionConfig() {
return PostgresqlConnectionConfiguration
.builder()
.host("db-r2dbc")
.port(5432)
.username("root")
.password("root");
}
#Bean
public PostgresqlConnectionFactory connectionFactory() {
return
new PostgresqlConnectionFactory(
connectionConfig().build()
);
}
}
DDL Scripts:
#Getter
#NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DDLScripts {
public static final String SQL_GET_TASK = "select * from tasks";
public static String sqlCreateDb(String db) {
String sql = "create database %1$s;";
String[] sql1OrderedParams = quotify(new String[]{db});
String finalSql = format(sql,(Object[]) sql1OrderedParams);
return finalSql;
}
public static String sqlCreateSchema(String schema) {
String sql = "create schema if not exists %1$s;";
String[] sql1OrderedParams = quotify(new String[]{schema});
return format(sql,(Object[]) sql1OrderedParams);
}
public static String sqlCreateTable(String schema,String table) {
String sql1 = "create table %1$s.%2$s " +
"(id serial not null constraint tasks_pk primary key, " +
"lastname varchar not null); ";
String[] sql1OrderedParams = quotify(new String[]{schema,table});
String sql1Final = format(sql1,(Object[]) sql1OrderedParams);
String sql2 = "alter table %1$s.%2$s owner to root; ";
String[] sql2OrderedParams = quotify(new String[]{schema,table});
String sql2Final = format(sql2,(Object[]) sql2OrderedParams);
return sql1Final + sql2Final;
}
public static String sqlPopulateTable(String schema,String table) {
String sql = "insert into %1$s.%2$s values (1, 'schema-table-%3$s');";
String[] sql1OrderedParams = quotify(new String[]{schema,table,schema});
return format(sql,(Object[]) sql1OrderedParams);
}
private static String[] quotify(String[] stringArray) {
String[] returnArray = new String[stringArray.length];
for (int i = 0; i < stringArray.length; i++) {
returnArray[i] = "\"" + stringArray[i] + "\"";
}
return returnArray;
}
}
It is actually possible to load a schema by defining a specific class in this way:
import io.r2dbc.spi.ConnectionFactory
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
#Configuration
#EnableR2dbcRepositories
class DbConfig {
#Bean
fun initializer(connectionFactory: ConnectionFactory): ConnectionFactoryInitializer {
val initializer = ConnectionFactoryInitializer()
initializer.setConnectionFactory(connectionFactory)
initializer.setDatabasePopulator(
ResourceDatabasePopulator(
ClassPathResource("schema.sql")
)
)
return initializer
}
}
Pay attention that IntelliJ gives an error "Could not autowire. No beans of 'ConnectionFactory' type found" but it is actually a false positive. So ignore it and build again your project.
The schema.sql file has to be put in resources folder.

Problem with Update in CRUD during unit tests because of Bcrypt encryption

I am hashing my user passwords while saving the entities to the database.
While doing that, I'm unable to update the username, without hashing the password again.
I wrote the test for it, which fails.
#Test
#DisplayName("Update")
public void testForUpdate() {
final User user = new User("UserForUpdate", "UpdatedUser123");
this.userService.save(user);
User found = this.userService.findOneByUsernameAndPassword(user.getUsername(), user.getPassword());
assertTrue(found.getId() != null, "Found real user");
this.userService.save(found);
final User asserted = this.userService.findOneByUsernameAndPassword(found.getUsername(), user.getPassword());
assertTrue(asserted != null, "Updated user found");
assertTrue(user.getId() == asserted.getId(), "User ID is persisted");
}
The save method from the UserService looks like this:
#Override
public User save(User newUser) {
newUser.setPassword(passwordEncoder.encode(newUser.getPassword()));
return repository.save(newUser);
}
Am I doing something wrong saving it like this?
How should I proceed, to implement the CRUD Update correctly?
Thanks for any pointers
Do not modify the password when you store the user. Instead encode the password when you modify it.
public class UserSevice {
...
public changePassword(User user, String plainPassword) {
user.setPassword(passwordEncoder.encode(plainPassword));
}
}

Match password efficiently in Spring Boot - JPA

I have User class like this :
#Data
#Entity
public class User {
#Id #GeneratedValue Long userID;
String eMail;
String passwordHash;
}
And I have data like this :
[{"userID":1,"passwordHash":"asdasd","email":"admin#admin.com"},
{"userID":2,"passwordHash":"12345","email":"admin1asdasd#admin.com"}]
I have two method , one - to get single user :
// Single item
#GetMapping("/user/{id}")
User one(#PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
Other method to retrieve all user :
// Aggregate root
#GetMapping("/user")
List<User> all() {
return repository.findAll();
}
Now how can I match password ? What will be the efficient way ?
You may want to consider this kind of an aproach: in general, you should save hashed password in the database and check passwords using hashed values. Bcrypt is a good option for hashing and it can be easily integrated with Spring.
As explained in the link above you can define a password encoder service:
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
and you can use it like this:
#Autowired
private PasswordEncoder passwordEncoder;
//...
User user = new User();
user.setFirstName(accountDto.getFirstName());
user.setLastName(accountDto.getLastName());
user.setPassword(passwordEncoder.encode(accountDto.getPassword()));
user.setEmail(accountDto.getEmail());
user.setRole(new Role(Integer.valueOf(1), user));
repository.save(user);
where accountDto contains the password in clear-text.
Now you can expose a dedicated login method that compares hashed values, something along these lines:
void login(String username, char[] password) throws Exception {
User user = userRepository.findByUsername(username);
if (user != null) {
String encodedPassword = user.getPassword();
if(passwordEncoder.matches(String.valueOf(password), encodedPassword)) {
return;
}
}
throw new Exception("User cannot be authenticated");
}

Geting Current logged user details for jhi_persistenet_audit_event table

I am working with jhipster. I need to create a new table for auditing my database changes and link it with the default jhi_persistenet_audit_event table generated by the Jhipster. How I can get the current logged user record from the jhi_persistenet_audit_event table to link that id to my new table?
Solution 1: Principal principal
#RequestMapping(value = {"/", ""})
public String start(Principal principal, Model model) {
String currentUser = principal.getName();
return currentUser;
}
Solution 2: Authentication authentication
#RequestMapping(value = {"/", ""})
public String currentUserName(Authentication authentication) {
return authentication.getName();
}
Solution 3: SecurityContextHolder
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
Details 1 Details 2

Cannot connect to AWS MySQL using Java SDK and IAM Role / Instance Profile

I want to connect to an RDS Aurora instance using an Instance Profile that utilizes STS to assume a role so that I don't need to hard code my password in the solution. I'm getting an error that states my user doesn't have access. However, when I hard code the connection string with username and password, I'm able to connect using the same user. I've checked db user permissions and they're correct. I've also tried using all permissions in the role. I've added logging to check that I'm receiving a token and I am. Any ideas or help is appreciated. Amazon's documentation that I've been following is: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Connecting.Java.html
My Code:
public final class Database {
private static String jdbcUrl = "jdbc:mysql://" + DockerConstants.PersistenceStoreUrl + ":" + DockerConstants.PersistenceStorePort + "/dbname";
private Database() {
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(jdbcUrl, setMySqlConnectionProperties());
}
static String generateAuthToken(){
RdsIamAuthTokenGenerator generator = RdsIamAuthTokenGenerator.builder()
.credentials(InstanceProfileCredentialsProvider.getInstance())
.region(EC2MetadataUtils.getEC2InstanceRegion())
.build();
String authToken = generator.getAuthToken(
GetIamAuthTokenRequest.builder()
.hostname(DockerConstants.PersistenceStoreUrl)
.port(DockerConstants.PersistenceStorePort)
.userName(DockerConstants.PersistenceStoreUserName)
.build());
return authToken;
}
private static Properties setMySqlConnectionProperties() {
Properties mysqlConnectionProperties = new Properties();
mysqlConnectionProperties.setProperty("verifyServerCertificate","false");
mysqlConnectionProperties.setProperty("useSSL", "false");
mysqlConnectionProperties.setProperty("user", DockerConstants.PersistenceStoreUserName);
mysqlConnectionProperties.setProperty("password",generateAuthToken());
return mysqlConnectionProperties;
}
}